blob: 3197e3f3b762ebf2a0183b6912c078d90ead6d8e [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
*
* http://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.
*/
#include "avro/allocation.h"
#include "avro/basics.h"
#include "avro/errors.h"
#include "avro/legacy.h"
#include "avro/refcount.h"
#include "avro/schema.h"
#include "avro_private.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "datum.h"
#include "schema.h"
#include "encoding.h"
#define DEFAULT_TABLE_SIZE 32
static void avro_datum_init(avro_datum_t datum, avro_type_t type)
{
datum->type = type;
datum->class_type = AVRO_DATUM;
avro_refcount_set(&datum->refcount, 1);
}
static void
avro_str_free_wrapper(void *ptr, size_t sz)
{
// don't need sz, since the size is stored in the string buffer
AVRO_UNUSED(sz);
avro_str_free((char *)ptr);
}
static avro_datum_t avro_string_private(char *str, int64_t size,
avro_free_func_t string_free)
{
struct avro_string_datum_t *datum =
(struct avro_string_datum_t *) avro_new(struct avro_string_datum_t);
if (!datum) {
avro_set_error("Cannot create new string datum");
return NULL;
}
datum->s = str;
datum->size = size;
datum->free = string_free;
avro_datum_init(&datum->obj, AVRO_STRING);
return &datum->obj;
}
avro_datum_t avro_string(const char *str)
{
char *p = avro_strdup(str);
if (!p) {
avro_set_error("Cannot copy string content");
return NULL;
}
avro_datum_t s_datum = avro_string_private(p, 0, avro_str_free_wrapper);
if (!s_datum) {
avro_str_free(p);
}
return s_datum;
}
avro_datum_t avro_givestring(const char *str,
avro_free_func_t free)
{
int64_t sz = strlen(str)+1;
return avro_string_private((char *)str, sz, free);
}
int avro_string_get(avro_datum_t datum, char **p)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_string(datum), "string datum");
check_param(EINVAL, p, "string buffer");
*p = avro_datum_to_string(datum)->s;
return 0;
}
static int avro_string_set_private(avro_datum_t datum,
const char *p, int64_t size,
avro_free_func_t string_free)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_string(datum), "string datum");
check_param(EINVAL, p, "string content");
struct avro_string_datum_t *string = avro_datum_to_string(datum);
if (string->free) {
string->free(string->s, string->size);
}
string->free = string_free;
string->s = (char *)p;
string->size = size;
return 0;
}
int avro_string_set(avro_datum_t datum, const char *p)
{
char *string_copy = avro_strdup(p);
int rval;
if (!string_copy) {
avro_set_error("Cannot copy string content");
return ENOMEM;
}
rval = avro_string_set_private(datum, string_copy, 0,
avro_str_free_wrapper);
if (rval) {
avro_str_free(string_copy);
}
return rval;
}
int avro_givestring_set(avro_datum_t datum, const char *p,
avro_free_func_t free)
{
int64_t size = strlen(p)+1;
return avro_string_set_private(datum, p, size, free);
}
static avro_datum_t avro_bytes_private(char *bytes, int64_t size,
avro_free_func_t bytes_free)
{
struct avro_bytes_datum_t *datum;
datum = (struct avro_bytes_datum_t *) avro_new(struct avro_bytes_datum_t);
if (!datum) {
avro_set_error("Cannot create new bytes datum");
return NULL;
}
datum->bytes = bytes;
datum->size = size;
datum->free = bytes_free;
avro_datum_init(&datum->obj, AVRO_BYTES);
return &datum->obj;
}
avro_datum_t avro_bytes(const char *bytes, int64_t size)
{
char *bytes_copy = (char *) avro_malloc(size);
if (!bytes_copy) {
avro_set_error("Cannot copy bytes content");
return NULL;
}
memcpy(bytes_copy, bytes, size);
avro_datum_t result =
avro_bytes_private(bytes_copy, size, avro_alloc_free_func);
if (result == NULL) {
avro_free(bytes_copy, size);
}
return result;
}
avro_datum_t avro_givebytes(const char *bytes, int64_t size,
avro_free_func_t free)
{
return avro_bytes_private((char *)bytes, size, free);
}
static int avro_bytes_set_private(avro_datum_t datum, const char *bytes,
const int64_t size,
avro_free_func_t bytes_free)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_bytes(datum), "bytes datum");
struct avro_bytes_datum_t *b = avro_datum_to_bytes(datum);
if (b->free) {
b->free(b->bytes, b->size);
}
b->free = bytes_free;
b->bytes = (char *)bytes;
b->size = size;
return 0;
}
int avro_bytes_set(avro_datum_t datum, const char *bytes, const int64_t size)
{
int rval;
char *bytes_copy = (char *) avro_malloc(size);
if (!bytes_copy) {
avro_set_error("Cannot copy bytes content");
return ENOMEM;
}
memcpy(bytes_copy, bytes, size);
rval = avro_bytes_set_private(datum, bytes_copy, size, avro_alloc_free_func);
if (rval) {
avro_free(bytes_copy, size);
}
return rval;
}
int avro_givebytes_set(avro_datum_t datum, const char *bytes,
const int64_t size, avro_free_func_t free)
{
return avro_bytes_set_private(datum, bytes, size, free);
}
int avro_bytes_get(avro_datum_t datum, char **bytes, int64_t * size)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_bytes(datum), "bytes datum");
check_param(EINVAL, bytes, "bytes");
check_param(EINVAL, size, "size");
*bytes = avro_datum_to_bytes(datum)->bytes;
*size = avro_datum_to_bytes(datum)->size;
return 0;
}
avro_datum_t avro_int32(int32_t i)
{
struct avro_int32_datum_t *datum =
(struct avro_int32_datum_t *) avro_new(struct avro_int32_datum_t);
if (!datum) {
avro_set_error("Cannot create new int datum");
return NULL;
}
datum->i32 = i;
avro_datum_init(&datum->obj, AVRO_INT32);
return &datum->obj;
}
int avro_int32_get(avro_datum_t datum, int32_t * i)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_int32(datum), "int datum");
check_param(EINVAL, i, "value pointer");
*i = avro_datum_to_int32(datum)->i32;
return 0;
}
int avro_int32_set(avro_datum_t datum, const int32_t i)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_int32(datum), "int datum");
avro_datum_to_int32(datum)->i32 = i;
return 0;
}
avro_datum_t avro_int64(int64_t l)
{
struct avro_int64_datum_t *datum =
(struct avro_int64_datum_t *) avro_new(struct avro_int64_datum_t);
if (!datum) {
avro_set_error("Cannot create new long datum");
return NULL;
}
datum->i64 = l;
avro_datum_init(&datum->obj, AVRO_INT64);
return &datum->obj;
}
int avro_int64_get(avro_datum_t datum, int64_t * l)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_int64(datum), "long datum");
check_param(EINVAL, l, "value pointer");
*l = avro_datum_to_int64(datum)->i64;
return 0;
}
int avro_int64_set(avro_datum_t datum, const int64_t l)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_int64(datum), "long datum");
avro_datum_to_int64(datum)->i64 = l;
return 0;
}
avro_datum_t avro_float(float f)
{
struct avro_float_datum_t *datum =
(struct avro_float_datum_t *) avro_new(struct avro_float_datum_t);
if (!datum) {
avro_set_error("Cannot create new float datum");
return NULL;
}
datum->f = f;
avro_datum_init(&datum->obj, AVRO_FLOAT);
return &datum->obj;
}
int avro_float_set(avro_datum_t datum, const float f)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_float(datum), "float datum");
avro_datum_to_float(datum)->f = f;
return 0;
}
int avro_float_get(avro_datum_t datum, float *f)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_float(datum), "float datum");
check_param(EINVAL, f, "value pointer");
*f = avro_datum_to_float(datum)->f;
return 0;
}
avro_datum_t avro_double(double d)
{
struct avro_double_datum_t *datum =
(struct avro_double_datum_t *) avro_new(struct avro_double_datum_t);
if (!datum) {
avro_set_error("Cannot create new double atom");
return NULL;
}
datum->d = d;
avro_datum_init(&datum->obj, AVRO_DOUBLE);
return &datum->obj;
}
int avro_double_set(avro_datum_t datum, const double d)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_double(datum), "double datum");
avro_datum_to_double(datum)->d = d;
return 0;
}
int avro_double_get(avro_datum_t datum, double *d)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_double(datum), "double datum");
check_param(EINVAL, d, "value pointer");
*d = avro_datum_to_double(datum)->d;
return 0;
}
avro_datum_t avro_boolean(int8_t i)
{
struct avro_boolean_datum_t *datum =
(struct avro_boolean_datum_t *) avro_new(struct avro_boolean_datum_t);
if (!datum) {
avro_set_error("Cannot create new boolean datum");
return NULL;
}
datum->i = i;
avro_datum_init(&datum->obj, AVRO_BOOLEAN);
return &datum->obj;
}
int avro_boolean_set(avro_datum_t datum, const int8_t i)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_boolean(datum), "boolean datum");
avro_datum_to_boolean(datum)->i = i;
return 0;
}
int avro_boolean_get(avro_datum_t datum, int8_t * i)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_boolean(datum), "boolean datum");
check_param(EINVAL, i, "value pointer");
*i = avro_datum_to_boolean(datum)->i;
return 0;
}
avro_datum_t avro_null(void)
{
static struct avro_obj_t obj = {
AVRO_NULL,
AVRO_DATUM,
1
};
return avro_datum_incref(&obj);
}
avro_datum_t avro_union(avro_schema_t schema,
int64_t discriminant, avro_datum_t value)
{
check_param(NULL, is_avro_schema(schema), "schema");
struct avro_union_datum_t *datum =
(struct avro_union_datum_t *) avro_new(struct avro_union_datum_t);
if (!datum) {
avro_set_error("Cannot create new union datum");
return NULL;
}
datum->schema = avro_schema_incref(schema);
datum->discriminant = discriminant;
datum->value = avro_datum_incref(value);
avro_datum_init(&datum->obj, AVRO_UNION);
return &datum->obj;
}
int64_t avro_union_discriminant(const avro_datum_t datum)
{
return avro_datum_to_union(datum)->discriminant;
}
avro_datum_t avro_union_current_branch(avro_datum_t datum)
{
return avro_datum_to_union(datum)->value;
}
int avro_union_set_discriminant(avro_datum_t datum,
int discriminant,
avro_datum_t *branch)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_union(datum), "union datum");
struct avro_union_datum_t *unionp = avro_datum_to_union(datum);
avro_schema_t schema = unionp->schema;
avro_schema_t branch_schema =
avro_schema_union_branch(schema, discriminant);
if (branch_schema == NULL) {
// That branch doesn't exist!
avro_set_error("Branch %d doesn't exist", discriminant);
return EINVAL;
}
if (unionp->discriminant != discriminant) {
// If we're changing the branch, throw away any old
// branch value.
if (unionp->value != NULL) {
avro_datum_decref(unionp->value);
unionp->value = NULL;
}
unionp->discriminant = discriminant;
}
// Create a new branch value, if there isn't one already.
if (unionp->value == NULL) {
unionp->value = avro_datum_from_schema(branch_schema);
}
if (branch != NULL) {
*branch = unionp->value;
}
return 0;
}
avro_datum_t avro_record(avro_schema_t schema)
{
check_param(NULL, is_avro_schema(schema), "schema");
struct avro_record_datum_t *datum =
(struct avro_record_datum_t *) avro_new(struct avro_record_datum_t);
if (!datum) {
avro_set_error("Cannot create new record datum");
return NULL;
}
datum->field_order = st_init_numtable_with_size(DEFAULT_TABLE_SIZE);
if (!datum->field_order) {
avro_set_error("Cannot create new record datum");
avro_freet(struct avro_record_datum_t, datum);
return NULL;
}
datum->fields_byname = st_init_strtable_with_size(DEFAULT_TABLE_SIZE);
if (!datum->fields_byname) {
avro_set_error("Cannot create new record datum");
st_free_table(datum->field_order);
avro_freet(struct avro_record_datum_t, datum);
return NULL;
}
datum->schema = avro_schema_incref(schema);
avro_datum_init(&datum->obj, AVRO_RECORD);
return &datum->obj;
}
int
avro_record_get(const avro_datum_t datum, const char *field_name,
avro_datum_t * field)
{
union {
avro_datum_t field;
st_data_t data;
} val;
if (is_avro_datum(datum) && is_avro_record(datum) && field_name) {
if (st_lookup
(avro_datum_to_record(datum)->fields_byname,
(st_data_t) field_name, &(val.data))) {
*field = val.field;
return 0;
}
}
avro_set_error("No field named %s", field_name);
return EINVAL;
}
int
avro_record_set(avro_datum_t datum, const char *field_name,
const avro_datum_t field_value)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_record(datum), "record datum");
check_param(EINVAL, field_name, "field_name");
char *key = (char *)field_name;
avro_datum_t old_field;
if (avro_record_get(datum, field_name, &old_field) == 0) {
/* Overriding old value */
avro_datum_decref(old_field);
} else {
/* Inserting new value */
struct avro_record_datum_t *record =
avro_datum_to_record(datum);
key = avro_strdup(field_name);
if (!key) {
avro_set_error("Cannot copy field name");
return ENOMEM;
}
st_insert(record->field_order,
record->field_order->num_entries,
(st_data_t) key);
}
avro_datum_incref(field_value);
st_insert(avro_datum_to_record(datum)->fields_byname,
(st_data_t) key, (st_data_t) field_value);
return 0;
}
avro_datum_t avro_enum(avro_schema_t schema, int i)
{
check_param(NULL, is_avro_schema(schema), "schema");
struct avro_enum_datum_t *datum =
(struct avro_enum_datum_t *) avro_new(struct avro_enum_datum_t);
if (!datum) {
avro_set_error("Cannot create new enum datum");
return NULL;
}
datum->schema = avro_schema_incref(schema);
datum->value = i;
avro_datum_init(&datum->obj, AVRO_ENUM);
return &datum->obj;
}
int avro_enum_get(const avro_datum_t datum)
{
return avro_datum_to_enum(datum)->value;
}
const char *avro_enum_get_name(const avro_datum_t datum)
{
int value = avro_enum_get(datum);
avro_schema_t schema = avro_datum_to_enum(datum)->schema;
return avro_schema_enum_get(schema, value);
}
int avro_enum_set(avro_datum_t datum, const int symbol_value)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_enum(datum), "enum datum");
avro_datum_to_enum(datum)->value = symbol_value;
return 0;
}
int avro_enum_set_name(avro_datum_t datum, const char *symbol_name)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_enum(datum), "enum datum");
check_param(EINVAL, symbol_name, "symbol name");
avro_schema_t schema = avro_datum_to_enum(datum)->schema;
int symbol_value = avro_schema_enum_get_by_name(schema, symbol_name);
if (symbol_value == -1) {
avro_set_error("No symbol named %s", symbol_name);
return EINVAL;
}
avro_datum_to_enum(datum)->value = symbol_value;
return 0;
}
static avro_datum_t avro_fixed_private(avro_schema_t schema,
const char *bytes, const int64_t size,
avro_free_func_t fixed_free)
{
check_param(NULL, is_avro_schema(schema), "schema");
struct avro_fixed_schema_t *fschema = avro_schema_to_fixed(schema);
if (size != fschema->size) {
avro_free((char *) bytes, size);
avro_set_error("Fixed size (%zu) doesn't match schema (%zu)",
(size_t) size, (size_t) fschema->size);
return NULL;
}
struct avro_fixed_datum_t *datum =
(struct avro_fixed_datum_t *) avro_new(struct avro_fixed_datum_t);
if (!datum) {
avro_free((char *) bytes, size);
avro_set_error("Cannot create new fixed datum");
return NULL;
}
datum->schema = avro_schema_incref(schema);
datum->size = size;
datum->bytes = (char *)bytes;
datum->free = fixed_free;
avro_datum_init(&datum->obj, AVRO_FIXED);
return &datum->obj;
}
avro_datum_t avro_fixed(avro_schema_t schema,
const char *bytes, const int64_t size)
{
char *bytes_copy = (char *) avro_malloc(size);
if (!bytes_copy) {
avro_set_error("Cannot copy fixed content");
return NULL;
}
memcpy(bytes_copy, bytes, size);
return avro_fixed_private(schema, bytes_copy, size, avro_alloc_free_func);
}
avro_datum_t avro_givefixed(avro_schema_t schema,
const char *bytes, const int64_t size,
avro_free_func_t free)
{
return avro_fixed_private(schema, bytes, size, free);
}
static int avro_fixed_set_private(avro_datum_t datum,
const char *bytes, const int64_t size,
avro_free_func_t fixed_free)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_fixed(datum), "fixed datum");
struct avro_fixed_datum_t *fixed = avro_datum_to_fixed(datum);
struct avro_fixed_schema_t *schema = avro_schema_to_fixed(fixed->schema);
if (size != schema->size) {
avro_set_error("Fixed size doesn't match schema");
return EINVAL;
}
if (fixed->free) {
fixed->free(fixed->bytes, fixed->size);
}
fixed->free = fixed_free;
fixed->bytes = (char *)bytes;
fixed->size = size;
return 0;
}
int avro_fixed_set(avro_datum_t datum, const char *bytes, const int64_t size)
{
int rval;
char *bytes_copy = (char *) avro_malloc(size);
if (!bytes_copy) {
avro_set_error("Cannot copy fixed content");
return ENOMEM;
}
memcpy(bytes_copy, bytes, size);
rval = avro_fixed_set_private(datum, bytes_copy, size, avro_alloc_free_func);
if (rval) {
avro_free(bytes_copy, size);
}
return rval;
}
int avro_givefixed_set(avro_datum_t datum, const char *bytes,
const int64_t size, avro_free_func_t free)
{
return avro_fixed_set_private(datum, bytes, size, free);
}
int avro_fixed_get(avro_datum_t datum, char **bytes, int64_t * size)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_fixed(datum), "fixed datum");
check_param(EINVAL, bytes, "bytes");
check_param(EINVAL, size, "size");
*bytes = avro_datum_to_fixed(datum)->bytes;
*size = avro_datum_to_fixed(datum)->size;
return 0;
}
static int
avro_init_map(struct avro_map_datum_t *datum)
{
datum->map = st_init_strtable_with_size(DEFAULT_TABLE_SIZE);
if (!datum->map) {
avro_set_error("Cannot create new map datum");
return ENOMEM;
}
datum->indices_by_key = st_init_strtable_with_size(DEFAULT_TABLE_SIZE);
if (!datum->indices_by_key) {
avro_set_error("Cannot create new map datum");
st_free_table(datum->map);
return ENOMEM;
}
datum->keys_by_index = st_init_numtable_with_size(DEFAULT_TABLE_SIZE);
if (!datum->keys_by_index) {
avro_set_error("Cannot create new map datum");
st_free_table(datum->indices_by_key);
st_free_table(datum->map);
return ENOMEM;
}
return 0;
}
avro_datum_t avro_map(avro_schema_t schema)
{
check_param(NULL, is_avro_schema(schema), "schema");
struct avro_map_datum_t *datum =
(struct avro_map_datum_t *) avro_new(struct avro_map_datum_t);
if (!datum) {
avro_set_error("Cannot create new map datum");
return NULL;
}
if (avro_init_map(datum) != 0) {
avro_freet(struct avro_map_datum_t, datum);
return NULL;
}
datum->schema = avro_schema_incref(schema);
avro_datum_init(&datum->obj, AVRO_MAP);
return &datum->obj;
}
size_t
avro_map_size(const avro_datum_t datum)
{
const struct avro_map_datum_t *map = avro_datum_to_map(datum);
return map->map->num_entries;
}
int
avro_map_get(const avro_datum_t datum, const char *key, avro_datum_t * value)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_map(datum), "map datum");
check_param(EINVAL, key, "key");
check_param(EINVAL, value, "value");
union {
avro_datum_t datum;
st_data_t data;
} val;
struct avro_map_datum_t *map = avro_datum_to_map(datum);
if (st_lookup(map->map, (st_data_t) key, &(val.data))) {
*value = val.datum;
return 0;
}
avro_set_error("No map element named %s", key);
return EINVAL;
}
int avro_map_get_key(const avro_datum_t datum, int index,
const char **key)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_map(datum), "map datum");
check_param(EINVAL, index >= 0, "index");
check_param(EINVAL, key, "key");
union {
st_data_t data;
char *key;
} val;
struct avro_map_datum_t *map = avro_datum_to_map(datum);
if (st_lookup(map->keys_by_index, (st_data_t) index, &val.data)) {
*key = val.key;
return 0;
}
avro_set_error("No map element with index %d", index);
return EINVAL;
}
int avro_map_get_index(const avro_datum_t datum, const char *key,
int *index)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_map(datum), "map datum");
check_param(EINVAL, key, "key");
check_param(EINVAL, index, "index");
st_data_t data;
struct avro_map_datum_t *map = avro_datum_to_map(datum);
if (st_lookup(map->indices_by_key, (st_data_t) key, &data)) {
*index = (int) data;
return 0;
}
avro_set_error("No map element with key %s", key);
return EINVAL;
}
int
avro_map_set(avro_datum_t datum, const char *key,
const avro_datum_t value)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
check_param(EINVAL, is_avro_map(datum), "map datum");
check_param(EINVAL, key, "key");
check_param(EINVAL, is_avro_datum(value), "value");
char *save_key = (char *)key;
avro_datum_t old_datum;
struct avro_map_datum_t *map = avro_datum_to_map(datum);
if (avro_map_get(datum, key, &old_datum) == 0) {
/* Overwriting an old value */
avro_datum_decref(old_datum);
} else {
/* Inserting a new value */
save_key = avro_strdup(key);
if (!save_key) {
avro_set_error("Cannot copy map key");
return ENOMEM;
}
int new_index = map->map->num_entries;
st_insert(map->indices_by_key, (st_data_t) save_key,
(st_data_t) new_index);
st_insert(map->keys_by_index, (st_data_t) new_index,
(st_data_t) save_key);
}
avro_datum_incref(value);
st_insert(map->map, (st_data_t) save_key, (st_data_t) value);
return 0;
}
static int
avro_init_array(struct avro_array_datum_t *datum)
{
datum->els = st_init_numtable_with_size(DEFAULT_TABLE_SIZE);
if (!datum->els) {
avro_set_error("Cannot create new array datum");
return ENOMEM;
}
return 0;
}
avro_datum_t avro_array(avro_schema_t schema)
{
check_param(NULL, is_avro_schema(schema), "schema");
struct avro_array_datum_t *datum =
(struct avro_array_datum_t *) avro_new(struct avro_array_datum_t);
if (!datum) {
avro_set_error("Cannot create new array datum");
return NULL;
}
if (avro_init_array(datum) != 0) {
avro_freet(struct avro_array_datum_t, datum);
return NULL;
}
datum->schema = avro_schema_incref(schema);
avro_datum_init(&datum->obj, AVRO_ARRAY);
return &datum->obj;
}
int
avro_array_get(const avro_datum_t array_datum, int64_t index, avro_datum_t * value)
{
check_param(EINVAL, is_avro_datum(array_datum), "datum");
check_param(EINVAL, is_avro_array(array_datum), "array datum");
check_param(EINVAL, value, "value pointer");
union {
st_data_t data;
avro_datum_t datum;
} val;
const struct avro_array_datum_t * array = avro_datum_to_array(array_datum);
if (st_lookup(array->els, index, &val.data)) {
*value = val.datum;
return 0;
}
avro_set_error("No array element with index %ld", (long) index);
return EINVAL;
}
size_t
avro_array_size(const avro_datum_t datum)
{
const struct avro_array_datum_t *array = avro_datum_to_array(datum);
return array->els->num_entries;
}
int
avro_array_append_datum(avro_datum_t array_datum,
const avro_datum_t datum)
{
check_param(EINVAL, is_avro_datum(array_datum), "datum");
check_param(EINVAL, is_avro_array(array_datum), "array datum");
check_param(EINVAL, is_avro_datum(datum), "element datum");
struct avro_array_datum_t *array = avro_datum_to_array(array_datum);
st_insert(array->els, array->els->num_entries,
(st_data_t) avro_datum_incref(datum));
return 0;
}
static int char_datum_free_foreach(char *key, avro_datum_t datum, void *arg)
{
AVRO_UNUSED(arg);
avro_datum_decref(datum);
avro_str_free(key);
return ST_DELETE;
}
static int array_free_foreach(int i, avro_datum_t datum, void *arg)
{
AVRO_UNUSED(i);
AVRO_UNUSED(arg);
avro_datum_decref(datum);
return ST_DELETE;
}
avro_schema_t avro_datum_get_schema(const avro_datum_t datum)
{
check_param(NULL, is_avro_datum(datum), "datum");
switch (avro_typeof(datum)) {
/*
* For the primitive types, which don't store an
* explicit reference to their schema, we decref the
* schema before returning. This maintains the
* invariant that this function doesn't add any
* additional references to the schema. The primitive
* schemas won't be freed, because there's always at
* least 1 reference for their initial static
* initializers.
*/
case AVRO_STRING:
{
avro_schema_t result = avro_schema_string();
avro_schema_decref(result);
return result;
}
case AVRO_BYTES:
{
avro_schema_t result = avro_schema_bytes();
avro_schema_decref(result);
return result;
}
case AVRO_INT32:
{
avro_schema_t result = avro_schema_int();
avro_schema_decref(result);
return result;
}
case AVRO_INT64:
{
avro_schema_t result = avro_schema_long();
avro_schema_decref(result);
return result;
}
case AVRO_FLOAT:
{
avro_schema_t result = avro_schema_float();
avro_schema_decref(result);
return result;
}
case AVRO_DOUBLE:
{
avro_schema_t result = avro_schema_double();
avro_schema_decref(result);
return result;
}
case AVRO_BOOLEAN:
{
avro_schema_t result = avro_schema_boolean();
avro_schema_decref(result);
return result;
}
case AVRO_NULL:
{
avro_schema_t result = avro_schema_null();
avro_schema_decref(result);
return result;
}
case AVRO_RECORD:
return avro_datum_to_record(datum)->schema;
case AVRO_ENUM:
return avro_datum_to_enum(datum)->schema;
case AVRO_FIXED:
return avro_datum_to_fixed(datum)->schema;
case AVRO_MAP:
return avro_datum_to_map(datum)->schema;
case AVRO_ARRAY:
return avro_datum_to_array(datum)->schema;
case AVRO_UNION:
return avro_datum_to_union(datum)->schema;
default:
return NULL;
}
}
static void avro_datum_free(avro_datum_t datum)
{
if (is_avro_datum(datum)) {
switch (avro_typeof(datum)) {
case AVRO_STRING:{
struct avro_string_datum_t *string;
string = avro_datum_to_string(datum);
if (string->free) {
string->free(string->s, string->size);
}
avro_freet(struct avro_string_datum_t, string);
}
break;
case AVRO_BYTES:{
struct avro_bytes_datum_t *bytes;
bytes = avro_datum_to_bytes(datum);
if (bytes->free) {
bytes->free(bytes->bytes, bytes->size);
}
avro_freet(struct avro_bytes_datum_t, bytes);
}
break;
case AVRO_INT32:{
avro_freet(struct avro_int32_datum_t, datum);
}
break;
case AVRO_INT64:{
avro_freet(struct avro_int64_datum_t, datum);
}
break;
case AVRO_FLOAT:{
avro_freet(struct avro_float_datum_t, datum);
}
break;
case AVRO_DOUBLE:{
avro_freet(struct avro_double_datum_t, datum);
}
break;
case AVRO_BOOLEAN:{
avro_freet(struct avro_boolean_datum_t, datum);
}
break;
case AVRO_NULL:
/* Nothing allocated */
break;
case AVRO_RECORD:{
struct avro_record_datum_t *record;
record = avro_datum_to_record(datum);
avro_schema_decref(record->schema);
st_foreach(record->fields_byname,
HASH_FUNCTION_CAST char_datum_free_foreach, 0);
st_free_table(record->field_order);
st_free_table(record->fields_byname);
avro_freet(struct avro_record_datum_t, record);
}
break;
case AVRO_ENUM:{
struct avro_enum_datum_t *enump;
enump = avro_datum_to_enum(datum);
avro_schema_decref(enump->schema);
avro_freet(struct avro_enum_datum_t, enump);
}
break;
case AVRO_FIXED:{
struct avro_fixed_datum_t *fixed;
fixed = avro_datum_to_fixed(datum);
avro_schema_decref(fixed->schema);
if (fixed->free) {
fixed->free((void *)fixed->bytes,
fixed->size);
}
avro_freet(struct avro_fixed_datum_t, fixed);
}
break;
case AVRO_MAP:{
struct avro_map_datum_t *map;
map = avro_datum_to_map(datum);
avro_schema_decref(map->schema);
st_foreach(map->map, HASH_FUNCTION_CAST char_datum_free_foreach,
0);
st_free_table(map->map);
st_free_table(map->indices_by_key);
st_free_table(map->keys_by_index);
avro_freet(struct avro_map_datum_t, map);
}
break;
case AVRO_ARRAY:{
struct avro_array_datum_t *array;
array = avro_datum_to_array(datum);
avro_schema_decref(array->schema);
st_foreach(array->els, HASH_FUNCTION_CAST array_free_foreach, 0);
st_free_table(array->els);
avro_freet(struct avro_array_datum_t, array);
}
break;
case AVRO_UNION:{
struct avro_union_datum_t *unionp;
unionp = avro_datum_to_union(datum);
avro_schema_decref(unionp->schema);
avro_datum_decref(unionp->value);
avro_freet(struct avro_union_datum_t, unionp);
}
break;
case AVRO_LINK:{
/* TODO */
}
break;
}
}
}
static int
datum_reset_foreach(int i, avro_datum_t datum, void *arg)
{
AVRO_UNUSED(i);
int rval;
int *result = (int *) arg;
rval = avro_datum_reset(datum);
if (rval == 0) {
return ST_CONTINUE;
} else {
*result = rval;
return ST_STOP;
}
}
int
avro_datum_reset(avro_datum_t datum)
{
check_param(EINVAL, is_avro_datum(datum), "datum");
int rval;
switch (avro_typeof(datum)) {
case AVRO_ARRAY:
{
struct avro_array_datum_t *array;
array = avro_datum_to_array(datum);
st_foreach(array->els, HASH_FUNCTION_CAST array_free_foreach, 0);
st_free_table(array->els);
rval = avro_init_array(array);
if (rval != 0) {
avro_freet(struct avro_array_datum_t, array);
return rval;
}
return 0;
}
case AVRO_MAP:
{
struct avro_map_datum_t *map;
map = avro_datum_to_map(datum);
st_foreach(map->map, HASH_FUNCTION_CAST char_datum_free_foreach, 0);
st_free_table(map->map);
st_free_table(map->indices_by_key);
st_free_table(map->keys_by_index);
rval = avro_init_map(map);
if (rval != 0) {
avro_freet(struct avro_map_datum_t, map);
return rval;
}
return 0;
}
case AVRO_RECORD:
{
struct avro_record_datum_t *record;
record = avro_datum_to_record(datum);
rval = 0;
st_foreach(record->fields_byname,
HASH_FUNCTION_CAST datum_reset_foreach, (st_data_t) &rval);
return rval;
}
case AVRO_UNION:
{
struct avro_union_datum_t *unionp;
unionp = avro_datum_to_union(datum);
return (unionp->value == NULL)? 0:
avro_datum_reset(unionp->value);
}
default:
return 0;
}
}
avro_datum_t avro_datum_incref(avro_datum_t datum)
{
if (datum) {
avro_refcount_inc(&datum->refcount);
}
return datum;
}
void avro_datum_decref(avro_datum_t datum)
{
if (datum && avro_refcount_dec(&datum->refcount)) {
avro_datum_free(datum);
}
}
void avro_datum_print(avro_datum_t value, FILE * fp)
{
AVRO_UNUSED(value);
AVRO_UNUSED(fp);
}