blob: c5619e7bf69b1df702fc55a04729b1e2ab87d3b9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#ifndef AVRO_VALUE_H
#define AVRO_VALUE_H
#ifdef __cplusplus
extern "C" {
#define CLOSE_EXTERN }
#else
#define CLOSE_EXTERN
#endif
#include <errno.h>
#include <avro/platform.h>
#include <stdlib.h>
#include <avro/data.h>
#include <avro/schema.h>
/*
* This file defines an interface struct for Avro data. Most of the
* interesting parts of this library will work with Avro data values
* that are expressed in whatever C type you want, as long as you can
* provide an implementation of this interface for that type.
*/
typedef struct avro_value_iface avro_value_iface_t;
typedef struct avro_value {
avro_value_iface_t *iface;
void *self;
} avro_value_t;
struct avro_value_iface {
/*-------------------------------------------------------------
* "class" methods
*/
/**
* Increment the reference count of the interface struct. This
* should be a no-op for static structs, since they don't need
* reference counts.
*/
avro_value_iface_t *
(*incref_iface)(avro_value_iface_t *iface);
/**
* Decrement the reference count of the interface struct. If
* the count falls to 0, free the struct. This should be a
* no-op for static structs, since they don't need reference
* counts.
*/
void
(*decref_iface)(avro_value_iface_t *iface);
/*-------------------------------------------------------------
* General "instance" methods
*/
/**
* Increments the reference count of a value.
*/
void
(*incref)(avro_value_t *value);
/**
* Decrements the reference count of a value, and frees the
* value if the reference count drops to 0. After calling this
* method, your value instance is undefined, and cannot be used
* anymore.
*/
void
(*decref)(avro_value_t *value);
/**
* Reset the instance to its "empty", default value. You don't
* have to free the underlying storage, if you want to keep it
* around for later values.
*/
int
(*reset)(const avro_value_iface_t *iface, void *self);
/**
* Return the general Avro type of a value instance.
*/
avro_type_t
(*get_type)(const avro_value_iface_t *iface, const void *self);
/**
* Return the Avro schema that a value is an instance of.
*/
avro_schema_t
(*get_schema)(const avro_value_iface_t *iface, const void *self);
/*-------------------------------------------------------------
* Primitive value getters
*/
int (*get_boolean)(const avro_value_iface_t *iface,
const void *self, int *out);
int (*get_bytes)(const avro_value_iface_t *iface,
const void *self, const void **buf, size_t *size);
int (*grab_bytes)(const avro_value_iface_t *iface,
const void *self, avro_wrapped_buffer_t *dest);
int (*get_double)(const avro_value_iface_t *iface,
const void *self, double *out);
int (*get_float)(const avro_value_iface_t *iface,
const void *self, float *out);
int (*get_int)(const avro_value_iface_t *iface,
const void *self, int32_t *out);
int (*get_long)(const avro_value_iface_t *iface,
const void *self, int64_t *out);
int (*get_null)(const avro_value_iface_t *iface,
const void *self);
/* The result will be NUL-terminated; the size will INCLUDE the
* NUL terminator. str will never be NULL unless there's an
* error. */
int (*get_string)(const avro_value_iface_t *iface,
const void *self, const char **str, size_t *size);
int (*grab_string)(const avro_value_iface_t *iface,
const void *self, avro_wrapped_buffer_t *dest);
int (*get_enum)(const avro_value_iface_t *iface,
const void *self, int *out);
int (*get_fixed)(const avro_value_iface_t *iface,
const void *self, const void **buf, size_t *size);
int (*grab_fixed)(const avro_value_iface_t *iface,
const void *self, avro_wrapped_buffer_t *dest);
/*-------------------------------------------------------------
* Primitive value setters
*/
/*
* The "give" setters can be used to give control of an existing
* buffer to a bytes, fixed, or string value. The free function
* will be called when the buffer is no longer needed. (It's
* okay for free to be NULL; that just means that nothing
* special needs to be done to free the buffer. That's useful
* for a static string, for instance.)
*
* If your class can't take control of an existing buffer, then
* your give functions should pass the buffer into the
* corresponding "set" method and then immediately free the
* buffer.
*
* Note that for strings, the free function will be called with
* a size that *includes* the NUL terminator, even though you
* provide a size that does *not*.
*/
int (*set_boolean)(const avro_value_iface_t *iface,
void *self, int val);
int (*set_bytes)(const avro_value_iface_t *iface,
void *self, void *buf, size_t size);
int (*give_bytes)(const avro_value_iface_t *iface,
void *self, avro_wrapped_buffer_t *buf);
int (*set_double)(const avro_value_iface_t *iface,
void *self, double val);
int (*set_float)(const avro_value_iface_t *iface,
void *self, float val);
int (*set_int)(const avro_value_iface_t *iface,
void *self, int32_t val);
int (*set_long)(const avro_value_iface_t *iface,
void *self, int64_t val);
int (*set_null)(const avro_value_iface_t *iface, void *self);
/* The input must be NUL-terminated */
int (*set_string)(const avro_value_iface_t *iface,
void *self, const char *str);
/* and size must INCLUDE the NUL terminator */
int (*set_string_len)(const avro_value_iface_t *iface,
void *self, const char *str, size_t size);
int (*give_string_len)(const avro_value_iface_t *iface,
void *self, avro_wrapped_buffer_t *buf);
int (*set_enum)(const avro_value_iface_t *iface,
void *self, int val);
int (*set_fixed)(const avro_value_iface_t *iface,
void *self, void *buf, size_t size);
int (*give_fixed)(const avro_value_iface_t *iface,
void *self, avro_wrapped_buffer_t *buf);
/*-------------------------------------------------------------
* Compound value getters
*/
/* Number of elements in array/map, or the number of fields in a
* record. */
int (*get_size)(const avro_value_iface_t *iface,
const void *self, size_t *size);
/*
* For arrays and maps, returns the element with the given
* index. (For maps, the "index" is based on the order that the
* keys were added to the map.) For records, returns the field
* with that index in the schema.
*
* For maps and records, the name parameter (if given) will be
* filled in with the key or field name of the returned value.
* For arrays, the name parameter will always be ignored.
*/
int (*get_by_index)(const avro_value_iface_t *iface,
const void *self, size_t index,
avro_value_t *child, const char **name);
/*
* For maps, returns the element with the given key. For
* records, returns the element with the given field name. If
* index is given, it will be filled in with the numeric index
* of the returned value.
*/
int (*get_by_name)(const avro_value_iface_t *iface,
const void *self, const char *name,
avro_value_t *child, size_t *index);
/* Discriminant of current union value */
int (*get_discriminant)(const avro_value_iface_t *iface,
const void *self, int *out);
/* Current union value */
int (*get_current_branch)(const avro_value_iface_t *iface,
const void *self, avro_value_t *branch);
/*-------------------------------------------------------------
* Compound value setters
*/
/*
* For all of these, the value class should know which class to
* use for its children.
*/
/* Creates a new array element. */
int (*append)(const avro_value_iface_t *iface,
void *self, avro_value_t *child_out, size_t *new_index);
/* Creates a new map element, or returns an existing one. */
int (*add)(const avro_value_iface_t *iface,
void *self, const char *key,
avro_value_t *child, size_t *index, int *is_new);
/* Select a union branch. */
int (*set_branch)(const avro_value_iface_t *iface,
void *self, int discriminant,
avro_value_t *branch);
};
/**
* Increments the reference count of a value instance. Normally you
* don't need to call this directly; you'll have a reference whenever
* you create the value, and @ref avro_value_copy and @ref
* avro_value_move update the reference counts correctly for you.
*/
void
avro_value_incref(avro_value_t *value);
/**
* Decremenets the reference count of a value instance, freeing it if
* its reference count drops to 0.
*/
void
avro_value_decref(avro_value_t *value);
/**
* Copies a reference to a value. This does not copy any of the data
* in the value; you get two avro_value_t references that point at the
* same underlying value instance.
*/
void
avro_value_copy_ref(avro_value_t *dest, const avro_value_t *src);
/**
* Moves a reference to a value. This does not copy any of the data in
* the value. The @ref src value is invalidated by this function; its
* equivalent to the following:
*
* <code>
* avro_value_copy_ref(dest, src);
* avro_value_decref(src);
* </code>
*/
void
avro_value_move_ref(avro_value_t *dest, avro_value_t *src);
/**
* Compares two values for equality. The two values don't need to have
* the same implementation of the value interface, but they do need to
* represent Avro values of the same schema. This function ensures that
* the schemas match; if you want to skip this check, use
* avro_value_equal_fast.
*/
int
avro_value_equal(avro_value_t *val1, avro_value_t *val2);
/**
* Compares two values for equality. The two values don't need to have
* the same implementation of the value interface, but they do need to
* represent Avro values of the same schema. This function assumes that
* the schemas match; if you can't guarantee this, you should use
* avro_value_equal, which compares the schemas before comparing the
* values.
*/
int
avro_value_equal_fast(avro_value_t *val1, avro_value_t *val2);
/**
* Compares two values using the sort order defined in the Avro
* specification. The two values don't need to have the same
* implementation of the value interface, but they do need to represent
* Avro values of the same schema. This function ensures that the
* schemas match; if you want to skip this check, use
* avro_value_cmp_fast.
*/
int
avro_value_cmp(avro_value_t *val1, avro_value_t *val2);
/**
* Compares two values using the sort order defined in the Avro
* specification. The two values don't need to have the same
* implementation of the value interface, but they do need to represent
* Avro values of the same schema. This function assumes that the
* schemas match; if you can't guarantee this, you should use
* avro_value_cmp, which compares the schemas before comparing the
* values.
*/
int
avro_value_cmp_fast(avro_value_t *val1, avro_value_t *val2);
/**
* Copies the contents of src into dest. The two values don't need to
* have the same implementation of the value interface, but they do need
* to represent Avro values of the same schema. This function ensures
* that the schemas match; if you want to skip this check, use
* avro_value_copy_fast.
*/
int
avro_value_copy(avro_value_t *dest, const avro_value_t *src);
/**
* Copies the contents of src into dest. The two values don't need to
* have the same implementation of the value interface, but they do need
* to represent Avro values of the same schema. This function assumes
* that the schemas match; if you can't guarantee this, you should use
* avro_value_copy, which compares the schemas before comparing the
* values.
*/
int
avro_value_copy_fast(avro_value_t *dest, const avro_value_t *src);
/**
* Returns a hash value for a given Avro value.
*/
uint32_t
avro_value_hash(avro_value_t *value);
/*
* Returns a string containing the JSON encoding of an Avro value. You
* must free this string when you're done with it, using the standard
* free() function. (*Not* using the custom Avro allocator.)
*/
int
avro_value_to_json(const avro_value_t *value,
int one_line, char **json_str);
/**
* A helper macro for calling a given method in a value instance, if
* it's present. If the value's class doesn't implement the given
* method, we return dflt. You usually won't call this directly; it's
* just here to implement the macros below.
*/
#define avro_value_call0(value, method, dflt) \
((value)->iface->method == NULL? (dflt): \
(value)->iface->method((value)->iface, (value)->self))
#define avro_value_call(value, method, dflt, ...) \
((value)->iface->method == NULL? (dflt): \
(value)->iface->method((value)->iface, (value)->self, __VA_ARGS__))
#define avro_value_iface_incref(cls) \
((cls)->incref_iface == NULL? (cls): (cls)->incref_iface((cls)))
#define avro_value_iface_decref(cls) \
((cls)->decref_iface == NULL? (void) 0: (cls)->decref_iface((cls)))
#define avro_value_reset(value) \
avro_value_call0(value, reset, EINVAL)
#define avro_value_get_type(value) \
avro_value_call0(value, get_type, (avro_type_t) -1)
#define avro_value_get_schema(value) \
avro_value_call0(value, get_schema, NULL)
#define avro_value_get_boolean(value, out) \
avro_value_call(value, get_boolean, EINVAL, out)
#define avro_value_get_bytes(value, buf, size) \
avro_value_call(value, get_bytes, EINVAL, buf, size)
#define avro_value_grab_bytes(value, dest) \
avro_value_call(value, grab_bytes, EINVAL, dest)
#define avro_value_get_double(value, out) \
avro_value_call(value, get_double, EINVAL, out)
#define avro_value_get_float(value, out) \
avro_value_call(value, get_float, EINVAL, out)
#define avro_value_get_int(value, out) \
avro_value_call(value, get_int, EINVAL, out)
#define avro_value_get_long(value, out) \
avro_value_call(value, get_long, EINVAL, out)
#define avro_value_get_null(value) \
avro_value_call0(value, get_null, EINVAL)
#define avro_value_get_string(value, str, size) \
avro_value_call(value, get_string, EINVAL, str, size)
#define avro_value_grab_string(value, dest) \
avro_value_call(value, grab_string, EINVAL, dest)
#define avro_value_get_enum(value, out) \
avro_value_call(value, get_enum, EINVAL, out)
#define avro_value_get_fixed(value, buf, size) \
avro_value_call(value, get_fixed, EINVAL, buf, size)
#define avro_value_grab_fixed(value, dest) \
avro_value_call(value, grab_fixed, EINVAL, dest)
#define avro_value_set_boolean(value, val) \
avro_value_call(value, set_boolean, EINVAL, val)
#define avro_value_set_bytes(value, buf, size) \
avro_value_call(value, set_bytes, EINVAL, buf, size)
#define avro_value_give_bytes(value, buf) \
avro_value_call(value, give_bytes, EINVAL, buf)
#define avro_value_set_double(value, val) \
avro_value_call(value, set_double, EINVAL, val)
#define avro_value_set_float(value, val) \
avro_value_call(value, set_float, EINVAL, val)
#define avro_value_set_int(value, val) \
avro_value_call(value, set_int, EINVAL, val)
#define avro_value_set_long(value, val) \
avro_value_call(value, set_long, EINVAL, val)
#define avro_value_set_null(value) \
avro_value_call0(value, set_null, EINVAL)
#define avro_value_set_string(value, str) \
avro_value_call(value, set_string, EINVAL, str)
#define avro_value_set_string_len(value, str, size) \
avro_value_call(value, set_string_len, EINVAL, str, size)
#define avro_value_give_string_len(value, buf) \
avro_value_call(value, give_string_len, EINVAL, buf)
#define avro_value_set_enum(value, val) \
avro_value_call(value, set_enum, EINVAL, val)
#define avro_value_set_fixed(value, buf, size) \
avro_value_call(value, set_fixed, EINVAL, buf, size)
#define avro_value_give_fixed(value, buf) \
avro_value_call(value, give_fixed, EINVAL, buf)
#define avro_value_get_size(value, size) \
avro_value_call(value, get_size, EINVAL, size)
#define avro_value_get_by_index(value, idx, child, name) \
avro_value_call(value, get_by_index, EINVAL, idx, child, name)
#define avro_value_get_by_name(value, name, child, index) \
avro_value_call(value, get_by_name, EINVAL, name, child, index)
#define avro_value_get_discriminant(value, out) \
avro_value_call(value, get_discriminant, EINVAL, out)
#define avro_value_get_current_branch(value, branch) \
avro_value_call(value, get_current_branch, EINVAL, branch)
#define avro_value_append(value, child, new_index) \
avro_value_call(value, append, EINVAL, child, new_index)
#define avro_value_add(value, key, child, index, is_new) \
avro_value_call(value, add, EINVAL, key, child, index, is_new)
#define avro_value_set_branch(value, discriminant, branch) \
avro_value_call(value, set_branch, EINVAL, discriminant, branch)
CLOSE_EXTERN
#endif