1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to you under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  * https://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14  * implied.  See the License for the specific language governing
15  * permissions and limitations under the License.
16  */
17 
18 #include <avro/platform.h>
19 #include <stdlib.h>
20 #include <string.h>
21 
22 #include "avro/allocation.h"
23 #include "avro/basics.h"
24 #include "avro/errors.h"
25 #include "avro/legacy.h"
26 #include "avro/refcount.h"
27 #include "avro/schema.h"
28 #include "avro/value.h"
29 #include "avro_private.h"
30 
31 extern avro_value_iface_t  AVRO_DATUM_VALUE_CLASS;
32 
33 avro_value_iface_t *
avro_datum_class(void)34 avro_datum_class(void)
35 {
36 	return &AVRO_DATUM_VALUE_CLASS;
37 }
38 
39 int
avro_datum_as_value(avro_value_t * value,avro_datum_t src)40 avro_datum_as_value(avro_value_t *value, avro_datum_t src)
41 {
42 	value->iface = &AVRO_DATUM_VALUE_CLASS;
43 	value->self = avro_datum_incref(src);
44 	return 0;
45 }
46 
47 static int
avro_datum_as_child_value(avro_value_t * value,avro_datum_t src)48 avro_datum_as_child_value(avro_value_t *value, avro_datum_t src)
49 {
50 	value->iface = &AVRO_DATUM_VALUE_CLASS;
51 	value->self = src;
52 	return 0;
53 }
54 
55 static void
avro_datum_value_incref(avro_value_t * value)56 avro_datum_value_incref(avro_value_t *value)
57 {
58 	avro_datum_t  self = (avro_datum_t) value->self;
59 	avro_datum_incref(self);
60 }
61 
62 static void
avro_datum_value_decref(avro_value_t * value)63 avro_datum_value_decref(avro_value_t *value)
64 {
65 	avro_datum_t  self = (avro_datum_t) value->self;
66 	avro_datum_decref(self);
67 }
68 
69 static int
avro_datum_value_reset(const avro_value_iface_t * iface,void * vself)70 avro_datum_value_reset(const avro_value_iface_t *iface, void *vself)
71 {
72 	AVRO_UNUSED(iface);
73 	avro_datum_t  self = (avro_datum_t) vself;
74 	check_param(EINVAL, self, "datum instance");
75 	return avro_datum_reset(self);
76 }
77 
78 static avro_type_t
avro_datum_value_get_type(const avro_value_iface_t * iface,const void * vself)79 avro_datum_value_get_type(const avro_value_iface_t *iface, const void *vself)
80 {
81 	AVRO_UNUSED(iface);
82 	const avro_datum_t  self = (const avro_datum_t) vself;
83 #ifdef _WIN32
84 #pragma message("#warning: Bug: EINVAL is not of type avro_type_t.")
85 #else
86 #warning "Bug: EINVAL is not of type avro_type_t."
87 #endif
88         /* We shouldn't use EINVAL as the return value to
89          * check_param(), because EINVAL (= 22) is not a valid enum
90          * avro_type_t. This is a structural issue -- we would need a
91          * different interface on all the get_type functions to fix
92          * this. For now, suppressing the error by casting EINVAL to
93          * (avro_type_t) so the code compiles under C++.
94          */
95 	check_param((avro_type_t) EINVAL, self, "datum instance");
96 	return avro_typeof(self);
97 }
98 
99 static avro_schema_t
avro_datum_value_get_schema(const avro_value_iface_t * iface,const void * vself)100 avro_datum_value_get_schema(const avro_value_iface_t *iface, const void *vself)
101 {
102 	AVRO_UNUSED(iface);
103 	const avro_datum_t  self = (const avro_datum_t) vself;
104 	check_param(NULL, self, "datum instance");
105 	return avro_datum_get_schema(self);
106 }
107 
108 
109 static int
avro_datum_value_get_boolean(const avro_value_iface_t * iface,const void * vself,int * out)110 avro_datum_value_get_boolean(const avro_value_iface_t *iface,
111 			     const void *vself, int *out)
112 {
113 	AVRO_UNUSED(iface);
114 	const avro_datum_t  self = (const avro_datum_t) vself;
115 	check_param(EINVAL, self, "datum instance");
116 
117 	int  rval;
118 	int8_t  value;
119 	check(rval, avro_boolean_get(self, &value));
120 	*out = value;
121 	return 0;
122 }
123 
124 static int
avro_datum_value_get_bytes(const avro_value_iface_t * iface,const void * vself,const void ** buf,size_t * size)125 avro_datum_value_get_bytes(const avro_value_iface_t *iface,
126 			   const void *vself, const void **buf, size_t *size)
127 {
128 	AVRO_UNUSED(iface);
129 	const avro_datum_t  self = (const avro_datum_t) vself;
130 	check_param(EINVAL, self, "datum instance");
131 
132 	int  rval;
133 	char  *bytes;
134 	int64_t  sz;
135 	check(rval, avro_bytes_get(self, &bytes, &sz));
136 	if (buf != NULL) {
137 		*buf = (const void *) bytes;
138 	}
139 	if (size != NULL) {
140 		*size = sz;
141 	}
142 	return 0;
143 }
144 
145 static int
avro_datum_value_grab_bytes(const avro_value_iface_t * iface,const void * vself,avro_wrapped_buffer_t * dest)146 avro_datum_value_grab_bytes(const avro_value_iface_t *iface,
147 			    const void *vself, avro_wrapped_buffer_t *dest)
148 {
149 	AVRO_UNUSED(iface);
150 	const avro_datum_t  self = (const avro_datum_t) vself;
151 	check_param(EINVAL, self, "datum instance");
152 
153 	int  rval;
154 	char  *bytes;
155 	int64_t  sz;
156 	check(rval, avro_bytes_get(self, &bytes, &sz));
157 
158 	/* nothing clever, just make a copy */
159 	return avro_wrapped_buffer_new_copy(dest, bytes, sz);
160 }
161 
162 static int
avro_datum_value_get_double(const avro_value_iface_t * iface,const void * vself,double * out)163 avro_datum_value_get_double(const avro_value_iface_t *iface,
164 			    const void *vself, double *out)
165 {
166 	AVRO_UNUSED(iface);
167 	const avro_datum_t  self = (const avro_datum_t) vself;
168 	check_param(EINVAL, self, "datum instance");
169 
170 	int  rval;
171 	double  value;
172 	check(rval, avro_double_get(self, &value));
173 	*out = value;
174 	return 0;
175 }
176 
177 static int
avro_datum_value_get_float(const avro_value_iface_t * iface,const void * vself,float * out)178 avro_datum_value_get_float(const avro_value_iface_t *iface,
179 			   const void *vself, float *out)
180 {
181 	AVRO_UNUSED(iface);
182 	const avro_datum_t  self = (const avro_datum_t) vself;
183 	check_param(EINVAL, self, "datum instance");
184 
185 	int  rval;
186 	float  value;
187 	check(rval, avro_float_get(self, &value));
188 	*out = value;
189 	return 0;
190 }
191 
192 static int
avro_datum_value_get_int(const avro_value_iface_t * iface,const void * vself,int32_t * out)193 avro_datum_value_get_int(const avro_value_iface_t *iface,
194 			 const void *vself, int32_t *out)
195 {
196 	AVRO_UNUSED(iface);
197 	const avro_datum_t  self = (const avro_datum_t) vself;
198 	check_param(EINVAL, self, "datum instance");
199 
200 	int  rval;
201 	int32_t  value;
202 	check(rval, avro_int32_get(self, &value));
203 	*out = value;
204 	return 0;
205 }
206 
207 static int
avro_datum_value_get_long(const avro_value_iface_t * iface,const void * vself,int64_t * out)208 avro_datum_value_get_long(const avro_value_iface_t *iface,
209 			  const void *vself, int64_t *out)
210 {
211 	AVRO_UNUSED(iface);
212 	const avro_datum_t  self = (const avro_datum_t) vself;
213 	check_param(EINVAL, self, "datum instance");
214 
215 	int  rval;
216 	int64_t  value;
217 	check(rval, avro_int64_get(self, &value));
218 	*out = value;
219 	return 0;
220 }
221 
222 static int
avro_datum_value_get_null(const avro_value_iface_t * iface,const void * vself)223 avro_datum_value_get_null(const avro_value_iface_t *iface,
224 			  const void *vself)
225 {
226 	AVRO_UNUSED(iface);
227 	const avro_datum_t  self = (const avro_datum_t) vself;
228 	check_param(EINVAL, is_avro_null(self), "datum instance");
229 	return 0;
230 }
231 
232 static int
avro_datum_value_get_string(const avro_value_iface_t * iface,const void * vself,const char ** str,size_t * size)233 avro_datum_value_get_string(const avro_value_iface_t *iface,
234 			    const void *vself, const char **str, size_t *size)
235 {
236 	AVRO_UNUSED(iface);
237 	const avro_datum_t  self = (const avro_datum_t) vself;
238 	check_param(EINVAL, self, "datum instance");
239 
240 	int  rval;
241 	char  *value;
242 	check(rval, avro_string_get(self, &value));
243 	if (str != NULL) {
244 		*str = (const char *) value;
245 	}
246 	if (size != NULL) {
247 		*size = strlen(value)+1;
248 	}
249 	return 0;
250 }
251 
252 static int
avro_datum_value_grab_string(const avro_value_iface_t * iface,const void * vself,avro_wrapped_buffer_t * dest)253 avro_datum_value_grab_string(const avro_value_iface_t *iface,
254 			     const void *vself, avro_wrapped_buffer_t *dest)
255 {
256 	AVRO_UNUSED(iface);
257 	const avro_datum_t  self = (const avro_datum_t) vself;
258 	check_param(EINVAL, self, "datum instance");
259 
260 	int  rval;
261 	char  *str;
262 	size_t  sz;
263 	check(rval, avro_string_get(self, &str));
264 	sz = strlen(str);
265 
266 	/* nothing clever, just make a copy */
267 	/* sz doesn't contain NUL terminator */
268 	return avro_wrapped_buffer_new_copy(dest, str, sz+1);
269 }
270 
271 static int
avro_datum_value_get_enum(const avro_value_iface_t * iface,const void * vself,int * out)272 avro_datum_value_get_enum(const avro_value_iface_t *iface,
273 			  const void *vself, int *out)
274 {
275 	AVRO_UNUSED(iface);
276 	const avro_datum_t  self = (const avro_datum_t) vself;
277 	check_param(EINVAL, is_avro_enum(self), "datum instance");
278 	*out = avro_enum_get(self);
279 	return 0;
280 }
281 
282 static int
avro_datum_value_get_fixed(const avro_value_iface_t * iface,const void * vself,const void ** buf,size_t * size)283 avro_datum_value_get_fixed(const avro_value_iface_t *iface,
284 			   const void *vself, const void **buf, size_t *size)
285 {
286 	AVRO_UNUSED(iface);
287 	const avro_datum_t  self = (const avro_datum_t) vself;
288 	check_param(EINVAL, self, "datum instance");
289 
290 	int  rval;
291 	char  *bytes;
292 	int64_t  sz;
293 	check(rval, avro_fixed_get(self, &bytes, &sz));
294 	if (buf != NULL) {
295 		*buf = (const void *) bytes;
296 	}
297 	if (size != NULL) {
298 		*size = sz;
299 	}
300 	return 0;
301 }
302 
303 static int
avro_datum_value_grab_fixed(const avro_value_iface_t * iface,const void * vself,avro_wrapped_buffer_t * dest)304 avro_datum_value_grab_fixed(const avro_value_iface_t *iface,
305 			    const void *vself, avro_wrapped_buffer_t *dest)
306 {
307 	AVRO_UNUSED(iface);
308 	const avro_datum_t  self = (const avro_datum_t) vself;
309 	check_param(EINVAL, self, "datum instance");
310 
311 	int  rval;
312 	char  *bytes;
313 	int64_t  sz;
314 	check(rval, avro_fixed_get(self, &bytes, &sz));
315 
316 	/* nothing clever, just make a copy */
317 	return avro_wrapped_buffer_new_copy(dest, bytes, sz);
318 }
319 
320 
321 static int
avro_datum_value_set_boolean(const avro_value_iface_t * iface,void * vself,int val)322 avro_datum_value_set_boolean(const avro_value_iface_t *iface,
323 			     void *vself, int val)
324 {
325 	AVRO_UNUSED(iface);
326 	avro_datum_t  self = (avro_datum_t) vself;
327 	check_param(EINVAL, self, "datum instance");
328 	return avro_boolean_set(self, val);
329 }
330 
331 static int
avro_datum_value_set_bytes(const avro_value_iface_t * iface,void * vself,void * buf,size_t size)332 avro_datum_value_set_bytes(const avro_value_iface_t *iface,
333 			   void *vself, void *buf, size_t size)
334 {
335 	AVRO_UNUSED(iface);
336 	avro_datum_t  self = (avro_datum_t) vself;
337 	check_param(EINVAL, self, "datum instance");
338 	return avro_bytes_set(self, (const char *) buf, size);
339 }
340 
341 static int
avro_datum_value_give_bytes(const avro_value_iface_t * iface,void * vself,avro_wrapped_buffer_t * buf)342 avro_datum_value_give_bytes(const avro_value_iface_t *iface,
343 			    void *vself, avro_wrapped_buffer_t *buf)
344 {
345 	/*
346 	 * We actually can't use avro_givebytes_set, since it can't
347 	 * handle the extra free_ud parameter.  Ah well, this is
348 	 * deprecated, so go ahead and make a copy.
349 	 */
350 
351 	int rval = avro_datum_value_set_bytes
352 	    (iface, vself, (void *) buf->buf, buf->size);
353 	avro_wrapped_buffer_free(buf);
354 	return rval;
355 }
356 
357 static int
avro_datum_value_set_double(const avro_value_iface_t * iface,void * vself,double val)358 avro_datum_value_set_double(const avro_value_iface_t *iface,
359 			    void *vself, double val)
360 {
361 	AVRO_UNUSED(iface);
362 	avro_datum_t  self = (avro_datum_t) vself;
363 	check_param(EINVAL, self, "datum instance");
364 	return avro_double_set(self, val);
365 }
366 
367 static int
avro_datum_value_set_float(const avro_value_iface_t * iface,void * vself,float val)368 avro_datum_value_set_float(const avro_value_iface_t *iface,
369 			   void *vself, float val)
370 {
371 	AVRO_UNUSED(iface);
372 	avro_datum_t  self = (avro_datum_t) vself;
373 	check_param(EINVAL, self, "datum instance");
374 	return avro_float_set(self, val);
375 }
376 
377 static int
avro_datum_value_set_int(const avro_value_iface_t * iface,void * vself,int32_t val)378 avro_datum_value_set_int(const avro_value_iface_t *iface,
379 			 void *vself, int32_t val)
380 {
381 	AVRO_UNUSED(iface);
382 	avro_datum_t  self = (avro_datum_t) vself;
383 	check_param(EINVAL, self, "datum instance");
384 	return avro_int32_set(self, val);
385 }
386 
387 static int
avro_datum_value_set_long(const avro_value_iface_t * iface,void * vself,int64_t val)388 avro_datum_value_set_long(const avro_value_iface_t *iface,
389 			  void *vself, int64_t val)
390 {
391 	AVRO_UNUSED(iface);
392 	avro_datum_t  self = (avro_datum_t) vself;
393 	check_param(EINVAL, self, "datum instance");
394 	return avro_int64_set(self, val);
395 }
396 
397 static int
avro_datum_value_set_null(const avro_value_iface_t * iface,void * vself)398 avro_datum_value_set_null(const avro_value_iface_t *iface, void *vself)
399 {
400 	AVRO_UNUSED(iface);
401 	avro_datum_t  self = (avro_datum_t) vself;
402 	check_param(EINVAL, is_avro_null(self), "datum instance");
403 	return 0;
404 }
405 
406 static int
avro_datum_value_set_string(const avro_value_iface_t * iface,void * vself,const char * str)407 avro_datum_value_set_string(const avro_value_iface_t *iface,
408 			    void *vself, const char *str)
409 {
410 	AVRO_UNUSED(iface);
411 	avro_datum_t  self = (avro_datum_t) vself;
412 	check_param(EINVAL, self, "datum instance");
413 	return avro_string_set(self, str);
414 }
415 
416 static int
avro_datum_value_set_string_len(const avro_value_iface_t * iface,void * vself,const char * str,size_t size)417 avro_datum_value_set_string_len(const avro_value_iface_t *iface,
418 				void *vself, const char *str, size_t size)
419 {
420 	AVRO_UNUSED(iface);
421 	AVRO_UNUSED(size);
422 	avro_datum_t  self = (avro_datum_t) vself;
423 	check_param(EINVAL, self, "datum instance");
424 	return avro_string_set(self, str);
425 }
426 
427 static int
avro_datum_value_give_string_len(const avro_value_iface_t * iface,void * vself,avro_wrapped_buffer_t * buf)428 avro_datum_value_give_string_len(const avro_value_iface_t *iface,
429 				 void *vself, avro_wrapped_buffer_t *buf)
430 {
431 	/*
432 	 * We actually can't use avro_givestring_set, since it can't
433 	 * handle the extra free_ud parameter.  Ah well, this is
434 	 * deprecated, so go ahead and make a copy.
435 	 */
436 
437 	int rval = avro_datum_value_set_string_len
438 	    (iface, vself, (char *) buf->buf, buf->size-1);
439 	avro_wrapped_buffer_free(buf);
440 	return rval;
441 }
442 
443 static int
avro_datum_value_set_enum(const avro_value_iface_t * iface,void * vself,int val)444 avro_datum_value_set_enum(const avro_value_iface_t *iface,
445 			  void *vself, int val)
446 {
447 	AVRO_UNUSED(iface);
448 	avro_datum_t  self = (avro_datum_t) vself;
449 	check_param(EINVAL, self, "datum instance");
450 	return avro_enum_set(self, val);
451 }
452 
453 static int
avro_datum_value_set_fixed(const avro_value_iface_t * iface,void * vself,void * buf,size_t size)454 avro_datum_value_set_fixed(const avro_value_iface_t *iface,
455 			   void *vself, void *buf, size_t size)
456 {
457 	AVRO_UNUSED(iface);
458 	avro_datum_t  self = (avro_datum_t) vself;
459 	check_param(EINVAL, self, "datum instance");
460 	return avro_fixed_set(self, (const char *) buf, size);
461 }
462 
463 static int
avro_datum_value_give_fixed(const avro_value_iface_t * iface,void * vself,avro_wrapped_buffer_t * buf)464 avro_datum_value_give_fixed(const avro_value_iface_t *iface,
465 			    void *vself, avro_wrapped_buffer_t *buf)
466 {
467 	/*
468 	 * We actually can't use avro_givefixed_set, since it can't
469 	 * handle the extra free_ud parameter.  Ah well, this is
470 	 * deprecated, so go ahead and make a copy.
471 	 */
472 
473 	int rval = avro_datum_value_set_fixed
474 	    (iface, vself, (void *) buf->buf, buf->size);
475 	avro_wrapped_buffer_free(buf);
476 	return rval;
477 }
478 
479 
480 static int
avro_datum_value_get_size(const avro_value_iface_t * iface,const void * vself,size_t * size)481 avro_datum_value_get_size(const avro_value_iface_t *iface,
482 			  const void *vself, size_t *size)
483 {
484 	AVRO_UNUSED(iface);
485 	const avro_datum_t  self = (const avro_datum_t) vself;
486 	check_param(EINVAL, self, "datum instance");
487 
488 	if (is_avro_array(self)) {
489 		*size = avro_array_size(self);
490 		return 0;
491 	}
492 
493 	if (is_avro_map(self)) {
494 		*size = avro_map_size(self);
495 		return 0;
496 	}
497 
498 	if (is_avro_record(self)) {
499 		avro_schema_t  schema = avro_datum_get_schema(self);
500 		*size = avro_schema_record_size(schema);
501 		return 0;
502 	}
503 
504 	avro_set_error("Can only get size of array, map, or record, %d", avro_typeof(self));
505 	return EINVAL;
506 }
507 
508 static int
avro_datum_value_get_by_index(const avro_value_iface_t * iface,const void * vself,size_t index,avro_value_t * child,const char ** name)509 avro_datum_value_get_by_index(const avro_value_iface_t *iface,
510 			      const void *vself, size_t index,
511 			      avro_value_t *child, const char **name)
512 {
513 	AVRO_UNUSED(iface);
514 	const avro_datum_t  self = (const avro_datum_t) vself;
515 	check_param(EINVAL, self, "datum instance");
516 
517 	int  rval;
518 	avro_datum_t  child_datum;
519 
520 	if (is_avro_array(self)) {
521 		check(rval, avro_array_get(self, index, &child_datum));
522 		return avro_datum_as_child_value(child, child_datum);
523 	}
524 
525 	if (is_avro_map(self)) {
526 		const char  *real_key;
527 		check(rval, avro_map_get_key(self, index, &real_key));
528 		if (name != NULL) {
529 			*name = real_key;
530 		}
531 		check(rval, avro_map_get(self, real_key, &child_datum));
532 		return avro_datum_as_child_value(child, child_datum);
533 	}
534 
535 	if (is_avro_record(self)) {
536 		avro_schema_t  schema = avro_datum_get_schema(self);
537 		const char  *field_name =
538 		    avro_schema_record_field_name(schema, index);
539 		if (field_name == NULL) {
540 			return EINVAL;
541 		}
542 		if (name != NULL) {
543 			*name = field_name;
544 		}
545 		check(rval, avro_record_get(self, field_name, &child_datum));
546 		return avro_datum_as_child_value(child, child_datum);
547 	}
548 
549 	avro_set_error("Can only get by index from array, map, or record");
550 	return EINVAL;
551 }
552 
553 static int
avro_datum_value_get_by_name(const avro_value_iface_t * iface,const void * vself,const char * name,avro_value_t * child,size_t * index)554 avro_datum_value_get_by_name(const avro_value_iface_t *iface,
555 			     const void *vself, const char *name,
556 			     avro_value_t *child, size_t *index)
557 {
558 	AVRO_UNUSED(iface);
559 	const avro_datum_t  self = (const avro_datum_t) vself;
560 	check_param(EINVAL, self, "datum instance");
561 
562 	int  rval;
563 	avro_datum_t  child_datum;
564 
565 	if (is_avro_map(self)) {
566 		if (index != NULL) {
567 			int  real_index;
568 			check(rval, avro_map_get_index(self, name, &real_index));
569 			*index = real_index;
570 		}
571 
572 		check(rval, avro_map_get(self, name, &child_datum));
573 		return avro_datum_as_child_value(child, child_datum);
574 	}
575 
576 	if (is_avro_record(self)) {
577 		if (index != NULL) {
578 			avro_schema_t  schema = avro_datum_get_schema(self);
579 			*index = avro_schema_record_field_get_index(schema, name);
580 		}
581 
582 		check(rval, avro_record_get(self, name, &child_datum));
583 		return avro_datum_as_child_value(child, child_datum);
584 	}
585 
586 	avro_set_error("Can only get by name from map or record");
587 	return EINVAL;
588 }
589 
590 static int
avro_datum_value_get_discriminant(const avro_value_iface_t * iface,const void * vself,int * out)591 avro_datum_value_get_discriminant(const avro_value_iface_t *iface,
592 				  const void *vself, int *out)
593 {
594 	AVRO_UNUSED(iface);
595 	const avro_datum_t  self = (const avro_datum_t) vself;
596 	check_param(EINVAL, self, "datum instance");
597 
598 	if (!is_avro_union(self)) {
599 		avro_set_error("Can only get discriminant of union");
600 		return EINVAL;
601 	}
602 
603 	*out = avro_union_discriminant(self);
604 	return 0;
605 }
606 
607 static int
avro_datum_value_get_current_branch(const avro_value_iface_t * iface,const void * vself,avro_value_t * branch)608 avro_datum_value_get_current_branch(const avro_value_iface_t *iface,
609 				    const void *vself, avro_value_t *branch)
610 {
611 	AVRO_UNUSED(iface);
612 	const avro_datum_t  self = (const avro_datum_t) vself;
613 	check_param(EINVAL, self, "datum instance");
614 
615 	if (!is_avro_union(self)) {
616 		avro_set_error("Can only get current branch of union");
617 		return EINVAL;
618 	}
619 
620 	avro_datum_t  child_datum = avro_union_current_branch(self);
621 	return avro_datum_as_child_value(branch, child_datum);
622 }
623 
624 
625 static int
avro_datum_value_append(const avro_value_iface_t * iface,void * vself,avro_value_t * child_out,size_t * new_index)626 avro_datum_value_append(const avro_value_iface_t *iface,
627 			void *vself, avro_value_t *child_out, size_t *new_index)
628 {
629 	AVRO_UNUSED(iface);
630 	avro_datum_t  self = (avro_datum_t) vself;
631 	check_param(EINVAL, self, "datum instance");
632 
633 	if (!is_avro_array(self)) {
634 		avro_set_error("Can only append to array");
635 		return EINVAL;
636 	}
637 
638 	int  rval;
639 
640 	avro_schema_t  array_schema = avro_datum_get_schema(self);
641 	avro_schema_t  child_schema = avro_schema_array_items(array_schema);
642 	avro_datum_t  child_datum = avro_datum_from_schema(child_schema);
643 	if (child_datum == NULL) {
644 		return ENOMEM;
645 	}
646 
647 	rval = avro_array_append_datum(self, child_datum);
648 	avro_datum_decref(child_datum);
649 	if (rval != 0) {
650 		return rval;
651 	}
652 
653 	if (new_index != NULL) {
654 		*new_index = avro_array_size(self) - 1;
655 	}
656 	return avro_datum_as_child_value(child_out, child_datum);
657 }
658 
659 static int
avro_datum_value_add(const avro_value_iface_t * iface,void * vself,const char * key,avro_value_t * child,size_t * index,int * is_new)660 avro_datum_value_add(const avro_value_iface_t *iface,
661 		     void *vself, const char *key,
662 		     avro_value_t *child, size_t *index, int *is_new)
663 {
664 	AVRO_UNUSED(iface);
665 	avro_datum_t  self = (avro_datum_t) vself;
666 	check_param(EINVAL, self, "datum instance");
667 
668 	if (!is_avro_map(self)) {
669 		avro_set_error("Can only add to map");
670 		return EINVAL;
671 	}
672 
673 	int  rval;
674 	avro_datum_t  child_datum;
675 
676 	if (avro_map_get(self, key, &child_datum) == 0) {
677 		/* key already exists */
678 		if (is_new != NULL) {
679 			*is_new = 0;
680 		}
681 		if (index != NULL) {
682 			int  real_index;
683 			avro_map_get_index(self, key, &real_index);
684 			*index = real_index;
685 		}
686 		return avro_datum_as_child_value(child, child_datum);
687 	}
688 
689 	/* key is new */
690 	avro_schema_t  map_schema = avro_datum_get_schema(self);
691 	avro_schema_t  child_schema = avro_schema_map_values(map_schema);
692 	child_datum = avro_datum_from_schema(child_schema);
693 	if (child_datum == NULL) {
694 		return ENOMEM;
695 	}
696 
697 	rval = avro_map_set(self, key, child_datum);
698 	avro_datum_decref(child_datum);
699 	if (rval != 0) {
700 		return rval;
701 	}
702 
703 	if (is_new != NULL) {
704 		*is_new = 1;
705 	}
706 	if (index != NULL) {
707 		*index = avro_map_size(self) - 1;
708 	}
709 
710 	return avro_datum_as_child_value(child, child_datum);
711 }
712 
713 static int
avro_datum_value_set_branch(const avro_value_iface_t * iface,void * vself,int discriminant,avro_value_t * branch)714 avro_datum_value_set_branch(const avro_value_iface_t *iface,
715 			    void *vself, int discriminant,
716 			    avro_value_t *branch)
717 {
718 	AVRO_UNUSED(iface);
719 	const avro_datum_t  self = (const avro_datum_t) vself;
720 	check_param(EINVAL, self, "datum instance");
721 
722 	if (!is_avro_union(self)) {
723 		avro_set_error("Can only set branch of union");
724 		return EINVAL;
725 	}
726 
727 	int  rval;
728 	avro_datum_t  child_datum;
729 	check(rval, avro_union_set_discriminant(self, discriminant, &child_datum));
730 	return avro_datum_as_child_value(branch, child_datum);
731 }
732 
733 
734 avro_value_iface_t  AVRO_DATUM_VALUE_CLASS =
735 {
736 	/* "class" methods */
737 	NULL, /* incref */
738 	NULL, /* decref */
739 	/* general "instance" methods */
740 	avro_datum_value_incref,
741 	avro_datum_value_decref,
742 	avro_datum_value_reset,
743 	avro_datum_value_get_type,
744 	avro_datum_value_get_schema,
745 	/* primitive getters */
746 	avro_datum_value_get_boolean,
747 	avro_datum_value_get_bytes,
748 	avro_datum_value_grab_bytes,
749 	avro_datum_value_get_double,
750 	avro_datum_value_get_float,
751 	avro_datum_value_get_int,
752 	avro_datum_value_get_long,
753 	avro_datum_value_get_null,
754 	avro_datum_value_get_string,
755 	avro_datum_value_grab_string,
756 	avro_datum_value_get_enum,
757 	avro_datum_value_get_fixed,
758 	avro_datum_value_grab_fixed,
759 	/* primitive setters */
760 	avro_datum_value_set_boolean,
761 	avro_datum_value_set_bytes,
762 	avro_datum_value_give_bytes,
763 	avro_datum_value_set_double,
764 	avro_datum_value_set_float,
765 	avro_datum_value_set_int,
766 	avro_datum_value_set_long,
767 	avro_datum_value_set_null,
768 	avro_datum_value_set_string,
769 	avro_datum_value_set_string_len,
770 	avro_datum_value_give_string_len,
771 	avro_datum_value_set_enum,
772 	avro_datum_value_set_fixed,
773 	avro_datum_value_give_fixed,
774 	/* compound getters */
775 	avro_datum_value_get_size,
776 	avro_datum_value_get_by_index,
777 	avro_datum_value_get_by_name,
778 	avro_datum_value_get_discriminant,
779 	avro_datum_value_get_current_branch,
780 	/* compound setters */
781 	avro_datum_value_append,
782 	avro_datum_value_add,
783 	avro_datum_value_set_branch
784 };
785