/* * 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. */ #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 #include #include #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); }