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_private.h"
23 #include "avro/allocation.h"
24 #include "avro/basics.h"
25 #include "avro/data.h"
26 #include "avro/errors.h"
27 #include "avro/refcount.h"
28 #include "avro/resolver.h"
29 #include "avro/schema.h"
30 #include "avro/value.h"
31 #include "st.h"
32
33 #ifndef AVRO_RESOLVER_DEBUG
34 #define AVRO_RESOLVER_DEBUG 0
35 #endif
36
37 #if AVRO_RESOLVER_DEBUG
38 #include <stdio.h>
39 #define DEBUG(...) \
40 do { \
41 fprintf(stderr, __VA_ARGS__); \
42 fprintf(stderr, "\n"); \
43 } while (0)
44 #else
45 #define DEBUG(...) /* don't print messages */
46 #endif
47
48
49 typedef struct avro_resolved_writer avro_resolved_writer_t;
50
51 struct avro_resolved_writer {
52 avro_value_iface_t parent;
53
54 /** The reference count for this interface. */
55 volatile int refcount;
56
57 /** The writer schema. */
58 avro_schema_t wschema;
59
60 /** The reader schema. */
61 avro_schema_t rschema;
62
63 /* If the reader schema is a union, but the writer schema is
64 * not, this field indicates which branch of the reader union
65 * should be selected. */
66 int reader_union_branch;
67
68 /* The size of the value instances for this resolver. */
69 size_t instance_size;
70
71 /* A function to calculate the instance size once the overall
72 * top-level resolver (and all of its children) have been
73 * constructed. */
74 void
75 (*calculate_size)(avro_resolved_writer_t *iface);
76
77 /* A free function for this resolver interface */
78 void
79 (*free_iface)(avro_resolved_writer_t *iface, st_table *freeing);
80
81 /* An initialization function for instances of this resolver. */
82 int
83 (*init)(const avro_resolved_writer_t *iface, void *self);
84
85 /* A finalization function for instances of this resolver. */
86 void
87 (*done)(const avro_resolved_writer_t *iface, void *self);
88
89 /* Clear out any existing wrappers, if any */
90 int
91 (*reset_wrappers)(const avro_resolved_writer_t *iface, void *self);
92 };
93
94 #define avro_resolved_writer_calculate_size(iface) \
95 do { \
96 if ((iface)->calculate_size != NULL) { \
97 (iface)->calculate_size((iface)); \
98 } \
99 } while (0)
100 #define avro_resolved_writer_init(iface, self) \
101 ((iface)->init == NULL? 0: (iface)->init((iface), (self)))
102 #define avro_resolved_writer_done(iface, self) \
103 ((iface)->done == NULL? (void) 0: (iface)->done((iface), (self)))
104 #define avro_resolved_writer_reset_wrappers(iface, self) \
105 ((iface)->reset_wrappers == NULL? 0: \
106 (iface)->reset_wrappers((iface), (self)))
107
108
109 /*
110 * We assume that each instance type in this value contains an an
111 * avro_value_t as its first element, which is the current wrapped
112 * value.
113 */
114
115 void
avro_resolved_writer_set_dest(avro_value_t * resolved,avro_value_t * dest)116 avro_resolved_writer_set_dest(avro_value_t *resolved,
117 avro_value_t *dest)
118 {
119 avro_value_t *self = (avro_value_t *) resolved->self;
120 if (self->self != NULL) {
121 avro_value_decref(self);
122 }
123 avro_value_copy_ref(self, dest);
124 }
125
126 void
avro_resolved_writer_clear_dest(avro_value_t * resolved)127 avro_resolved_writer_clear_dest(avro_value_t *resolved)
128 {
129 avro_value_t *self = (avro_value_t *) resolved->self;
130 if (self->self != NULL) {
131 avro_value_decref(self);
132 }
133 self->iface = NULL;
134 self->self = NULL;
135 }
136
137 int
avro_resolved_writer_new_value(avro_value_iface_t * viface,avro_value_t * value)138 avro_resolved_writer_new_value(avro_value_iface_t *viface,
139 avro_value_t *value)
140 {
141 int rval;
142 avro_resolved_writer_t *iface =
143 container_of(viface, avro_resolved_writer_t, parent);
144 void *self = avro_malloc(iface->instance_size + sizeof(volatile int));
145 if (self == NULL) {
146 value->iface = NULL;
147 value->self = NULL;
148 return ENOMEM;
149 }
150
151 memset(self, 0, iface->instance_size + sizeof(volatile int));
152 volatile int *refcount = (volatile int *) self;
153 self = (char *) self + sizeof(volatile int);
154
155 rval = avro_resolved_writer_init(iface, self);
156 if (rval != 0) {
157 avro_free(self, iface->instance_size + sizeof(volatile int));
158 value->iface = NULL;
159 value->self = NULL;
160 return rval;
161 }
162
163 *refcount = 1;
164 value->iface = avro_value_iface_incref(viface);
165 value->self = self;
166 return 0;
167 }
168
169 static void
avro_resolved_writer_free_value(const avro_value_iface_t * viface,void * vself)170 avro_resolved_writer_free_value(const avro_value_iface_t *viface, void *vself)
171 {
172 avro_resolved_writer_t *iface =
173 container_of(viface, avro_resolved_writer_t, parent);
174 avro_value_t *self = (avro_value_t *) vself;
175
176 avro_resolved_writer_done(iface, vself);
177 if (self->self != NULL) {
178 avro_value_decref(self);
179 }
180
181 vself = (char *) vself - sizeof(volatile int);
182 avro_free(vself, iface->instance_size + sizeof(volatile int));
183 }
184
185 static void
avro_resolved_writer_incref(avro_value_t * value)186 avro_resolved_writer_incref(avro_value_t *value)
187 {
188 /*
189 * This only works if you pass in the top-level value.
190 */
191
192 volatile int *refcount = (volatile int *) ((char *) value->self - sizeof(volatile int));
193 avro_refcount_inc(refcount);
194 }
195
196 static void
avro_resolved_writer_decref(avro_value_t * value)197 avro_resolved_writer_decref(avro_value_t *value)
198 {
199 /*
200 * This only works if you pass in the top-level value.
201 */
202
203 volatile int *refcount = (volatile int *) ((char *) value->self - sizeof(volatile int));
204 if (avro_refcount_dec(refcount)) {
205 avro_resolved_writer_free_value(value->iface, value->self);
206 }
207 }
208
209
210 static avro_value_iface_t *
avro_resolved_writer_incref_iface(avro_value_iface_t * viface)211 avro_resolved_writer_incref_iface(avro_value_iface_t *viface)
212 {
213 avro_resolved_writer_t *iface =
214 container_of(viface, avro_resolved_writer_t, parent);
215 avro_refcount_inc(&iface->refcount);
216 return viface;
217 }
218
219 static void
free_resolver(avro_resolved_writer_t * iface,st_table * freeing)220 free_resolver(avro_resolved_writer_t *iface, st_table *freeing)
221 {
222 /* First check if we've already started freeing this resolver. */
223 if (st_lookup(freeing, (st_data_t) iface, NULL)) {
224 DEBUG("Already freed %p", iface);
225 return;
226 }
227
228 /* Otherwise add this resolver to the freeing set, then free it. */
229 st_insert(freeing, (st_data_t) iface, (st_data_t) NULL);
230 DEBUG("Freeing resolver %p (%s->%s)", iface,
231 avro_schema_type_name(iface->wschema),
232 avro_schema_type_name(iface->rschema));
233
234 iface->free_iface(iface, freeing);
235 }
236
237 static void
avro_resolved_writer_calculate_size_(avro_resolved_writer_t * iface)238 avro_resolved_writer_calculate_size_(avro_resolved_writer_t *iface)
239 {
240 /* Only calculate the size for any resolver once */
241 iface->calculate_size = NULL;
242
243 DEBUG("Calculating size for %s->%s",
244 avro_schema_type_name((iface)->wschema),
245 avro_schema_type_name((iface)->rschema));
246 iface->instance_size = sizeof(avro_value_t);
247 }
248
249 static void
avro_resolved_writer_free_iface(avro_resolved_writer_t * iface,st_table * freeing)250 avro_resolved_writer_free_iface(avro_resolved_writer_t *iface, st_table *freeing)
251 {
252 AVRO_UNUSED(freeing);
253 avro_schema_decref(iface->wschema);
254 avro_schema_decref(iface->rschema);
255 avro_freet(avro_resolved_writer_t, iface);
256 }
257
258 static void
avro_resolved_writer_decref_iface(avro_value_iface_t * viface)259 avro_resolved_writer_decref_iface(avro_value_iface_t *viface)
260 {
261 avro_resolved_writer_t *iface =
262 container_of(viface, avro_resolved_writer_t, parent);
263 DEBUG("Decref resolver %p (before=%d)", iface, iface->refcount);
264 if (avro_refcount_dec(&iface->refcount)) {
265 avro_resolved_writer_t *iface =
266 container_of(viface, avro_resolved_writer_t, parent);
267
268 st_table *freeing = st_init_numtable();
269 free_resolver(iface, freeing);
270 st_free_table(freeing);
271 }
272 }
273
274
275 static int
avro_resolved_writer_reset(const avro_value_iface_t * viface,void * vself)276 avro_resolved_writer_reset(const avro_value_iface_t *viface, void *vself)
277 {
278 /*
279 * To reset a wrapped value, we first clear out any wrappers,
280 * and then have the wrapped value reset itself.
281 */
282
283 int rval;
284 avro_resolved_writer_t *iface =
285 container_of(viface, avro_resolved_writer_t, parent);
286 avro_value_t *self = (avro_value_t *) vself;
287 check(rval, avro_resolved_writer_reset_wrappers(iface, vself));
288 return avro_value_reset(self);
289 }
290
291 static avro_type_t
avro_resolved_writer_get_type(const avro_value_iface_t * viface,const void * vself)292 avro_resolved_writer_get_type(const avro_value_iface_t *viface, const void *vself)
293 {
294 AVRO_UNUSED(vself);
295 const avro_resolved_writer_t *iface =
296 container_of(viface, avro_resolved_writer_t, parent);
297 return avro_typeof(iface->wschema);
298 }
299
300 static avro_schema_t
avro_resolved_writer_get_schema(const avro_value_iface_t * viface,const void * vself)301 avro_resolved_writer_get_schema(const avro_value_iface_t *viface, const void *vself)
302 {
303 AVRO_UNUSED(vself);
304 avro_resolved_writer_t *iface =
305 container_of(viface, avro_resolved_writer_t, parent);
306 return iface->wschema;
307 }
308
309
310 static avro_resolved_writer_t *
avro_resolved_writer_create(avro_schema_t wschema,avro_schema_t rschema)311 avro_resolved_writer_create(avro_schema_t wschema, avro_schema_t rschema)
312 {
313 avro_resolved_writer_t *self = (avro_resolved_writer_t *) avro_new(avro_resolved_writer_t);
314 memset(self, 0, sizeof(avro_resolved_writer_t));
315
316 self->parent.incref_iface = avro_resolved_writer_incref_iface;
317 self->parent.decref_iface = avro_resolved_writer_decref_iface;
318 self->parent.incref = avro_resolved_writer_incref;
319 self->parent.decref = avro_resolved_writer_decref;
320 self->parent.reset = avro_resolved_writer_reset;
321 self->parent.get_type = avro_resolved_writer_get_type;
322 self->parent.get_schema = avro_resolved_writer_get_schema;
323
324 self->refcount = 1;
325 self->wschema = avro_schema_incref(wschema);
326 self->rschema = avro_schema_incref(rschema);
327 self->reader_union_branch = -1;
328 self->calculate_size = avro_resolved_writer_calculate_size_;
329 self->free_iface = avro_resolved_writer_free_iface;
330 self->reset_wrappers = NULL;
331 return self;
332 }
333
334 static inline int
avro_resolved_writer_get_real_dest(const avro_resolved_writer_t * iface,const avro_value_t * dest,avro_value_t * real_dest)335 avro_resolved_writer_get_real_dest(const avro_resolved_writer_t *iface,
336 const avro_value_t *dest, avro_value_t *real_dest)
337 {
338 if (iface->reader_union_branch < 0) {
339 /*
340 * The reader schema isn't a union, so use the dest
341 * field as-is.
342 */
343
344 *real_dest = *dest;
345 return 0;
346 }
347
348 DEBUG("Retrieving union branch %d for %s value",
349 iface->reader_union_branch,
350 avro_schema_type_name(iface->wschema));
351
352 return avro_value_set_branch(dest, iface->reader_union_branch, real_dest);
353 }
354
355
356 #define skip_links(schema) \
357 while (is_avro_link(schema)) { \
358 schema = avro_schema_link_target(schema); \
359 }
360
361
362 /*-----------------------------------------------------------------------
363 * Memoized resolvers
364 */
365
366 typedef struct avro_resolved_link_writer avro_resolved_link_writer_t;
367
368 typedef struct memoize_state_t {
369 avro_memoize_t mem;
370 avro_resolved_link_writer_t *links;
371 } memoize_state_t;
372
373 static avro_resolved_writer_t *
374 avro_resolved_writer_new_memoized(memoize_state_t *state,
375 avro_schema_t wschema, avro_schema_t rschema);
376
377
378 /*-----------------------------------------------------------------------
379 * Reader unions
380 */
381
382 /*
383 * For each Avro type, we have to check whether the reader schema on its
384 * own is compatible, and also whether the reader is a union that
385 * contains a compatible type. The macros in this section help us
386 * perform both of these checks with less code.
387 */
388
389
390 /**
391 * A helper macro that handles the case where neither writer nor reader
392 * are unions. Uses @ref check_func to see if the two schemas are
393 * compatible.
394 */
395
396 #define check_non_union(saved, wschema, rschema, check_func) \
397 do { \
398 avro_resolved_writer_t *self = NULL; \
399 int rc = check_func(saved, &self, wschema, rschema, \
400 rschema); \
401 if (self) { \
402 DEBUG("Non-union schemas %s (writer) " \
403 "and %s (reader) match", \
404 avro_schema_type_name(wschema), \
405 avro_schema_type_name(rschema)); \
406 \
407 self->reader_union_branch = -1; \
408 return self; \
409 } \
410 \
411 if (rc) { \
412 return NULL; \
413 } \
414 } while (0)
415
416
417 /**
418 * Helper macro that handles the case where the reader is a union, and
419 * the writer is not. Checks each branch of the reader union schema,
420 * looking for the first branch that is compatible with the writer
421 * schema. The @ref check_func argument should be a function that can
422 * check the compatiblity of each branch schema.
423 */
424
425 #define check_reader_union(saved, wschema, rschema, check_func) \
426 do { \
427 if (!is_avro_union(rschema)) { \
428 break; \
429 } \
430 \
431 DEBUG("Checking reader union schema"); \
432 size_t num_branches = avro_schema_union_size(rschema); \
433 unsigned int i; \
434 \
435 for (i = 0; i < num_branches; i++) { \
436 avro_schema_t branch_schema = \
437 avro_schema_union_branch(rschema, i); \
438 skip_links(branch_schema); \
439 \
440 DEBUG("Trying branch %u %s%s%s->%s", i, \
441 is_avro_link(wschema)? "[": "", \
442 avro_schema_type_name(wschema), \
443 is_avro_link(wschema)? "]": "", \
444 avro_schema_type_name(branch_schema)); \
445 \
446 avro_resolved_writer_t *self = NULL; \
447 int rc = check_func(saved, &self, \
448 wschema, branch_schema, rschema); \
449 if (self) { \
450 DEBUG("Reader union branch %d (%s) " \
451 "and writer %s match", \
452 i, avro_schema_type_name(branch_schema), \
453 avro_schema_type_name(wschema)); \
454 self->reader_union_branch = i; \
455 return self; \
456 } else { \
457 DEBUG("Reader union branch %d (%s) " \
458 "doesn't match", \
459 i, avro_schema_type_name(branch_schema)); \
460 } \
461 \
462 if (rc) { \
463 return NULL; \
464 } \
465 } \
466 \
467 DEBUG("No reader union branches match"); \
468 } while (0)
469
470 /**
471 * A helper macro that wraps together check_non_union and
472 * check_reader_union for a simple (non-union) writer schema type.
473 */
474
475 #define check_simple_writer(saved, wschema, rschema, type_name) \
476 do { \
477 check_non_union(saved, wschema, rschema, try_##type_name); \
478 check_reader_union(saved, wschema, rschema, try_##type_name); \
479 DEBUG("Writer %s doesn't match reader %s", \
480 avro_schema_type_name(wschema), \
481 avro_schema_type_name(rschema)); \
482 avro_set_error("Cannot store " #type_name " into %s", \
483 avro_schema_type_name(rschema)); \
484 return NULL; \
485 } while (0)
486
487
488 /*-----------------------------------------------------------------------
489 * Recursive schemas
490 */
491
492 /*
493 * Recursive schemas are handled specially; the value implementation for
494 * an AVRO_LINK schema is simply a wrapper around the value
495 * implementation for the link's target schema. The value methods all
496 * delegate to the wrapped implementation.
497 */
498
499 struct avro_resolved_link_writer {
500 avro_resolved_writer_t parent;
501
502 /**
503 * A pointer to the “next” link resolver that we've had to
504 * create. We use this as we're creating the overall top-level
505 * resolver to keep track of which ones we have to fix up
506 * afterwards.
507 */
508 avro_resolved_link_writer_t *next;
509
510 /** The target's implementation. */
511 avro_resolved_writer_t *target_resolver;
512 };
513
514 typedef struct avro_resolved_link_value {
515 avro_value_t wrapped;
516 avro_value_t target;
517 } avro_resolved_link_value_t;
518
519 static void
avro_resolved_link_writer_calculate_size(avro_resolved_writer_t * iface)520 avro_resolved_link_writer_calculate_size(avro_resolved_writer_t *iface)
521 {
522 /* Only calculate the size for any resolver once */
523 iface->calculate_size = NULL;
524
525 DEBUG("Calculating size for [%s]->%s",
526 avro_schema_type_name((iface)->wschema),
527 avro_schema_type_name((iface)->rschema));
528 iface->instance_size = sizeof(avro_resolved_link_value_t);
529 }
530
531 static void
avro_resolved_link_writer_free_iface(avro_resolved_writer_t * iface,st_table * freeing)532 avro_resolved_link_writer_free_iface(avro_resolved_writer_t *iface, st_table *freeing)
533 {
534 avro_resolved_link_writer_t *liface =
535 container_of(iface, avro_resolved_link_writer_t, parent);
536 if (liface->target_resolver != NULL) {
537 free_resolver(liface->target_resolver, freeing);
538 }
539 avro_schema_decref(iface->wschema);
540 avro_schema_decref(iface->rschema);
541 avro_freet(avro_resolved_link_writer_t, iface);
542 }
543
544 static int
avro_resolved_link_writer_init(const avro_resolved_writer_t * iface,void * vself)545 avro_resolved_link_writer_init(const avro_resolved_writer_t *iface, void *vself)
546 {
547 int rval;
548 const avro_resolved_link_writer_t *liface =
549 container_of(iface, avro_resolved_link_writer_t, parent);
550 avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
551 size_t target_instance_size = liface->target_resolver->instance_size;
552
553 self->target.iface = &liface->target_resolver->parent;
554 self->target.self = avro_malloc(target_instance_size);
555 if (self->target.self == NULL) {
556 return ENOMEM;
557 }
558 DEBUG("Allocated <%p:%" PRIsz "> for link", self->target.self, target_instance_size);
559
560 avro_value_t *target_vself = (avro_value_t *) self->target.self;
561 *target_vself = self->wrapped;
562
563 rval = avro_resolved_writer_init(liface->target_resolver, self->target.self);
564 if (rval != 0) {
565 avro_free(self->target.self, target_instance_size);
566 }
567 return rval;
568 }
569
570 static void
avro_resolved_link_writer_done(const avro_resolved_writer_t * iface,void * vself)571 avro_resolved_link_writer_done(const avro_resolved_writer_t *iface, void *vself)
572 {
573 const avro_resolved_link_writer_t *liface =
574 container_of(iface, avro_resolved_link_writer_t, parent);
575 avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
576 size_t target_instance_size = liface->target_resolver->instance_size;
577 DEBUG("Freeing <%p:%" PRIsz "> for link", self->target.self, target_instance_size);
578 avro_resolved_writer_done(liface->target_resolver, self->target.self);
579 avro_free(self->target.self, target_instance_size);
580 self->target.iface = NULL;
581 self->target.self = NULL;
582 }
583
584 static int
avro_resolved_link_writer_reset(const avro_resolved_writer_t * iface,void * vself)585 avro_resolved_link_writer_reset(const avro_resolved_writer_t *iface, void *vself)
586 {
587 const avro_resolved_link_writer_t *liface =
588 container_of(iface, avro_resolved_link_writer_t, parent);
589 avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
590 return avro_resolved_writer_reset_wrappers
591 (liface->target_resolver, self->target.self);
592 }
593
594 static avro_type_t
avro_resolved_link_writer_get_type(const avro_value_iface_t * iface,const void * vself)595 avro_resolved_link_writer_get_type(const avro_value_iface_t *iface, const void *vself)
596 {
597 AVRO_UNUSED(iface);
598 const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
599 avro_value_t *target_vself = (avro_value_t *) self->target.self;
600 *target_vself = self->wrapped;
601 return avro_value_get_type(&self->target);
602 }
603
604 static avro_schema_t
avro_resolved_link_writer_get_schema(const avro_value_iface_t * iface,const void * vself)605 avro_resolved_link_writer_get_schema(const avro_value_iface_t *iface, const void *vself)
606 {
607 AVRO_UNUSED(iface);
608 const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
609 avro_value_t *target_vself = (avro_value_t *) self->target.self;
610 *target_vself = self->wrapped;
611 return avro_value_get_schema(&self->target);
612 }
613
614 static int
avro_resolved_link_writer_get_boolean(const avro_value_iface_t * iface,const void * vself,int * out)615 avro_resolved_link_writer_get_boolean(const avro_value_iface_t *iface,
616 const void *vself, int *out)
617 {
618 AVRO_UNUSED(iface);
619 const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
620 avro_value_t *target_vself = (avro_value_t *) self->target.self;
621 *target_vself = self->wrapped;
622 return avro_value_get_boolean(&self->target, out);
623 }
624
625 static int
avro_resolved_link_writer_get_bytes(const avro_value_iface_t * iface,const void * vself,const void ** buf,size_t * size)626 avro_resolved_link_writer_get_bytes(const avro_value_iface_t *iface,
627 const void *vself, const void **buf, size_t *size)
628 {
629 AVRO_UNUSED(iface);
630 const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
631 avro_value_t *target_vself = (avro_value_t *) self->target.self;
632 *target_vself = self->wrapped;
633 return avro_value_get_bytes(&self->target, buf, size);
634 }
635
636 static int
avro_resolved_link_writer_grab_bytes(const avro_value_iface_t * iface,const void * vself,avro_wrapped_buffer_t * dest)637 avro_resolved_link_writer_grab_bytes(const avro_value_iface_t *iface,
638 const void *vself, avro_wrapped_buffer_t *dest)
639 {
640 AVRO_UNUSED(iface);
641 const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
642 avro_value_t *target_vself = (avro_value_t *) self->target.self;
643 *target_vself = self->wrapped;
644 return avro_value_grab_bytes(&self->target, dest);
645 }
646
647 static int
avro_resolved_link_writer_get_double(const avro_value_iface_t * iface,const void * vself,double * out)648 avro_resolved_link_writer_get_double(const avro_value_iface_t *iface,
649 const void *vself, double *out)
650 {
651 AVRO_UNUSED(iface);
652 const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
653 avro_value_t *target_vself = (avro_value_t *) self->target.self;
654 *target_vself = self->wrapped;
655 return avro_value_get_double(&self->target, out);
656 }
657
658 static int
avro_resolved_link_writer_get_float(const avro_value_iface_t * iface,const void * vself,float * out)659 avro_resolved_link_writer_get_float(const avro_value_iface_t *iface,
660 const void *vself, float *out)
661 {
662 AVRO_UNUSED(iface);
663 const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
664 avro_value_t *target_vself = (avro_value_t *) self->target.self;
665 *target_vself = self->wrapped;
666 return avro_value_get_float(&self->target, out);
667 }
668
669 static int
avro_resolved_link_writer_get_int(const avro_value_iface_t * iface,const void * vself,int32_t * out)670 avro_resolved_link_writer_get_int(const avro_value_iface_t *iface,
671 const void *vself, int32_t *out)
672 {
673 AVRO_UNUSED(iface);
674 const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
675 avro_value_t *target_vself = (avro_value_t *) self->target.self;
676 *target_vself = self->wrapped;
677 return avro_value_get_int(&self->target, out);
678 }
679
680 static int
avro_resolved_link_writer_get_long(const avro_value_iface_t * iface,const void * vself,int64_t * out)681 avro_resolved_link_writer_get_long(const avro_value_iface_t *iface,
682 const void *vself, int64_t *out)
683 {
684 AVRO_UNUSED(iface);
685 const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
686 avro_value_t *target_vself = (avro_value_t *) self->target.self;
687 *target_vself = self->wrapped;
688 return avro_value_get_long(&self->target, out);
689 }
690
691 static int
avro_resolved_link_writer_get_null(const avro_value_iface_t * iface,const void * vself)692 avro_resolved_link_writer_get_null(const avro_value_iface_t *iface, const void *vself)
693 {
694 AVRO_UNUSED(iface);
695 const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
696 avro_value_t *target_vself = (avro_value_t *) self->target.self;
697 *target_vself = self->wrapped;
698 return avro_value_get_null(&self->target);
699 }
700
701 static int
avro_resolved_link_writer_get_string(const avro_value_iface_t * iface,const void * vself,const char ** str,size_t * size)702 avro_resolved_link_writer_get_string(const avro_value_iface_t *iface,
703 const void *vself, const char **str, size_t *size)
704 {
705 AVRO_UNUSED(iface);
706 const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
707 avro_value_t *target_vself = (avro_value_t *) self->target.self;
708 *target_vself = self->wrapped;
709 return avro_value_get_string(&self->target, str, size);
710 }
711
712 static int
avro_resolved_link_writer_grab_string(const avro_value_iface_t * iface,const void * vself,avro_wrapped_buffer_t * dest)713 avro_resolved_link_writer_grab_string(const avro_value_iface_t *iface,
714 const void *vself, avro_wrapped_buffer_t *dest)
715 {
716 AVRO_UNUSED(iface);
717 const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
718 avro_value_t *target_vself = (avro_value_t *) self->target.self;
719 *target_vself = self->wrapped;
720 return avro_value_grab_string(&self->target, dest);
721 }
722
723 static int
avro_resolved_link_writer_get_enum(const avro_value_iface_t * iface,const void * vself,int * out)724 avro_resolved_link_writer_get_enum(const avro_value_iface_t *iface,
725 const void *vself, int *out)
726 {
727 AVRO_UNUSED(iface);
728 const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
729 avro_value_t *target_vself = (avro_value_t *) self->target.self;
730 *target_vself = self->wrapped;
731 return avro_value_get_enum(&self->target, out);
732 }
733
734 static int
avro_resolved_link_writer_get_fixed(const avro_value_iface_t * iface,const void * vself,const void ** buf,size_t * size)735 avro_resolved_link_writer_get_fixed(const avro_value_iface_t *iface,
736 const void *vself, const void **buf, size_t *size)
737 {
738 AVRO_UNUSED(iface);
739 const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
740 avro_value_t *target_vself = (avro_value_t *) self->target.self;
741 *target_vself = self->wrapped;
742 return avro_value_get_fixed(&self->target, buf, size);
743 }
744
745 static int
avro_resolved_link_writer_grab_fixed(const avro_value_iface_t * iface,const void * vself,avro_wrapped_buffer_t * dest)746 avro_resolved_link_writer_grab_fixed(const avro_value_iface_t *iface,
747 const void *vself, avro_wrapped_buffer_t *dest)
748 {
749 AVRO_UNUSED(iface);
750 const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
751 avro_value_t *target_vself = (avro_value_t *) self->target.self;
752 *target_vself = self->wrapped;
753 return avro_value_grab_fixed(&self->target, dest);
754 }
755
756 static int
avro_resolved_link_writer_set_boolean(const avro_value_iface_t * iface,void * vself,int val)757 avro_resolved_link_writer_set_boolean(const avro_value_iface_t *iface,
758 void *vself, int val)
759 {
760 AVRO_UNUSED(iface);
761 avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
762 avro_value_t *target_vself = (avro_value_t *) self->target.self;
763 *target_vself = self->wrapped;
764 return avro_value_set_boolean(&self->target, val);
765 }
766
767 static int
avro_resolved_link_writer_set_bytes(const avro_value_iface_t * iface,void * vself,void * buf,size_t size)768 avro_resolved_link_writer_set_bytes(const avro_value_iface_t *iface,
769 void *vself, void *buf, size_t size)
770 {
771 AVRO_UNUSED(iface);
772 avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
773 avro_value_t *target_vself = (avro_value_t *) self->target.self;
774 *target_vself = self->wrapped;
775 return avro_value_set_bytes(&self->target, buf, size);
776 }
777
778 static int
avro_resolved_link_writer_give_bytes(const avro_value_iface_t * iface,void * vself,avro_wrapped_buffer_t * buf)779 avro_resolved_link_writer_give_bytes(const avro_value_iface_t *iface,
780 void *vself, avro_wrapped_buffer_t *buf)
781 {
782 AVRO_UNUSED(iface);
783 avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
784 avro_value_t *target_vself = (avro_value_t *) self->target.self;
785 *target_vself = self->wrapped;
786 return avro_value_give_bytes(&self->target, buf);
787 }
788
789 static int
avro_resolved_link_writer_set_double(const avro_value_iface_t * iface,void * vself,double val)790 avro_resolved_link_writer_set_double(const avro_value_iface_t *iface,
791 void *vself, double val)
792 {
793 AVRO_UNUSED(iface);
794 avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
795 avro_value_t *target_vself = (avro_value_t *) self->target.self;
796 *target_vself = self->wrapped;
797 return avro_value_set_double(&self->target, val);
798 }
799
800 static int
avro_resolved_link_writer_set_float(const avro_value_iface_t * iface,void * vself,float val)801 avro_resolved_link_writer_set_float(const avro_value_iface_t *iface,
802 void *vself, float val)
803 {
804 AVRO_UNUSED(iface);
805 avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
806 avro_value_t *target_vself = (avro_value_t *) self->target.self;
807 *target_vself = self->wrapped;
808 return avro_value_set_float(&self->target, val);
809 }
810
811 static int
avro_resolved_link_writer_set_int(const avro_value_iface_t * iface,void * vself,int32_t val)812 avro_resolved_link_writer_set_int(const avro_value_iface_t *iface,
813 void *vself, int32_t val)
814 {
815 AVRO_UNUSED(iface);
816 avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
817 avro_value_t *target_vself = (avro_value_t *) self->target.self;
818 *target_vself = self->wrapped;
819 return avro_value_set_int(&self->target, val);
820 }
821
822 static int
avro_resolved_link_writer_set_long(const avro_value_iface_t * iface,void * vself,int64_t val)823 avro_resolved_link_writer_set_long(const avro_value_iface_t *iface,
824 void *vself, int64_t val)
825 {
826 AVRO_UNUSED(iface);
827 avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
828 avro_value_t *target_vself = (avro_value_t *) self->target.self;
829 *target_vself = self->wrapped;
830 return avro_value_set_long(&self->target, val);
831 }
832
833 static int
avro_resolved_link_writer_set_null(const avro_value_iface_t * iface,void * vself)834 avro_resolved_link_writer_set_null(const avro_value_iface_t *iface, void *vself)
835 {
836 AVRO_UNUSED(iface);
837 avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
838 avro_value_t *target_vself = (avro_value_t *) self->target.self;
839 *target_vself = self->wrapped;
840 return avro_value_set_null(&self->target);
841 }
842
843 static int
avro_resolved_link_writer_set_string(const avro_value_iface_t * iface,void * vself,const char * str)844 avro_resolved_link_writer_set_string(const avro_value_iface_t *iface,
845 void *vself, const char *str)
846 {
847 AVRO_UNUSED(iface);
848 avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
849 avro_value_t *target_vself = (avro_value_t *) self->target.self;
850 *target_vself = self->wrapped;
851 return avro_value_set_string(&self->target, str);
852 }
853
854 static int
avro_resolved_link_writer_set_string_len(const avro_value_iface_t * iface,void * vself,const char * str,size_t size)855 avro_resolved_link_writer_set_string_len(const avro_value_iface_t *iface,
856 void *vself, const char *str, size_t size)
857 {
858 AVRO_UNUSED(iface);
859 avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
860 avro_value_t *target_vself = (avro_value_t *) self->target.self;
861 *target_vself = self->wrapped;
862 return avro_value_set_string_len(&self->target, str, size);
863 }
864
865 static int
avro_resolved_link_writer_give_string_len(const avro_value_iface_t * iface,void * vself,avro_wrapped_buffer_t * buf)866 avro_resolved_link_writer_give_string_len(const avro_value_iface_t *iface,
867 void *vself, avro_wrapped_buffer_t *buf)
868 {
869 AVRO_UNUSED(iface);
870 avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
871 avro_value_t *target_vself = (avro_value_t *) self->target.self;
872 *target_vself = self->wrapped;
873 return avro_value_give_string_len(&self->target, buf);
874 }
875
876 static int
avro_resolved_link_writer_set_enum(const avro_value_iface_t * iface,void * vself,int val)877 avro_resolved_link_writer_set_enum(const avro_value_iface_t *iface,
878 void *vself, int val)
879 {
880 AVRO_UNUSED(iface);
881 avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
882 avro_value_t *target_vself = (avro_value_t *) self->target.self;
883 *target_vself = self->wrapped;
884 return avro_value_set_enum(&self->target, val);
885 }
886
887 static int
avro_resolved_link_writer_set_fixed(const avro_value_iface_t * iface,void * vself,void * buf,size_t size)888 avro_resolved_link_writer_set_fixed(const avro_value_iface_t *iface,
889 void *vself, void *buf, size_t size)
890 {
891 AVRO_UNUSED(iface);
892 avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
893 avro_value_t *target_vself = (avro_value_t *) self->target.self;
894 *target_vself = self->wrapped;
895 return avro_value_set_fixed(&self->target, buf, size);
896 }
897
898 static int
avro_resolved_link_writer_give_fixed(const avro_value_iface_t * iface,void * vself,avro_wrapped_buffer_t * buf)899 avro_resolved_link_writer_give_fixed(const avro_value_iface_t *iface,
900 void *vself, avro_wrapped_buffer_t *buf)
901 {
902 AVRO_UNUSED(iface);
903 avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
904 avro_value_t *target_vself = (avro_value_t *) self->target.self;
905 *target_vself = self->wrapped;
906 return avro_value_give_fixed(&self->target, buf);
907 }
908
909 static int
avro_resolved_link_writer_get_size(const avro_value_iface_t * iface,const void * vself,size_t * size)910 avro_resolved_link_writer_get_size(const avro_value_iface_t *iface,
911 const void *vself, size_t *size)
912 {
913 AVRO_UNUSED(iface);
914 const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
915 avro_value_t *target_vself = (avro_value_t *) self->target.self;
916 *target_vself = self->wrapped;
917 return avro_value_get_size(&self->target, size);
918 }
919
920 static int
avro_resolved_link_writer_get_by_index(const avro_value_iface_t * iface,const void * vself,size_t index,avro_value_t * child,const char ** name)921 avro_resolved_link_writer_get_by_index(const avro_value_iface_t *iface,
922 const void *vself, size_t index,
923 avro_value_t *child, const char **name)
924 {
925 AVRO_UNUSED(iface);
926 const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
927 avro_value_t *target_vself = (avro_value_t *) self->target.self;
928 *target_vself = self->wrapped;
929 return avro_value_get_by_index(&self->target, index, child, name);
930 }
931
932 static int
avro_resolved_link_writer_get_by_name(const avro_value_iface_t * iface,const void * vself,const char * name,avro_value_t * child,size_t * index)933 avro_resolved_link_writer_get_by_name(const avro_value_iface_t *iface,
934 const void *vself, const char *name,
935 avro_value_t *child, size_t *index)
936 {
937 AVRO_UNUSED(iface);
938 const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
939 avro_value_t *target_vself = (avro_value_t *) self->target.self;
940 *target_vself = self->wrapped;
941 return avro_value_get_by_name(&self->target, name, child, index);
942 }
943
944 static int
avro_resolved_link_writer_get_discriminant(const avro_value_iface_t * iface,const void * vself,int * out)945 avro_resolved_link_writer_get_discriminant(const avro_value_iface_t *iface,
946 const void *vself, int *out)
947 {
948 AVRO_UNUSED(iface);
949 const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
950 avro_value_t *target_vself = (avro_value_t *) self->target.self;
951 *target_vself = self->wrapped;
952 return avro_value_get_discriminant(&self->target, out);
953 }
954
955 static int
avro_resolved_link_writer_get_current_branch(const avro_value_iface_t * iface,const void * vself,avro_value_t * branch)956 avro_resolved_link_writer_get_current_branch(const avro_value_iface_t *iface,
957 const void *vself, avro_value_t *branch)
958 {
959 AVRO_UNUSED(iface);
960 const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
961 avro_value_t *target_vself = (avro_value_t *) self->target.self;
962 *target_vself = self->wrapped;
963 return avro_value_get_current_branch(&self->target, branch);
964 }
965
966 static int
avro_resolved_link_writer_append(const avro_value_iface_t * iface,void * vself,avro_value_t * child_out,size_t * new_index)967 avro_resolved_link_writer_append(const avro_value_iface_t *iface,
968 void *vself, avro_value_t *child_out,
969 size_t *new_index)
970 {
971 AVRO_UNUSED(iface);
972 avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
973 avro_value_t *target_vself = (avro_value_t *) self->target.self;
974 *target_vself = self->wrapped;
975 return avro_value_append(&self->target, child_out, new_index);
976 }
977
978 static int
avro_resolved_link_writer_add(const avro_value_iface_t * iface,void * vself,const char * key,avro_value_t * child,size_t * index,int * is_new)979 avro_resolved_link_writer_add(const avro_value_iface_t *iface,
980 void *vself, const char *key,
981 avro_value_t *child, size_t *index, int *is_new)
982 {
983 AVRO_UNUSED(iface);
984 avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
985 avro_value_t *target_vself = (avro_value_t *) self->target.self;
986 *target_vself = self->wrapped;
987 return avro_value_add(&self->target, key, child, index, is_new);
988 }
989
990 static int
avro_resolved_link_writer_set_branch(const avro_value_iface_t * iface,void * vself,int discriminant,avro_value_t * branch)991 avro_resolved_link_writer_set_branch(const avro_value_iface_t *iface,
992 void *vself, int discriminant,
993 avro_value_t *branch)
994 {
995 AVRO_UNUSED(iface);
996 avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
997 avro_value_t *target_vself = (avro_value_t *) self->target.self;
998 *target_vself = self->wrapped;
999 return avro_value_set_branch(&self->target, discriminant, branch);
1000 }
1001
1002 static avro_resolved_link_writer_t *
avro_resolved_link_writer_create(avro_schema_t wschema,avro_schema_t rschema)1003 avro_resolved_link_writer_create(avro_schema_t wschema, avro_schema_t rschema)
1004 {
1005 avro_resolved_writer_t *self = (avro_resolved_writer_t *) avro_new(avro_resolved_link_writer_t);
1006 memset(self, 0, sizeof(avro_resolved_link_writer_t));
1007
1008 self->parent.incref_iface = avro_resolved_writer_incref_iface;
1009 self->parent.decref_iface = avro_resolved_writer_decref_iface;
1010 self->parent.incref = avro_resolved_writer_incref;
1011 self->parent.decref = avro_resolved_writer_decref;
1012 self->parent.reset = avro_resolved_writer_reset;
1013 self->parent.get_type = avro_resolved_link_writer_get_type;
1014 self->parent.get_schema = avro_resolved_link_writer_get_schema;
1015 self->parent.get_size = avro_resolved_link_writer_get_size;
1016 self->parent.get_by_index = avro_resolved_link_writer_get_by_index;
1017 self->parent.get_by_name = avro_resolved_link_writer_get_by_name;
1018
1019 self->refcount = 1;
1020 self->wschema = avro_schema_incref(wschema);
1021 self->rschema = avro_schema_incref(rschema);
1022 self->reader_union_branch = -1;
1023 self->calculate_size = avro_resolved_link_writer_calculate_size;
1024 self->free_iface = avro_resolved_link_writer_free_iface;
1025 self->init = avro_resolved_link_writer_init;
1026 self->done = avro_resolved_link_writer_done;
1027 self->reset_wrappers = avro_resolved_link_writer_reset;
1028
1029 self->parent.get_boolean = avro_resolved_link_writer_get_boolean;
1030 self->parent.get_bytes = avro_resolved_link_writer_get_bytes;
1031 self->parent.grab_bytes = avro_resolved_link_writer_grab_bytes;
1032 self->parent.get_double = avro_resolved_link_writer_get_double;
1033 self->parent.get_float = avro_resolved_link_writer_get_float;
1034 self->parent.get_int = avro_resolved_link_writer_get_int;
1035 self->parent.get_long = avro_resolved_link_writer_get_long;
1036 self->parent.get_null = avro_resolved_link_writer_get_null;
1037 self->parent.get_string = avro_resolved_link_writer_get_string;
1038 self->parent.grab_string = avro_resolved_link_writer_grab_string;
1039 self->parent.get_enum = avro_resolved_link_writer_get_enum;
1040 self->parent.get_fixed = avro_resolved_link_writer_get_fixed;
1041 self->parent.grab_fixed = avro_resolved_link_writer_grab_fixed;
1042
1043 self->parent.set_boolean = avro_resolved_link_writer_set_boolean;
1044 self->parent.set_bytes = avro_resolved_link_writer_set_bytes;
1045 self->parent.give_bytes = avro_resolved_link_writer_give_bytes;
1046 self->parent.set_double = avro_resolved_link_writer_set_double;
1047 self->parent.set_float = avro_resolved_link_writer_set_float;
1048 self->parent.set_int = avro_resolved_link_writer_set_int;
1049 self->parent.set_long = avro_resolved_link_writer_set_long;
1050 self->parent.set_null = avro_resolved_link_writer_set_null;
1051 self->parent.set_string = avro_resolved_link_writer_set_string;
1052 self->parent.set_string_len = avro_resolved_link_writer_set_string_len;
1053 self->parent.give_string_len = avro_resolved_link_writer_give_string_len;
1054 self->parent.set_enum = avro_resolved_link_writer_set_enum;
1055 self->parent.set_fixed = avro_resolved_link_writer_set_fixed;
1056 self->parent.give_fixed = avro_resolved_link_writer_give_fixed;
1057
1058 self->parent.get_size = avro_resolved_link_writer_get_size;
1059 self->parent.get_by_index = avro_resolved_link_writer_get_by_index;
1060 self->parent.get_by_name = avro_resolved_link_writer_get_by_name;
1061 self->parent.get_discriminant = avro_resolved_link_writer_get_discriminant;
1062 self->parent.get_current_branch = avro_resolved_link_writer_get_current_branch;
1063
1064 self->parent.append = avro_resolved_link_writer_append;
1065 self->parent.add = avro_resolved_link_writer_add;
1066 self->parent.set_branch = avro_resolved_link_writer_set_branch;
1067
1068 return container_of(self, avro_resolved_link_writer_t, parent);
1069 }
1070
1071 static int
try_link(memoize_state_t * state,avro_resolved_writer_t ** self,avro_schema_t wschema,avro_schema_t rschema,avro_schema_t root_rschema)1072 try_link(memoize_state_t *state, avro_resolved_writer_t **self,
1073 avro_schema_t wschema, avro_schema_t rschema,
1074 avro_schema_t root_rschema)
1075 {
1076 AVRO_UNUSED(rschema);
1077
1078 /*
1079 * For link schemas, we create a special value implementation
1080 * that allocates space for its wrapped value at runtime. This
1081 * lets us handle recursive types without having to instantiate
1082 * in infinite-size value.
1083 */
1084
1085 avro_schema_t wtarget = avro_schema_link_target(wschema);
1086 avro_resolved_link_writer_t *lself =
1087 avro_resolved_link_writer_create(wtarget, root_rschema);
1088 avro_memoize_set(&state->mem, wschema, root_rschema, lself);
1089
1090 avro_resolved_writer_t *target_resolver =
1091 avro_resolved_writer_new_memoized(state, wtarget, rschema);
1092 if (target_resolver == NULL) {
1093 avro_memoize_delete(&state->mem, wschema, root_rschema);
1094 avro_value_iface_decref(&lself->parent.parent);
1095 avro_prefix_error("Link target isn't compatible: ");
1096 DEBUG("%s", avro_strerror());
1097 return EINVAL;
1098 }
1099
1100 lself->target_resolver = target_resolver;
1101 lself->next = state->links;
1102 state->links = lself;
1103
1104 *self = &lself->parent;
1105 return 0;
1106 }
1107
1108
1109 /*-----------------------------------------------------------------------
1110 * boolean
1111 */
1112
1113 static int
avro_resolved_writer_set_boolean(const avro_value_iface_t * viface,void * vself,int val)1114 avro_resolved_writer_set_boolean(const avro_value_iface_t *viface,
1115 void *vself, int val)
1116 {
1117 int rval;
1118 const avro_resolved_writer_t *iface =
1119 container_of(viface, avro_resolved_writer_t, parent);
1120 avro_value_t *self = (avro_value_t *) vself;
1121 avro_value_t dest;
1122 check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
1123 DEBUG("Storing %s into %p", val? "TRUE": "FALSE", dest.self);
1124 return avro_value_set_boolean(&dest, val);
1125 }
1126
1127 static int
try_boolean(memoize_state_t * state,avro_resolved_writer_t ** self,avro_schema_t wschema,avro_schema_t rschema,avro_schema_t root_rschema)1128 try_boolean(memoize_state_t *state, avro_resolved_writer_t **self,
1129 avro_schema_t wschema, avro_schema_t rschema,
1130 avro_schema_t root_rschema)
1131 {
1132 if (is_avro_boolean(rschema)) {
1133 *self = avro_resolved_writer_create(wschema, root_rschema);
1134 avro_memoize_set(&state->mem, wschema, root_rschema, *self);
1135 (*self)->parent.set_boolean = avro_resolved_writer_set_boolean;
1136 }
1137 return 0;
1138 }
1139
1140
1141 /*-----------------------------------------------------------------------
1142 * bytes
1143 */
1144
1145 static int
avro_resolved_writer_set_bytes(const avro_value_iface_t * viface,void * vself,void * buf,size_t size)1146 avro_resolved_writer_set_bytes(const avro_value_iface_t *viface,
1147 void *vself, void *buf, size_t size)
1148 {
1149 int rval;
1150 const avro_resolved_writer_t *iface =
1151 container_of(viface, avro_resolved_writer_t, parent);
1152 avro_value_t *self = (avro_value_t *) vself;
1153 avro_value_t dest;
1154 check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
1155 DEBUG("Storing <%p:%" PRIsz "> into %p", buf, size, dest.self);
1156 return avro_value_set_bytes(&dest, buf, size);
1157 }
1158
1159 static int
avro_resolved_writer_give_bytes(const avro_value_iface_t * viface,void * vself,avro_wrapped_buffer_t * buf)1160 avro_resolved_writer_give_bytes(const avro_value_iface_t *viface,
1161 void *vself, avro_wrapped_buffer_t *buf)
1162 {
1163 int rval;
1164 const avro_resolved_writer_t *iface =
1165 container_of(viface, avro_resolved_writer_t, parent);
1166 avro_value_t *self = (avro_value_t *) vself;
1167 avro_value_t dest;
1168 check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
1169 DEBUG("Storing [%p] into %p", buf, dest.self);
1170 return avro_value_give_bytes(&dest, buf);
1171 }
1172
1173 static int
try_bytes(memoize_state_t * state,avro_resolved_writer_t ** self,avro_schema_t wschema,avro_schema_t rschema,avro_schema_t root_rschema)1174 try_bytes(memoize_state_t *state, avro_resolved_writer_t **self,
1175 avro_schema_t wschema, avro_schema_t rschema,
1176 avro_schema_t root_rschema)
1177 {
1178 if (is_avro_bytes(rschema)) {
1179 *self = avro_resolved_writer_create(wschema, root_rschema);
1180 avro_memoize_set(&state->mem, wschema, root_rschema, *self);
1181 (*self)->parent.set_bytes = avro_resolved_writer_set_bytes;
1182 (*self)->parent.give_bytes = avro_resolved_writer_give_bytes;
1183 }
1184 return 0;
1185 }
1186
1187
1188 /*-----------------------------------------------------------------------
1189 * double
1190 */
1191
1192 static int
avro_resolved_writer_set_double(const avro_value_iface_t * viface,void * vself,double val)1193 avro_resolved_writer_set_double(const avro_value_iface_t *viface,
1194 void *vself, double val)
1195 {
1196 int rval;
1197 const avro_resolved_writer_t *iface =
1198 container_of(viface, avro_resolved_writer_t, parent);
1199 avro_value_t *self = (avro_value_t *) vself;
1200 avro_value_t dest;
1201 check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
1202 DEBUG("Storing %le into %p", val, dest.self);
1203 return avro_value_set_double(&dest, val);
1204 }
1205
1206 static int
try_double(memoize_state_t * state,avro_resolved_writer_t ** self,avro_schema_t wschema,avro_schema_t rschema,avro_schema_t root_rschema)1207 try_double(memoize_state_t *state, avro_resolved_writer_t **self,
1208 avro_schema_t wschema, avro_schema_t rschema,
1209 avro_schema_t root_rschema)
1210 {
1211 if (is_avro_double(rschema)) {
1212 *self = avro_resolved_writer_create(wschema, root_rschema);
1213 avro_memoize_set(&state->mem, wschema, root_rschema, *self);
1214 (*self)->parent.set_double = avro_resolved_writer_set_double;
1215 }
1216 return 0;
1217 }
1218
1219
1220 /*-----------------------------------------------------------------------
1221 * float
1222 */
1223
1224 static int
avro_resolved_writer_set_float(const avro_value_iface_t * viface,void * vself,float val)1225 avro_resolved_writer_set_float(const avro_value_iface_t *viface,
1226 void *vself, float val)
1227 {
1228 int rval;
1229 const avro_resolved_writer_t *iface =
1230 container_of(viface, avro_resolved_writer_t, parent);
1231 avro_value_t *self = (avro_value_t *) vself;
1232 avro_value_t dest;
1233 check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
1234 DEBUG("Storing %e into %p", val, dest.self);
1235 return avro_value_set_float(&dest, val);
1236 }
1237
1238 static int
avro_resolved_writer_set_float_double(const avro_value_iface_t * viface,void * vself,float val)1239 avro_resolved_writer_set_float_double(const avro_value_iface_t *viface,
1240 void *vself, float val)
1241 {
1242 int rval;
1243 const avro_resolved_writer_t *iface =
1244 container_of(viface, avro_resolved_writer_t, parent);
1245 avro_value_t *self = (avro_value_t *) vself;
1246 avro_value_t dest;
1247 check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
1248 DEBUG("Promoting float %e into double %p", val, dest.self);
1249 return avro_value_set_double(&dest, val);
1250 }
1251
1252 static int
try_float(memoize_state_t * state,avro_resolved_writer_t ** self,avro_schema_t wschema,avro_schema_t rschema,avro_schema_t root_rschema)1253 try_float(memoize_state_t *state, avro_resolved_writer_t **self,
1254 avro_schema_t wschema, avro_schema_t rschema,
1255 avro_schema_t root_rschema)
1256 {
1257 if (is_avro_float(rschema)) {
1258 *self = avro_resolved_writer_create(wschema, root_rschema);
1259 avro_memoize_set(&state->mem, wschema, root_rschema, *self);
1260 (*self)->parent.set_float = avro_resolved_writer_set_float;
1261 }
1262
1263 else if (is_avro_double(rschema)) {
1264 *self = avro_resolved_writer_create(wschema, root_rschema);
1265 avro_memoize_set(&state->mem, wschema, root_rschema, *self);
1266 (*self)->parent.set_float = avro_resolved_writer_set_float_double;
1267 }
1268
1269 return 0;
1270 }
1271
1272
1273 /*-----------------------------------------------------------------------
1274 * int
1275 */
1276
1277 static int
avro_resolved_writer_set_int(const avro_value_iface_t * viface,void * vself,int32_t val)1278 avro_resolved_writer_set_int(const avro_value_iface_t *viface,
1279 void *vself, int32_t val)
1280 {
1281 int rval;
1282 const avro_resolved_writer_t *iface =
1283 container_of(viface, avro_resolved_writer_t, parent);
1284 avro_value_t *self = (avro_value_t *) vself;
1285 avro_value_t dest;
1286 check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
1287 DEBUG("Storing %" PRId32 " into %p", val, dest.self);
1288 return avro_value_set_int(&dest, val);
1289 }
1290
1291 static int
avro_resolved_writer_set_int_double(const avro_value_iface_t * viface,void * vself,int32_t val)1292 avro_resolved_writer_set_int_double(const avro_value_iface_t *viface,
1293 void *vself, int32_t val)
1294 {
1295 int rval;
1296 const avro_resolved_writer_t *iface =
1297 container_of(viface, avro_resolved_writer_t, parent);
1298 avro_value_t *self = (avro_value_t *) vself;
1299 avro_value_t dest;
1300 check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
1301 DEBUG("Promoting int %" PRId32 " into double %p", val, dest.self);
1302 return avro_value_set_double(&dest, val);
1303 }
1304
1305 static int
avro_resolved_writer_set_int_float(const avro_value_iface_t * viface,void * vself,int32_t val)1306 avro_resolved_writer_set_int_float(const avro_value_iface_t *viface,
1307 void *vself, int32_t val)
1308 {
1309 int rval;
1310 const avro_resolved_writer_t *iface =
1311 container_of(viface, avro_resolved_writer_t, parent);
1312 avro_value_t *self = (avro_value_t *) vself;
1313 avro_value_t dest;
1314 check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
1315 DEBUG("Promoting int %" PRId32 " into float %p", val, dest.self);
1316 return avro_value_set_float(&dest, (float) val);
1317 }
1318
1319 static int
avro_resolved_writer_set_int_long(const avro_value_iface_t * viface,void * vself,int32_t val)1320 avro_resolved_writer_set_int_long(const avro_value_iface_t *viface,
1321 void *vself, int32_t val)
1322 {
1323 int rval;
1324 const avro_resolved_writer_t *iface =
1325 container_of(viface, avro_resolved_writer_t, parent);
1326 avro_value_t *self = (avro_value_t *) vself;
1327 avro_value_t dest;
1328 check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
1329 DEBUG("Promoting int %" PRId32 " into long %p", val, dest.self);
1330 return avro_value_set_long(&dest, val);
1331 }
1332
1333 static int
try_int(memoize_state_t * state,avro_resolved_writer_t ** self,avro_schema_t wschema,avro_schema_t rschema,avro_schema_t root_rschema)1334 try_int(memoize_state_t *state, avro_resolved_writer_t **self,
1335 avro_schema_t wschema, avro_schema_t rschema,
1336 avro_schema_t root_rschema)
1337 {
1338 if (is_avro_int32(rschema)) {
1339 *self = avro_resolved_writer_create(wschema, root_rschema);
1340 avro_memoize_set(&state->mem, wschema, root_rschema, *self);
1341 (*self)->parent.set_int = avro_resolved_writer_set_int;
1342 }
1343
1344 else if (is_avro_int64(rschema)) {
1345 *self = avro_resolved_writer_create(wschema, root_rschema);
1346 avro_memoize_set(&state->mem, wschema, root_rschema, *self);
1347 (*self)->parent.set_int = avro_resolved_writer_set_int_long;
1348 }
1349
1350 else if (is_avro_double(rschema)) {
1351 *self = avro_resolved_writer_create(wschema, root_rschema);
1352 avro_memoize_set(&state->mem, wschema, root_rschema, *self);
1353 (*self)->parent.set_int = avro_resolved_writer_set_int_double;
1354 }
1355
1356 else if (is_avro_float(rschema)) {
1357 *self = avro_resolved_writer_create(wschema, root_rschema);
1358 avro_memoize_set(&state->mem, wschema, root_rschema, *self);
1359 (*self)->parent.set_int = avro_resolved_writer_set_int_float;
1360 }
1361
1362 return 0;
1363 }
1364
1365
1366 /*-----------------------------------------------------------------------
1367 * long
1368 */
1369
1370 static int
avro_resolved_writer_set_long(const avro_value_iface_t * viface,void * vself,int64_t val)1371 avro_resolved_writer_set_long(const avro_value_iface_t *viface,
1372 void *vself, int64_t val)
1373 {
1374 int rval;
1375 const avro_resolved_writer_t *iface =
1376 container_of(viface, avro_resolved_writer_t, parent);
1377 avro_value_t *self = (avro_value_t *) vself;
1378 avro_value_t dest;
1379 check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
1380 DEBUG("Storing %" PRId64 " into %p", val, dest.self);
1381 return avro_value_set_long(&dest, val);
1382 }
1383
1384 static int
avro_resolved_writer_set_long_double(const avro_value_iface_t * viface,void * vself,int64_t val)1385 avro_resolved_writer_set_long_double(const avro_value_iface_t *viface,
1386 void *vself, int64_t val)
1387 {
1388 int rval;
1389 const avro_resolved_writer_t *iface =
1390 container_of(viface, avro_resolved_writer_t, parent);
1391 avro_value_t *self = (avro_value_t *) vself;
1392 avro_value_t dest;
1393 check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
1394 DEBUG("Promoting long %" PRId64 " into double %p", val, dest.self);
1395 return avro_value_set_double(&dest, (double) val);
1396 }
1397
1398 static int
avro_resolved_writer_set_long_float(const avro_value_iface_t * viface,void * vself,int64_t val)1399 avro_resolved_writer_set_long_float(const avro_value_iface_t *viface,
1400 void *vself, int64_t val)
1401 {
1402 int rval;
1403 const avro_resolved_writer_t *iface =
1404 container_of(viface, avro_resolved_writer_t, parent);
1405 avro_value_t *self = (avro_value_t *) vself;
1406 avro_value_t dest;
1407 check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
1408 DEBUG("Promoting long %" PRId64 " into float %p", val, dest.self);
1409 return avro_value_set_float(&dest, (float) val);
1410 }
1411
1412 static int
try_long(memoize_state_t * state,avro_resolved_writer_t ** self,avro_schema_t wschema,avro_schema_t rschema,avro_schema_t root_rschema)1413 try_long(memoize_state_t *state, avro_resolved_writer_t **self,
1414 avro_schema_t wschema, avro_schema_t rschema,
1415 avro_schema_t root_rschema)
1416 {
1417 if (is_avro_int64(rschema)) {
1418 *self = avro_resolved_writer_create(wschema, root_rschema);
1419 avro_memoize_set(&state->mem, wschema, root_rschema, *self);
1420 (*self)->parent.set_long = avro_resolved_writer_set_long;
1421 }
1422
1423 else if (is_avro_double(rschema)) {
1424 *self = avro_resolved_writer_create(wschema, root_rschema);
1425 avro_memoize_set(&state->mem, wschema, root_rschema, *self);
1426 (*self)->parent.set_long = avro_resolved_writer_set_long_double;
1427 }
1428
1429 else if (is_avro_float(rschema)) {
1430 *self = avro_resolved_writer_create(wschema, root_rschema);
1431 avro_memoize_set(&state->mem, wschema, root_rschema, *self);
1432 (*self)->parent.set_long = avro_resolved_writer_set_long_float;
1433 }
1434
1435 return 0;
1436 }
1437
1438
1439 /*-----------------------------------------------------------------------
1440 * null
1441 */
1442
1443 static int
avro_resolved_writer_set_null(const avro_value_iface_t * viface,void * vself)1444 avro_resolved_writer_set_null(const avro_value_iface_t *viface,
1445 void *vself)
1446 {
1447 int rval;
1448 const avro_resolved_writer_t *iface =
1449 container_of(viface, avro_resolved_writer_t, parent);
1450 avro_value_t *self = (avro_value_t *) vself;
1451 avro_value_t dest;
1452 check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
1453 DEBUG("Storing NULL into %p", dest.self);
1454 return avro_value_set_null(&dest);
1455 }
1456
1457 static int
try_null(memoize_state_t * state,avro_resolved_writer_t ** self,avro_schema_t wschema,avro_schema_t rschema,avro_schema_t root_rschema)1458 try_null(memoize_state_t *state, avro_resolved_writer_t **self,
1459 avro_schema_t wschema, avro_schema_t rschema,
1460 avro_schema_t root_rschema)
1461 {
1462 if (is_avro_null(rschema)) {
1463 *self = avro_resolved_writer_create(wschema, root_rschema);
1464 avro_memoize_set(&state->mem, wschema, root_rschema, *self);
1465 (*self)->parent.set_null = avro_resolved_writer_set_null;
1466 }
1467 return 0;
1468 }
1469
1470
1471 /*-----------------------------------------------------------------------
1472 * string
1473 */
1474
1475 static int
avro_resolved_writer_set_string(const avro_value_iface_t * viface,void * vself,const char * str)1476 avro_resolved_writer_set_string(const avro_value_iface_t *viface,
1477 void *vself, const char *str)
1478 {
1479 int rval;
1480 const avro_resolved_writer_t *iface =
1481 container_of(viface, avro_resolved_writer_t, parent);
1482 avro_value_t *self = (avro_value_t *) vself;
1483 avro_value_t dest;
1484 check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
1485 DEBUG("Storing \"%s\" into %p", str, dest.self);
1486 return avro_value_set_string(&dest, str);
1487 }
1488
1489 static int
avro_resolved_writer_set_string_len(const avro_value_iface_t * viface,void * vself,const char * str,size_t size)1490 avro_resolved_writer_set_string_len(const avro_value_iface_t *viface,
1491 void *vself, const char *str, size_t size)
1492 {
1493 int rval;
1494 const avro_resolved_writer_t *iface =
1495 container_of(viface, avro_resolved_writer_t, parent);
1496 avro_value_t *self = (avro_value_t *) vself;
1497 avro_value_t dest;
1498 check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
1499 DEBUG("Storing <%p:%" PRIsz "> into %p", str, size, dest.self);
1500 return avro_value_set_string_len(&dest, str, size);
1501 }
1502
1503 static int
avro_resolved_writer_give_string_len(const avro_value_iface_t * viface,void * vself,avro_wrapped_buffer_t * buf)1504 avro_resolved_writer_give_string_len(const avro_value_iface_t *viface,
1505 void *vself, avro_wrapped_buffer_t *buf)
1506 {
1507 int rval;
1508 const avro_resolved_writer_t *iface =
1509 container_of(viface, avro_resolved_writer_t, parent);
1510 avro_value_t *self = (avro_value_t *) vself;
1511 avro_value_t dest;
1512 check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
1513 DEBUG("Storing [%p] into %p", buf, dest.self);
1514 return avro_value_give_string_len(&dest, buf);
1515 }
1516
1517 static int
try_string(memoize_state_t * state,avro_resolved_writer_t ** self,avro_schema_t wschema,avro_schema_t rschema,avro_schema_t root_rschema)1518 try_string(memoize_state_t *state, avro_resolved_writer_t **self,
1519 avro_schema_t wschema, avro_schema_t rschema,
1520 avro_schema_t root_rschema)
1521 {
1522 if (is_avro_string(rschema)) {
1523 *self = avro_resolved_writer_create(wschema, root_rschema);
1524 avro_memoize_set(&state->mem, wschema, root_rschema, *self);
1525 (*self)->parent.set_string = avro_resolved_writer_set_string;
1526 (*self)->parent.set_string_len = avro_resolved_writer_set_string_len;
1527 (*self)->parent.give_string_len = avro_resolved_writer_give_string_len;
1528 }
1529 return 0;
1530 }
1531
1532
1533 /*-----------------------------------------------------------------------
1534 * array
1535 */
1536
1537 typedef struct avro_resolved_array_writer {
1538 avro_resolved_writer_t parent;
1539 avro_resolved_writer_t *child_resolver;
1540 } avro_resolved_array_writer_t;
1541
1542 typedef struct avro_resolved_array_value {
1543 avro_value_t wrapped;
1544 avro_raw_array_t children;
1545 } avro_resolved_array_value_t;
1546
1547 static void
avro_resolved_array_writer_calculate_size(avro_resolved_writer_t * iface)1548 avro_resolved_array_writer_calculate_size(avro_resolved_writer_t *iface)
1549 {
1550 avro_resolved_array_writer_t *aiface =
1551 container_of(iface, avro_resolved_array_writer_t, parent);
1552
1553 /* Only calculate the size for any resolver once */
1554 iface->calculate_size = NULL;
1555
1556 DEBUG("Calculating size for %s->%s",
1557 avro_schema_type_name((iface)->wschema),
1558 avro_schema_type_name((iface)->rschema));
1559 iface->instance_size = sizeof(avro_resolved_array_value_t);
1560
1561 avro_resolved_writer_calculate_size(aiface->child_resolver);
1562 }
1563
1564 static void
avro_resolved_array_writer_free_iface(avro_resolved_writer_t * iface,st_table * freeing)1565 avro_resolved_array_writer_free_iface(avro_resolved_writer_t *iface, st_table *freeing)
1566 {
1567 avro_resolved_array_writer_t *aiface =
1568 container_of(iface, avro_resolved_array_writer_t, parent);
1569 free_resolver(aiface->child_resolver, freeing);
1570 avro_schema_decref(iface->wschema);
1571 avro_schema_decref(iface->rschema);
1572 avro_freet(avro_resolved_array_writer_t, iface);
1573 }
1574
1575 static int
avro_resolved_array_writer_init(const avro_resolved_writer_t * iface,void * vself)1576 avro_resolved_array_writer_init(const avro_resolved_writer_t *iface, void *vself)
1577 {
1578 const avro_resolved_array_writer_t *aiface =
1579 container_of(iface, avro_resolved_array_writer_t, parent);
1580 avro_resolved_array_value_t *self = (avro_resolved_array_value_t *) vself;
1581 size_t child_instance_size = aiface->child_resolver->instance_size;
1582 DEBUG("Initializing child array (child_size=%" PRIsz ")", child_instance_size);
1583 avro_raw_array_init(&self->children, child_instance_size);
1584 return 0;
1585 }
1586
1587 static void
avro_resolved_array_writer_free_elements(const avro_resolved_writer_t * child_iface,avro_resolved_array_value_t * self)1588 avro_resolved_array_writer_free_elements(const avro_resolved_writer_t *child_iface,
1589 avro_resolved_array_value_t *self)
1590 {
1591 size_t i;
1592 for (i = 0; i < avro_raw_array_size(&self->children); i++) {
1593 void *child_self = avro_raw_array_get_raw(&self->children, i);
1594 avro_resolved_writer_done(child_iface, child_self);
1595 }
1596 }
1597
1598 static void
avro_resolved_array_writer_done(const avro_resolved_writer_t * iface,void * vself)1599 avro_resolved_array_writer_done(const avro_resolved_writer_t *iface, void *vself)
1600 {
1601 const avro_resolved_array_writer_t *aiface =
1602 container_of(iface, avro_resolved_array_writer_t, parent);
1603 avro_resolved_array_value_t *self = (avro_resolved_array_value_t *) vself;
1604 avro_resolved_array_writer_free_elements(aiface->child_resolver, self);
1605 avro_raw_array_done(&self->children);
1606 }
1607
1608 static int
avro_resolved_array_writer_reset(const avro_resolved_writer_t * iface,void * vself)1609 avro_resolved_array_writer_reset(const avro_resolved_writer_t *iface, void *vself)
1610 {
1611 const avro_resolved_array_writer_t *aiface =
1612 container_of(iface, avro_resolved_array_writer_t, parent);
1613 avro_resolved_array_value_t *self = (avro_resolved_array_value_t *) vself;
1614
1615 /* Clear out our cache of wrapped children */
1616 avro_resolved_array_writer_free_elements(aiface->child_resolver, self);
1617 avro_raw_array_clear(&self->children);
1618 return 0;
1619 }
1620
1621 static int
avro_resolved_array_writer_get_size(const avro_value_iface_t * viface,const void * vself,size_t * size)1622 avro_resolved_array_writer_get_size(const avro_value_iface_t *viface,
1623 const void *vself, size_t *size)
1624 {
1625 int rval;
1626 const avro_resolved_writer_t *iface =
1627 container_of(viface, avro_resolved_writer_t, parent);
1628 const avro_resolved_array_value_t *self = (const avro_resolved_array_value_t *) vself;
1629 avro_value_t dest;
1630 check(rval, avro_resolved_writer_get_real_dest(iface, &self->wrapped, &dest));
1631 return avro_value_get_size(&dest, size);
1632 }
1633
1634 static int
avro_resolved_array_writer_append(const avro_value_iface_t * viface,void * vself,avro_value_t * child_out,size_t * new_index)1635 avro_resolved_array_writer_append(const avro_value_iface_t *viface,
1636 void *vself, avro_value_t *child_out,
1637 size_t *new_index)
1638 {
1639 int rval;
1640 const avro_resolved_writer_t *iface =
1641 container_of(viface, avro_resolved_writer_t, parent);
1642 const avro_resolved_array_writer_t *aiface =
1643 container_of(iface, avro_resolved_array_writer_t, parent);
1644 avro_resolved_array_value_t *self = (avro_resolved_array_value_t *) vself;
1645 avro_value_t dest;
1646 check(rval, avro_resolved_writer_get_real_dest(iface, &self->wrapped, &dest));
1647
1648 child_out->iface = &aiface->child_resolver->parent;
1649 child_out->self = avro_raw_array_append(&self->children);
1650 if (child_out->self == NULL) {
1651 avro_set_error("Couldn't expand array");
1652 return ENOMEM;
1653 }
1654
1655 DEBUG("Appending to array %p", dest.self);
1656 check(rval, avro_value_append(&dest, (avro_value_t *) child_out->self, new_index));
1657 return avro_resolved_writer_init(aiface->child_resolver, child_out->self);
1658 }
1659
1660 static avro_resolved_array_writer_t *
avro_resolved_array_writer_create(avro_schema_t wschema,avro_schema_t rschema)1661 avro_resolved_array_writer_create(avro_schema_t wschema, avro_schema_t rschema)
1662 {
1663 avro_resolved_writer_t *self = (avro_resolved_writer_t *) avro_new(avro_resolved_array_writer_t);
1664 memset(self, 0, sizeof(avro_resolved_array_writer_t));
1665
1666 self->parent.incref_iface = avro_resolved_writer_incref_iface;
1667 self->parent.decref_iface = avro_resolved_writer_decref_iface;
1668 self->parent.incref = avro_resolved_writer_incref;
1669 self->parent.decref = avro_resolved_writer_decref;
1670 self->parent.reset = avro_resolved_writer_reset;
1671 self->parent.get_type = avro_resolved_writer_get_type;
1672 self->parent.get_schema = avro_resolved_writer_get_schema;
1673 self->parent.get_size = avro_resolved_array_writer_get_size;
1674 self->parent.append = avro_resolved_array_writer_append;
1675
1676 self->refcount = 1;
1677 self->wschema = avro_schema_incref(wschema);
1678 self->rschema = avro_schema_incref(rschema);
1679 self->reader_union_branch = -1;
1680 self->calculate_size = avro_resolved_array_writer_calculate_size;
1681 self->free_iface = avro_resolved_array_writer_free_iface;
1682 self->init = avro_resolved_array_writer_init;
1683 self->done = avro_resolved_array_writer_done;
1684 self->reset_wrappers = avro_resolved_array_writer_reset;
1685 return container_of(self, avro_resolved_array_writer_t, parent);
1686 }
1687
1688 static int
try_array(memoize_state_t * state,avro_resolved_writer_t ** self,avro_schema_t wschema,avro_schema_t rschema,avro_schema_t root_rschema)1689 try_array(memoize_state_t *state, avro_resolved_writer_t **self,
1690 avro_schema_t wschema, avro_schema_t rschema,
1691 avro_schema_t root_rschema)
1692 {
1693 /*
1694 * First verify that the reader is an array.
1695 */
1696
1697 if (!is_avro_array(rschema)) {
1698 return 0;
1699 }
1700
1701 /*
1702 * Array schemas have to have compatible element schemas to be
1703 * compatible themselves. Try to create an resolver to check
1704 * the compatibility.
1705 */
1706
1707 avro_resolved_array_writer_t *aself =
1708 avro_resolved_array_writer_create(wschema, root_rschema);
1709 avro_memoize_set(&state->mem, wschema, root_rschema, aself);
1710
1711 avro_schema_t witems = avro_schema_array_items(wschema);
1712 avro_schema_t ritems = avro_schema_array_items(rschema);
1713
1714 avro_resolved_writer_t *item_resolver =
1715 avro_resolved_writer_new_memoized(state, witems, ritems);
1716 if (item_resolver == NULL) {
1717 avro_memoize_delete(&state->mem, wschema, root_rschema);
1718 avro_value_iface_decref(&aself->parent.parent);
1719 avro_prefix_error("Array values aren't compatible: ");
1720 return EINVAL;
1721 }
1722
1723 /*
1724 * The two schemas are compatible. Store the item schema's
1725 * resolver into the child_resolver field.
1726 */
1727
1728 aself->child_resolver = item_resolver;
1729 *self = &aself->parent;
1730 return 0;
1731 }
1732
1733
1734 /*-----------------------------------------------------------------------
1735 * enum
1736 */
1737
1738 static int
avro_resolved_writer_set_enum(const avro_value_iface_t * viface,void * vself,int val)1739 avro_resolved_writer_set_enum(const avro_value_iface_t *viface,
1740 void *vself, int val)
1741 {
1742 int rval;
1743 const avro_resolved_writer_t *iface =
1744 container_of(viface, avro_resolved_writer_t, parent);
1745 avro_value_t *self = (avro_value_t *) vself;
1746 avro_value_t dest;
1747 check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
1748 DEBUG("Storing %d into %p", val, dest.self);
1749 return avro_value_set_enum(&dest, val);
1750 }
1751
1752 static int
try_enum(memoize_state_t * state,avro_resolved_writer_t ** self,avro_schema_t wschema,avro_schema_t rschema,avro_schema_t root_rschema)1753 try_enum(memoize_state_t *state, avro_resolved_writer_t **self,
1754 avro_schema_t wschema, avro_schema_t rschema,
1755 avro_schema_t root_rschema)
1756 {
1757 /*
1758 * Enum schemas have to have the same name — but not the same
1759 * list of symbols — to be compatible.
1760 */
1761
1762 if (is_avro_enum(rschema)) {
1763 const char *wname = avro_schema_name(wschema);
1764 const char *rname = avro_schema_name(rschema);
1765
1766 if (strcmp(wname, rname) == 0) {
1767 *self = avro_resolved_writer_create(wschema, root_rschema);
1768 avro_memoize_set(&state->mem, wschema, root_rschema, *self);
1769 (*self)->parent.set_enum = avro_resolved_writer_set_enum;
1770 }
1771 }
1772 return 0;
1773 }
1774
1775
1776 /*-----------------------------------------------------------------------
1777 * fixed
1778 */
1779
1780 static int
avro_resolved_writer_set_fixed(const avro_value_iface_t * viface,void * vself,void * buf,size_t size)1781 avro_resolved_writer_set_fixed(const avro_value_iface_t *viface,
1782 void *vself, void *buf, size_t size)
1783 {
1784 int rval;
1785 const avro_resolved_writer_t *iface =
1786 container_of(viface, avro_resolved_writer_t, parent);
1787 avro_value_t *self = (avro_value_t *) vself;
1788 avro_value_t dest;
1789 check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
1790 DEBUG("Storing <%p:%" PRIsz "> into (fixed) %p", buf, size, dest.self);
1791 return avro_value_set_fixed(&dest, buf, size);
1792 }
1793
1794 static int
avro_resolved_writer_give_fixed(const avro_value_iface_t * viface,void * vself,avro_wrapped_buffer_t * buf)1795 avro_resolved_writer_give_fixed(const avro_value_iface_t *viface,
1796 void *vself, avro_wrapped_buffer_t *buf)
1797 {
1798 int rval;
1799 const avro_resolved_writer_t *iface =
1800 container_of(viface, avro_resolved_writer_t, parent);
1801 avro_value_t *self = (avro_value_t *) vself;
1802 avro_value_t dest;
1803 check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
1804 DEBUG("Storing [%p] into (fixed) %p", buf, dest.self);
1805 return avro_value_give_fixed(&dest, buf);
1806 }
1807
1808 static int
try_fixed(memoize_state_t * state,avro_resolved_writer_t ** self,avro_schema_t wschema,avro_schema_t rschema,avro_schema_t root_rschema)1809 try_fixed(memoize_state_t *state, avro_resolved_writer_t **self,
1810 avro_schema_t wschema, avro_schema_t rschema,
1811 avro_schema_t root_rschema)
1812 {
1813 /*
1814 * Fixed schemas need the same name and size to be compatible.
1815 */
1816
1817 if (avro_schema_equal(wschema, rschema)) {
1818 *self = avro_resolved_writer_create(wschema, root_rschema);
1819 avro_memoize_set(&state->mem, wschema, root_rschema, *self);
1820 (*self)->parent.set_fixed = avro_resolved_writer_set_fixed;
1821 (*self)->parent.give_fixed = avro_resolved_writer_give_fixed;
1822 }
1823 return 0;
1824 }
1825
1826
1827 /*-----------------------------------------------------------------------
1828 * map
1829 */
1830
1831 typedef struct avro_resolved_map_writer {
1832 avro_resolved_writer_t parent;
1833 avro_resolved_writer_t *child_resolver;
1834 } avro_resolved_map_writer_t;
1835
1836 typedef struct avro_resolved_map_value {
1837 avro_value_t wrapped;
1838 avro_raw_array_t children;
1839 } avro_resolved_map_value_t;
1840
1841 static void
avro_resolved_map_writer_calculate_size(avro_resolved_writer_t * iface)1842 avro_resolved_map_writer_calculate_size(avro_resolved_writer_t *iface)
1843 {
1844 avro_resolved_map_writer_t *miface =
1845 container_of(iface, avro_resolved_map_writer_t, parent);
1846
1847 /* Only calculate the size for any resolver once */
1848 iface->calculate_size = NULL;
1849
1850 DEBUG("Calculating size for %s->%s",
1851 avro_schema_type_name((iface)->wschema),
1852 avro_schema_type_name((iface)->rschema));
1853 iface->instance_size = sizeof(avro_resolved_map_value_t);
1854
1855 avro_resolved_writer_calculate_size(miface->child_resolver);
1856 }
1857
1858 static void
avro_resolved_map_writer_free_iface(avro_resolved_writer_t * iface,st_table * freeing)1859 avro_resolved_map_writer_free_iface(avro_resolved_writer_t *iface, st_table *freeing)
1860 {
1861 avro_resolved_map_writer_t *miface =
1862 container_of(iface, avro_resolved_map_writer_t, parent);
1863 free_resolver(miface->child_resolver, freeing);
1864 avro_schema_decref(iface->wschema);
1865 avro_schema_decref(iface->rschema);
1866 avro_freet(avro_resolved_map_writer_t, iface);
1867 }
1868
1869 static int
avro_resolved_map_writer_init(const avro_resolved_writer_t * iface,void * vself)1870 avro_resolved_map_writer_init(const avro_resolved_writer_t *iface, void *vself)
1871 {
1872 const avro_resolved_map_writer_t *miface =
1873 container_of(iface, avro_resolved_map_writer_t, parent);
1874 avro_resolved_map_value_t *self = (avro_resolved_map_value_t *) vself;
1875 size_t child_instance_size = miface->child_resolver->instance_size;
1876 DEBUG("Initializing child array for map (child_size=%" PRIsz ")", child_instance_size);
1877 avro_raw_array_init(&self->children, child_instance_size);
1878 return 0;
1879 }
1880
1881 static void
avro_resolved_map_writer_free_elements(const avro_resolved_writer_t * child_iface,avro_resolved_map_value_t * self)1882 avro_resolved_map_writer_free_elements(const avro_resolved_writer_t *child_iface,
1883 avro_resolved_map_value_t *self)
1884 {
1885 size_t i;
1886 for (i = 0; i < avro_raw_array_size(&self->children); i++) {
1887 void *child_self = avro_raw_array_get_raw(&self->children, i);
1888 avro_resolved_writer_done(child_iface, child_self);
1889 }
1890 }
1891
1892 static void
avro_resolved_map_writer_done(const avro_resolved_writer_t * iface,void * vself)1893 avro_resolved_map_writer_done(const avro_resolved_writer_t *iface, void *vself)
1894 {
1895 const avro_resolved_map_writer_t *miface =
1896 container_of(iface, avro_resolved_map_writer_t, parent);
1897 avro_resolved_map_value_t *self = (avro_resolved_map_value_t *) vself;
1898 avro_resolved_map_writer_free_elements(miface->child_resolver, self);
1899 avro_raw_array_done(&self->children);
1900 }
1901
1902 static int
avro_resolved_map_writer_reset(const avro_resolved_writer_t * iface,void * vself)1903 avro_resolved_map_writer_reset(const avro_resolved_writer_t *iface, void *vself)
1904 {
1905 const avro_resolved_map_writer_t *miface =
1906 container_of(iface, avro_resolved_map_writer_t, parent);
1907 avro_resolved_map_value_t *self = (avro_resolved_map_value_t *) vself;
1908
1909 /* Clear out our cache of wrapped children */
1910 avro_resolved_map_writer_free_elements(miface->child_resolver, self);
1911 return 0;
1912 }
1913
1914 static int
avro_resolved_map_writer_get_size(const avro_value_iface_t * viface,const void * vself,size_t * size)1915 avro_resolved_map_writer_get_size(const avro_value_iface_t *viface,
1916 const void *vself, size_t *size)
1917 {
1918 int rval;
1919 const avro_resolved_writer_t *iface =
1920 container_of(viface, avro_resolved_writer_t, parent);
1921 const avro_resolved_map_value_t *self = (const avro_resolved_map_value_t *) vself;
1922 avro_value_t dest;
1923 check(rval, avro_resolved_writer_get_real_dest(iface, &self->wrapped, &dest));
1924 return avro_value_get_size(&dest, size);
1925 }
1926
1927 static int
avro_resolved_map_writer_add(const avro_value_iface_t * viface,void * vself,const char * key,avro_value_t * child,size_t * index,int * is_new)1928 avro_resolved_map_writer_add(const avro_value_iface_t *viface,
1929 void *vself, const char *key,
1930 avro_value_t *child, size_t *index, int *is_new)
1931 {
1932 int rval;
1933 const avro_resolved_writer_t *iface =
1934 container_of(viface, avro_resolved_writer_t, parent);
1935 const avro_resolved_map_writer_t *miface =
1936 container_of(iface, avro_resolved_map_writer_t, parent);
1937 avro_resolved_map_value_t *self = (avro_resolved_map_value_t *) vself;
1938 avro_value_t dest;
1939 check(rval, avro_resolved_writer_get_real_dest(iface, &self->wrapped, &dest));
1940
1941 /*
1942 * This is a bit convoluted. We need to stash the wrapped child
1943 * value somewhere in our children array. But we don't know
1944 * where to put it until the wrapped map tells us whether this
1945 * is a new value, and if not, which index the value should go
1946 * in.
1947 */
1948
1949 avro_value_t real_child;
1950 size_t real_index;
1951 int real_is_new;
1952
1953 DEBUG("Adding %s to map %p", key, dest.self);
1954 check(rval, avro_value_add(&dest, key, &real_child, &real_index, &real_is_new));
1955
1956 child->iface = &miface->child_resolver->parent;
1957 if (real_is_new) {
1958 child->self = avro_raw_array_append(&self->children);
1959 DEBUG("Element is new (child resolver=%p)", child->self);
1960 if (child->self == NULL) {
1961 avro_set_error("Couldn't expand map");
1962 return ENOMEM;
1963 }
1964 check(rval, avro_resolved_writer_init
1965 (miface->child_resolver, child->self));
1966 } else {
1967 child->self = avro_raw_array_get_raw(&self->children, real_index);
1968 DEBUG("Element is old (child resolver=%p)", child->self);
1969 }
1970 avro_value_t *child_vself = (avro_value_t *) child->self;
1971 *child_vself = real_child;
1972
1973 if (index != NULL) {
1974 *index = real_index;
1975 }
1976 if (is_new != NULL) {
1977 *is_new = real_is_new;
1978 }
1979 return 0;
1980 }
1981
1982 static avro_resolved_map_writer_t *
avro_resolved_map_writer_create(avro_schema_t wschema,avro_schema_t rschema)1983 avro_resolved_map_writer_create(avro_schema_t wschema, avro_schema_t rschema)
1984 {
1985 avro_resolved_writer_t *self = (avro_resolved_writer_t *) avro_new(avro_resolved_map_writer_t);
1986 memset(self, 0, sizeof(avro_resolved_map_writer_t));
1987
1988 self->parent.incref_iface = avro_resolved_writer_incref_iface;
1989 self->parent.decref_iface = avro_resolved_writer_decref_iface;
1990 self->parent.incref = avro_resolved_writer_incref;
1991 self->parent.decref = avro_resolved_writer_decref;
1992 self->parent.reset = avro_resolved_writer_reset;
1993 self->parent.get_type = avro_resolved_writer_get_type;
1994 self->parent.get_schema = avro_resolved_writer_get_schema;
1995 self->parent.get_size = avro_resolved_map_writer_get_size;
1996 self->parent.add = avro_resolved_map_writer_add;
1997
1998 self->refcount = 1;
1999 self->wschema = avro_schema_incref(wschema);
2000 self->rschema = avro_schema_incref(rschema);
2001 self->reader_union_branch = -1;
2002 self->calculate_size = avro_resolved_map_writer_calculate_size;
2003 self->free_iface = avro_resolved_map_writer_free_iface;
2004 self->init = avro_resolved_map_writer_init;
2005 self->done = avro_resolved_map_writer_done;
2006 self->reset_wrappers = avro_resolved_map_writer_reset;
2007 return container_of(self, avro_resolved_map_writer_t, parent);
2008 }
2009
2010 static int
try_map(memoize_state_t * state,avro_resolved_writer_t ** self,avro_schema_t wschema,avro_schema_t rschema,avro_schema_t root_rschema)2011 try_map(memoize_state_t *state, avro_resolved_writer_t **self,
2012 avro_schema_t wschema, avro_schema_t rschema,
2013 avro_schema_t root_rschema)
2014 {
2015 /*
2016 * First verify that the reader is an map.
2017 */
2018
2019 if (!is_avro_map(rschema)) {
2020 return 0;
2021 }
2022
2023 /*
2024 * Map schemas have to have compatible element schemas to be
2025 * compatible themselves. Try to create an resolver to check
2026 * the compatibility.
2027 */
2028
2029 avro_resolved_map_writer_t *mself =
2030 avro_resolved_map_writer_create(wschema, root_rschema);
2031 avro_memoize_set(&state->mem, wschema, root_rschema, mself);
2032
2033 avro_schema_t witems = avro_schema_map_values(wschema);
2034 avro_schema_t ritems = avro_schema_map_values(rschema);
2035
2036 avro_resolved_writer_t *item_resolver =
2037 avro_resolved_writer_new_memoized(state, witems, ritems);
2038 if (item_resolver == NULL) {
2039 avro_memoize_delete(&state->mem, wschema, root_rschema);
2040 avro_value_iface_decref(&mself->parent.parent);
2041 avro_prefix_error("Map values aren't compatible: ");
2042 return EINVAL;
2043 }
2044
2045 /*
2046 * The two schemas are compatible. Store the item schema's
2047 * resolver into the child_resolver field.
2048 */
2049
2050 mself->child_resolver = item_resolver;
2051 *self = &mself->parent;
2052 return 0;
2053 }
2054
2055
2056 /*-----------------------------------------------------------------------
2057 * record
2058 */
2059
2060 typedef struct avro_resolved_record_writer {
2061 avro_resolved_writer_t parent;
2062 size_t field_count;
2063 size_t *field_offsets;
2064 avro_resolved_writer_t **field_resolvers;
2065 size_t *index_mapping;
2066 } avro_resolved_record_writer_t;
2067
2068 typedef struct avro_resolved_record_value {
2069 avro_value_t wrapped;
2070 /* The rest of the struct is taken up by the inline storage
2071 * needed for each field. */
2072 } avro_resolved_record_value_t;
2073
2074 /** Return a pointer to the given field within a record struct. */
2075 #define avro_resolved_record_field(iface, rec, index) \
2076 (((char *) (rec)) + (iface)->field_offsets[(index)])
2077
2078
2079 static void
avro_resolved_record_writer_calculate_size(avro_resolved_writer_t * iface)2080 avro_resolved_record_writer_calculate_size(avro_resolved_writer_t *iface)
2081 {
2082 avro_resolved_record_writer_t *riface =
2083 container_of(iface, avro_resolved_record_writer_t, parent);
2084
2085 /* Only calculate the size for any resolver once */
2086 iface->calculate_size = NULL;
2087
2088 DEBUG("Calculating size for %s->%s",
2089 avro_schema_type_name((iface)->wschema),
2090 avro_schema_type_name((iface)->rschema));
2091
2092 /*
2093 * Once we've figured out which writer fields we actually need,
2094 * calculate an offset for each one.
2095 */
2096
2097 size_t wi;
2098 size_t next_offset = sizeof(avro_resolved_record_value_t);
2099 for (wi = 0; wi < riface->field_count; wi++) {
2100 riface->field_offsets[wi] = next_offset;
2101 if (riface->field_resolvers[wi] != NULL) {
2102 avro_resolved_writer_calculate_size
2103 (riface->field_resolvers[wi]);
2104 size_t field_size =
2105 riface->field_resolvers[wi]->instance_size;
2106 DEBUG("Field %" PRIsz " has size %" PRIsz, wi, field_size);
2107 next_offset += field_size;
2108 } else {
2109 DEBUG("Field %" PRIsz " is being skipped", wi);
2110 }
2111 }
2112
2113 DEBUG("Record has size %" PRIsz, next_offset);
2114 iface->instance_size = next_offset;
2115 }
2116
2117 static void
avro_resolved_record_writer_free_iface(avro_resolved_writer_t * iface,st_table * freeing)2118 avro_resolved_record_writer_free_iface(avro_resolved_writer_t *iface, st_table *freeing)
2119 {
2120 avro_resolved_record_writer_t *riface =
2121 container_of(iface, avro_resolved_record_writer_t, parent);
2122
2123 if (riface->field_offsets != NULL) {
2124 avro_free(riface->field_offsets,
2125 riface->field_count * sizeof(size_t));
2126 }
2127
2128 if (riface->field_resolvers != NULL) {
2129 size_t i;
2130 for (i = 0; i < riface->field_count; i++) {
2131 if (riface->field_resolvers[i] != NULL) {
2132 DEBUG("Freeing field %" PRIsz " %p", i,
2133 riface->field_resolvers[i]);
2134 free_resolver(riface->field_resolvers[i], freeing);
2135 }
2136 }
2137 avro_free(riface->field_resolvers,
2138 riface->field_count * sizeof(avro_resolved_writer_t *));
2139 }
2140
2141 if (riface->index_mapping != NULL) {
2142 avro_free(riface->index_mapping,
2143 riface->field_count * sizeof(size_t));
2144 }
2145
2146 avro_schema_decref(iface->wschema);
2147 avro_schema_decref(iface->rschema);
2148 avro_freet(avro_resolved_record_writer_t, iface);
2149 }
2150
2151 static int
avro_resolved_record_writer_init(const avro_resolved_writer_t * iface,void * vself)2152 avro_resolved_record_writer_init(const avro_resolved_writer_t *iface, void *vself)
2153 {
2154 int rval;
2155 const avro_resolved_record_writer_t *riface =
2156 container_of(iface, avro_resolved_record_writer_t, parent);
2157 avro_resolved_record_value_t *self = (avro_resolved_record_value_t *) vself;
2158
2159 /* Initialize each field */
2160 size_t i;
2161 for (i = 0; i < riface->field_count; i++) {
2162 if (riface->field_resolvers[i] != NULL) {
2163 check(rval, avro_resolved_writer_init
2164 (riface->field_resolvers[i],
2165 avro_resolved_record_field(riface, self, i)));
2166 }
2167 }
2168
2169 return 0;
2170 }
2171
2172 static void
avro_resolved_record_writer_done(const avro_resolved_writer_t * iface,void * vself)2173 avro_resolved_record_writer_done(const avro_resolved_writer_t *iface, void *vself)
2174 {
2175 const avro_resolved_record_writer_t *riface =
2176 container_of(iface, avro_resolved_record_writer_t, parent);
2177 avro_resolved_record_value_t *self = (avro_resolved_record_value_t *) vself;
2178
2179 /* Finalize each field */
2180 size_t i;
2181 for (i = 0; i < riface->field_count; i++) {
2182 if (riface->field_resolvers[i] != NULL) {
2183 avro_resolved_writer_done
2184 (riface->field_resolvers[i],
2185 avro_resolved_record_field(riface, self, i));
2186 }
2187 }
2188 }
2189
2190 static int
avro_resolved_record_writer_reset(const avro_resolved_writer_t * iface,void * vself)2191 avro_resolved_record_writer_reset(const avro_resolved_writer_t *iface, void *vself)
2192 {
2193 int rval;
2194 const avro_resolved_record_writer_t *riface =
2195 container_of(iface, avro_resolved_record_writer_t, parent);
2196 avro_resolved_record_value_t *self = (avro_resolved_record_value_t *) vself;
2197
2198 /* Reset each field */
2199 size_t i;
2200 for (i = 0; i < riface->field_count; i++) {
2201 if (riface->field_resolvers[i] != NULL) {
2202 check(rval, avro_resolved_writer_reset_wrappers
2203 (riface->field_resolvers[i],
2204 avro_resolved_record_field(riface, self, i)));
2205 }
2206 }
2207
2208 return 0;
2209 }
2210
2211 static int
avro_resolved_record_writer_get_size(const avro_value_iface_t * viface,const void * vself,size_t * size)2212 avro_resolved_record_writer_get_size(const avro_value_iface_t *viface,
2213 const void *vself, size_t *size)
2214 {
2215 AVRO_UNUSED(vself);
2216 const avro_resolved_writer_t *iface =
2217 container_of(viface, avro_resolved_writer_t, parent);
2218 const avro_resolved_record_writer_t *riface =
2219 container_of(iface, avro_resolved_record_writer_t, parent);
2220 *size = riface->field_count;
2221 return 0;
2222 }
2223
2224 static int
avro_resolved_record_writer_get_by_index(const avro_value_iface_t * viface,const void * vself,size_t index,avro_value_t * child,const char ** name)2225 avro_resolved_record_writer_get_by_index(const avro_value_iface_t *viface,
2226 const void *vself, size_t index,
2227 avro_value_t *child, const char **name)
2228 {
2229 int rval;
2230 const avro_resolved_writer_t *iface =
2231 container_of(viface, avro_resolved_writer_t, parent);
2232 const avro_resolved_record_writer_t *riface =
2233 container_of(iface, avro_resolved_record_writer_t, parent);
2234 const avro_resolved_record_value_t *self = (const avro_resolved_record_value_t *) vself;
2235 avro_value_t dest;
2236
2237 DEBUG("Getting writer field %" PRIsz " from record %p", index, self);
2238 if (riface->field_resolvers[index] == NULL) {
2239 DEBUG("Reader doesn't have field, skipping");
2240 child->iface = NULL;
2241 child->self = NULL;
2242 return 0;
2243 }
2244
2245 check(rval, avro_resolved_writer_get_real_dest(iface, &self->wrapped, &dest));
2246 size_t reader_index = riface->index_mapping[index];
2247 DEBUG(" Reader field is %" PRIsz, reader_index);
2248 child->iface = &riface->field_resolvers[index]->parent;
2249 child->self = avro_resolved_record_field(riface, self, index);
2250
2251 return avro_value_get_by_index(&dest, reader_index, (avro_value_t *) child->self, name);
2252 }
2253
2254 static int
avro_resolved_record_writer_get_by_name(const avro_value_iface_t * viface,const void * vself,const char * name,avro_value_t * child,size_t * index)2255 avro_resolved_record_writer_get_by_name(const avro_value_iface_t *viface,
2256 const void *vself, const char *name,
2257 avro_value_t *child, size_t *index)
2258 {
2259 const avro_resolved_writer_t *iface =
2260 container_of(viface, avro_resolved_writer_t, parent);
2261
2262 int wi = avro_schema_record_field_get_index(iface->wschema, name);
2263 if (wi == -1) {
2264 avro_set_error("Record doesn't have field named %s", name);
2265 return EINVAL;
2266 }
2267
2268 DEBUG("Writer field %s is at index %d", name, wi);
2269 if (index != NULL) {
2270 *index = wi;
2271 }
2272 return avro_resolved_record_writer_get_by_index(viface, vself, wi, child, NULL);
2273 }
2274
2275 static avro_resolved_record_writer_t *
avro_resolved_record_writer_create(avro_schema_t wschema,avro_schema_t rschema)2276 avro_resolved_record_writer_create(avro_schema_t wschema, avro_schema_t rschema)
2277 {
2278 avro_resolved_writer_t *self = (avro_resolved_writer_t *) avro_new(avro_resolved_record_writer_t);
2279 memset(self, 0, sizeof(avro_resolved_record_writer_t));
2280
2281 self->parent.incref_iface = avro_resolved_writer_incref_iface;
2282 self->parent.decref_iface = avro_resolved_writer_decref_iface;
2283 self->parent.incref = avro_resolved_writer_incref;
2284 self->parent.decref = avro_resolved_writer_decref;
2285 self->parent.reset = avro_resolved_writer_reset;
2286 self->parent.get_type = avro_resolved_writer_get_type;
2287 self->parent.get_schema = avro_resolved_writer_get_schema;
2288 self->parent.get_size = avro_resolved_record_writer_get_size;
2289 self->parent.get_by_index = avro_resolved_record_writer_get_by_index;
2290 self->parent.get_by_name = avro_resolved_record_writer_get_by_name;
2291
2292 self->refcount = 1;
2293 self->wschema = avro_schema_incref(wschema);
2294 self->rschema = avro_schema_incref(rschema);
2295 self->reader_union_branch = -1;
2296 self->calculate_size = avro_resolved_record_writer_calculate_size;
2297 self->free_iface = avro_resolved_record_writer_free_iface;
2298 self->init = avro_resolved_record_writer_init;
2299 self->done = avro_resolved_record_writer_done;
2300 self->reset_wrappers = avro_resolved_record_writer_reset;
2301 return container_of(self, avro_resolved_record_writer_t, parent);
2302 }
2303
2304 static int
try_record(memoize_state_t * state,avro_resolved_writer_t ** self,avro_schema_t wschema,avro_schema_t rschema,avro_schema_t root_rschema)2305 try_record(memoize_state_t *state, avro_resolved_writer_t **self,
2306 avro_schema_t wschema, avro_schema_t rschema,
2307 avro_schema_t root_rschema)
2308 {
2309 /*
2310 * First verify that the reader is also a record, and has the
2311 * same name as the writer.
2312 */
2313
2314 if (!is_avro_record(rschema)) {
2315 return 0;
2316 }
2317
2318 const char *wname = avro_schema_name(wschema);
2319 const char *rname = avro_schema_name(rschema);
2320
2321 if (strcmp(wname, rname) != 0) {
2322 return 0;
2323 }
2324
2325 /*
2326 * Categorize the fields in the record schemas. Fields that are
2327 * only in the writer are ignored. Fields that are only in the
2328 * reader raise a schema mismatch error, unless the field has a
2329 * default value. Fields that are in both are resolved
2330 * recursively.
2331 *
2332 * The field_resolvers array will contain an avro_value_iface_t
2333 * for each field in the writer schema. To build this array, we
2334 * loop through the fields of the reader schema. If that field
2335 * is also in the writer schema, we resolve them recursively,
2336 * and store the resolver into the array. If the field isn't in
2337 * the writer schema, we raise an error. (TODO: Eventually,
2338 * we'll handle default values here.) After this loop finishes,
2339 * any NULLs in the field_resolvers array will represent fields
2340 * in the writer but not the reader; these fields will be
2341 * skipped when processing the input.
2342 */
2343
2344 avro_resolved_record_writer_t *rself =
2345 avro_resolved_record_writer_create(wschema, root_rschema);
2346 avro_memoize_set(&state->mem, wschema, root_rschema, rself);
2347
2348 size_t wfields = avro_schema_record_size(wschema);
2349 size_t rfields = avro_schema_record_size(rschema);
2350
2351 DEBUG("Checking writer record schema %s", wname);
2352
2353 avro_resolved_writer_t **field_resolvers =
2354 (avro_resolved_writer_t **) avro_calloc(wfields, sizeof(avro_resolved_writer_t *));
2355 size_t *field_offsets = (size_t *) avro_calloc(wfields, sizeof(size_t));
2356 size_t *index_mapping = (size_t *) avro_calloc(wfields, sizeof(size_t));
2357
2358 size_t ri;
2359 for (ri = 0; ri < rfields; ri++) {
2360 avro_schema_t rfield =
2361 avro_schema_record_field_get_by_index(rschema, ri);
2362 const char *field_name =
2363 avro_schema_record_field_name(rschema, ri);
2364
2365 DEBUG("Resolving reader record field %" PRIsz " (%s)", ri, field_name);
2366
2367 /*
2368 * See if this field is also in the writer schema.
2369 */
2370
2371 int wi = avro_schema_record_field_get_index(wschema, field_name);
2372
2373 if (wi == -1) {
2374 /*
2375 * This field isn't in the writer schema —
2376 * that's an error! TODO: Handle default
2377 * values!
2378 */
2379
2380 DEBUG("Field %s isn't in writer", field_name);
2381
2382 /* Allow missing fields in the writer. They
2383 * will default to zero. So skip over the
2384 * missing field, and continue building the
2385 * resolver. Note also that all missing values
2386 * are zero because avro_generic_value_new()
2387 * initializes all values of the reader to 0
2388 * on creation. This is a work-around because
2389 * default values are not implemented yet.
2390 */
2391 #ifdef AVRO_ALLOW_MISSING_FIELDS_IN_RESOLVED_WRITER
2392 continue;
2393 #else
2394 avro_set_error("Reader field %s doesn't appear in writer",
2395 field_name);
2396 goto error;
2397 #endif
2398 }
2399
2400 /*
2401 * Try to recursively resolve the schemas for this
2402 * field. If they're not compatible, that's an error.
2403 */
2404
2405 avro_schema_t wfield =
2406 avro_schema_record_field_get_by_index(wschema, wi);
2407 avro_resolved_writer_t *field_resolver =
2408 avro_resolved_writer_new_memoized(state, wfield, rfield);
2409
2410 if (field_resolver == NULL) {
2411 avro_prefix_error("Field %s isn't compatible: ", field_name);
2412 goto error;
2413 }
2414
2415 /*
2416 * Save the details for this field.
2417 */
2418
2419 DEBUG("Found match for field %s (%" PRIsz " in reader, %d in writer)",
2420 field_name, ri, wi);
2421 field_resolvers[wi] = field_resolver;
2422 index_mapping[wi] = ri;
2423 }
2424
2425 /*
2426 * We might not have found matches for all of the writer fields,
2427 * but that's okay — any extras will be ignored.
2428 */
2429
2430 rself->field_count = wfields;
2431 rself->field_offsets = field_offsets;
2432 rself->field_resolvers = field_resolvers;
2433 rself->index_mapping = index_mapping;
2434 *self = &rself->parent;
2435 return 0;
2436
2437 error:
2438 /*
2439 * Clean up any resolver we might have already created.
2440 */
2441
2442 avro_memoize_delete(&state->mem, wschema, root_rschema);
2443 avro_value_iface_decref(&rself->parent.parent);
2444
2445 {
2446 unsigned int i;
2447 for (i = 0; i < wfields; i++) {
2448 if (field_resolvers[i]) {
2449 avro_value_iface_decref(&field_resolvers[i]->parent);
2450 }
2451 }
2452 }
2453
2454 avro_free(field_resolvers, wfields * sizeof(avro_resolved_writer_t *));
2455 avro_free(field_offsets, wfields * sizeof(size_t));
2456 avro_free(index_mapping, wfields * sizeof(size_t));
2457 return EINVAL;
2458 }
2459
2460
2461 /*-----------------------------------------------------------------------
2462 * union
2463 */
2464
2465 typedef struct avro_resolved_union_writer {
2466 avro_resolved_writer_t parent;
2467 size_t branch_count;
2468 avro_resolved_writer_t **branch_resolvers;
2469 } avro_resolved_union_writer_t;
2470
2471 typedef struct avro_resolved_union_value {
2472 avro_value_t wrapped;
2473
2474 /** The currently active branch of the union. -1 if no branch
2475 * is selected. */
2476 int discriminant;
2477
2478 /* The rest of the struct is taken up by the inline storage
2479 * needed for the active branch. */
2480 } avro_resolved_union_value_t;
2481
2482 /** Return a pointer to the active branch within a union struct. */
2483 #define avro_resolved_union_branch(_union) \
2484 (((char *) (_union)) + sizeof(avro_resolved_union_value_t))
2485
2486
2487 static void
avro_resolved_union_writer_calculate_size(avro_resolved_writer_t * iface)2488 avro_resolved_union_writer_calculate_size(avro_resolved_writer_t *iface)
2489 {
2490 avro_resolved_union_writer_t *uiface =
2491 container_of(iface, avro_resolved_union_writer_t, parent);
2492
2493 /* Only calculate the size for any resolver once */
2494 iface->calculate_size = NULL;
2495
2496 DEBUG("Calculating size for %s->%s",
2497 avro_schema_type_name((iface)->wschema),
2498 avro_schema_type_name((iface)->rschema));
2499
2500 size_t i;
2501 size_t max_branch_size = 0;
2502 for (i = 0; i < uiface->branch_count; i++) {
2503 if (uiface->branch_resolvers[i] == NULL) {
2504 DEBUG("No match for writer union branch %" PRIsz, i);
2505 } else {
2506 avro_resolved_writer_calculate_size
2507 (uiface->branch_resolvers[i]);
2508 size_t branch_size =
2509 uiface->branch_resolvers[i]->instance_size;
2510 DEBUG("Writer branch %" PRIsz " has size %" PRIsz, i, branch_size);
2511 if (branch_size > max_branch_size) {
2512 max_branch_size = branch_size;
2513 }
2514 }
2515 }
2516
2517 DEBUG("Maximum branch size is %" PRIsz, max_branch_size);
2518 iface->instance_size =
2519 sizeof(avro_resolved_union_value_t) + max_branch_size;
2520 DEBUG("Total union size is %" PRIsz, iface->instance_size);
2521 }
2522
2523 static void
avro_resolved_union_writer_free_iface(avro_resolved_writer_t * iface,st_table * freeing)2524 avro_resolved_union_writer_free_iface(avro_resolved_writer_t *iface, st_table *freeing)
2525 {
2526 avro_resolved_union_writer_t *uiface =
2527 container_of(iface, avro_resolved_union_writer_t, parent);
2528
2529 if (uiface->branch_resolvers != NULL) {
2530 size_t i;
2531 for (i = 0; i < uiface->branch_count; i++) {
2532 if (uiface->branch_resolvers[i] != NULL) {
2533 free_resolver(uiface->branch_resolvers[i], freeing);
2534 }
2535 }
2536 avro_free(uiface->branch_resolvers,
2537 uiface->branch_count * sizeof(avro_resolved_writer_t *));
2538 }
2539
2540 avro_schema_decref(iface->wschema);
2541 avro_schema_decref(iface->rschema);
2542 avro_freet(avro_resolved_union_writer_t, iface);
2543 }
2544
2545 static int
avro_resolved_union_writer_init(const avro_resolved_writer_t * iface,void * vself)2546 avro_resolved_union_writer_init(const avro_resolved_writer_t *iface, void *vself)
2547 {
2548 AVRO_UNUSED(iface);
2549 avro_resolved_union_value_t *self = (avro_resolved_union_value_t *) vself;
2550 self->discriminant = -1;
2551 return 0;
2552 }
2553
2554 static void
avro_resolved_union_writer_done(const avro_resolved_writer_t * iface,void * vself)2555 avro_resolved_union_writer_done(const avro_resolved_writer_t *iface, void *vself)
2556 {
2557 const avro_resolved_union_writer_t *uiface =
2558 container_of(iface, avro_resolved_union_writer_t, parent);
2559 avro_resolved_union_value_t *self = (avro_resolved_union_value_t *) vself;
2560 if (self->discriminant >= 0) {
2561 avro_resolved_writer_done
2562 (uiface->branch_resolvers[self->discriminant],
2563 avro_resolved_union_branch(self));
2564 self->discriminant = -1;
2565 }
2566 }
2567
2568 static int
avro_resolved_union_writer_reset(const avro_resolved_writer_t * iface,void * vself)2569 avro_resolved_union_writer_reset(const avro_resolved_writer_t *iface, void *vself)
2570 {
2571 const avro_resolved_union_writer_t *uiface =
2572 container_of(iface, avro_resolved_union_writer_t, parent);
2573 avro_resolved_union_value_t *self = (avro_resolved_union_value_t *) vself;
2574
2575 /* Keep the same branch selected, for the common case that we're
2576 * about to reuse it. */
2577 if (self->discriminant >= 0) {
2578 return avro_resolved_writer_reset_wrappers
2579 (uiface->branch_resolvers[self->discriminant],
2580 avro_resolved_union_branch(self));
2581 }
2582
2583 return 0;
2584 }
2585
2586 static int
avro_resolved_union_writer_set_branch(const avro_value_iface_t * viface,void * vself,int discriminant,avro_value_t * branch)2587 avro_resolved_union_writer_set_branch(const avro_value_iface_t *viface,
2588 void *vself, int discriminant,
2589 avro_value_t *branch)
2590 {
2591 int rval;
2592 const avro_resolved_writer_t *iface =
2593 container_of(viface, avro_resolved_writer_t, parent);
2594 const avro_resolved_union_writer_t *uiface =
2595 container_of(iface, avro_resolved_union_writer_t, parent);
2596 avro_resolved_union_value_t *self = (avro_resolved_union_value_t *) vself;
2597
2598 DEBUG("Getting writer branch %d from union %p", discriminant, vself);
2599 avro_resolved_writer_t *branch_resolver =
2600 uiface->branch_resolvers[discriminant];
2601 if (branch_resolver == NULL) {
2602 DEBUG("Reader doesn't have branch, skipping");
2603 avro_set_error("Writer union branch %d is incompatible "
2604 "with reader schema \"%s\"",
2605 discriminant, avro_schema_type_name(iface->rschema));
2606 return EINVAL;
2607 }
2608
2609 if (self->discriminant == discriminant) {
2610 DEBUG("Writer branch %d already selected", discriminant);
2611 } else {
2612 if (self->discriminant >= 0) {
2613 DEBUG("Finalizing old writer branch %d", self->discriminant);
2614 avro_resolved_writer_done
2615 (uiface->branch_resolvers[self->discriminant],
2616 avro_resolved_union_branch(self));
2617 }
2618 DEBUG("Initializing writer branch %d", discriminant);
2619 check(rval, avro_resolved_writer_init
2620 (uiface->branch_resolvers[discriminant],
2621 avro_resolved_union_branch(self)));
2622 self->discriminant = discriminant;
2623 }
2624
2625 branch->iface = &branch_resolver->parent;
2626 branch->self = avro_resolved_union_branch(self);
2627 avro_value_t *branch_vself = (avro_value_t *) branch->self;
2628 *branch_vself = self->wrapped;
2629 return 0;
2630 }
2631
2632 static avro_resolved_union_writer_t *
avro_resolved_union_writer_create(avro_schema_t wschema,avro_schema_t rschema)2633 avro_resolved_union_writer_create(avro_schema_t wschema, avro_schema_t rschema)
2634 {
2635 avro_resolved_writer_t *self = (avro_resolved_writer_t *) avro_new(avro_resolved_union_writer_t);
2636 memset(self, 0, sizeof(avro_resolved_union_writer_t));
2637
2638 self->parent.incref_iface = avro_resolved_writer_incref_iface;
2639 self->parent.decref_iface = avro_resolved_writer_decref_iface;
2640 self->parent.incref = avro_resolved_writer_incref;
2641 self->parent.decref = avro_resolved_writer_decref;
2642 self->parent.reset = avro_resolved_writer_reset;
2643 self->parent.get_type = avro_resolved_writer_get_type;
2644 self->parent.get_schema = avro_resolved_writer_get_schema;
2645 self->parent.set_branch = avro_resolved_union_writer_set_branch;
2646
2647 self->refcount = 1;
2648 self->wschema = avro_schema_incref(wschema);
2649 self->rschema = avro_schema_incref(rschema);
2650 self->reader_union_branch = -1;
2651 self->calculate_size = avro_resolved_union_writer_calculate_size;
2652 self->free_iface = avro_resolved_union_writer_free_iface;
2653 self->init = avro_resolved_union_writer_init;
2654 self->done = avro_resolved_union_writer_done;
2655 self->reset_wrappers = avro_resolved_union_writer_reset;
2656 return container_of(self, avro_resolved_union_writer_t, parent);
2657 }
2658
2659 static avro_resolved_writer_t *
try_union(memoize_state_t * state,avro_schema_t wschema,avro_schema_t rschema)2660 try_union(memoize_state_t *state,
2661 avro_schema_t wschema, avro_schema_t rschema)
2662 {
2663 /*
2664 * For a writer union, we recursively try to resolve each branch
2665 * against the reader schema. This will work correctly whether
2666 * or not the reader is also a union — if the reader is a union,
2667 * then we'll resolve each (non-union) writer branch against the
2668 * reader union, which will be checked in our calls to
2669 * check_simple_writer below. The net result is that we might
2670 * end up trying every combination of writer and reader
2671 * branches, when looking for compatible schemas.
2672 *
2673 * Regardless of what the reader schema is, for each writer
2674 * branch, we stash away the recursive resolver into the
2675 * branch_resolvers array. A NULL entry in this array means
2676 * that that branch isn't compatible with the reader. This
2677 * isn't an immediate schema resolution error, since we allow
2678 * incompatible branches in the types as long as that branch
2679 * never appears in the actual data. We only return an error if
2680 * there are *no* branches that are compatible.
2681 */
2682
2683 size_t branch_count = avro_schema_union_size(wschema);
2684 DEBUG("Checking %" PRIsz "-branch writer union schema", branch_count);
2685
2686 avro_resolved_union_writer_t *uself =
2687 avro_resolved_union_writer_create(wschema, rschema);
2688 avro_memoize_set(&state->mem, wschema, rschema, uself);
2689
2690 avro_resolved_writer_t **branch_resolvers =
2691 (avro_resolved_writer_t **) avro_calloc(branch_count, sizeof(avro_resolved_writer_t *));
2692 int some_branch_compatible = 0;
2693
2694 size_t i;
2695 for (i = 0; i < branch_count; i++) {
2696 avro_schema_t branch_schema =
2697 avro_schema_union_branch(wschema, i);
2698
2699 DEBUG("Resolving writer union branch %" PRIsz " (%s)", i,
2700 avro_schema_type_name(branch_schema));
2701
2702 /*
2703 * Try to recursively resolve this branch of the writer
2704 * union. Don't raise an error if this fails — it's
2705 * okay for some of the branches to not be compatible
2706 * with the reader, as long as those branches never
2707 * appear in the input.
2708 */
2709
2710 branch_resolvers[i] =
2711 avro_resolved_writer_new_memoized(state, branch_schema, rschema);
2712 if (branch_resolvers[i] == NULL) {
2713 DEBUG("No match for writer union branch %" PRIsz, i);
2714 } else {
2715 DEBUG("Found match for writer union branch %" PRIsz, i);
2716 some_branch_compatible = 1;
2717 }
2718 }
2719
2720 /*
2721 * As long as there's at least one branch that's compatible with
2722 * the reader, then we consider this schema resolution a
2723 * success.
2724 */
2725
2726 if (!some_branch_compatible) {
2727 DEBUG("No writer union branches match");
2728 avro_set_error("No branches in the writer are compatible "
2729 "with reader schema %s",
2730 avro_schema_type_name(rschema));
2731 goto error;
2732 }
2733
2734 uself->branch_count = branch_count;
2735 uself->branch_resolvers = branch_resolvers;
2736 return &uself->parent;
2737
2738 error:
2739 /*
2740 * Clean up any resolver we might have already created.
2741 */
2742
2743 avro_memoize_delete(&state->mem, wschema, rschema);
2744 avro_value_iface_decref(&uself->parent.parent);
2745
2746 {
2747 unsigned int i;
2748 for (i = 0; i < branch_count; i++) {
2749 if (branch_resolvers[i]) {
2750 avro_value_iface_decref(&branch_resolvers[i]->parent);
2751 }
2752 }
2753 }
2754
2755 avro_free(branch_resolvers, branch_count * sizeof(avro_resolved_writer_t *));
2756 return NULL;
2757 }
2758
2759
2760 /*-----------------------------------------------------------------------
2761 * Schema type dispatcher
2762 */
2763
2764 static avro_resolved_writer_t *
avro_resolved_writer_new_memoized(memoize_state_t * state,avro_schema_t wschema,avro_schema_t rschema)2765 avro_resolved_writer_new_memoized(memoize_state_t *state,
2766 avro_schema_t wschema, avro_schema_t rschema)
2767 {
2768 check_param(NULL, is_avro_schema(wschema), "writer schema");
2769 check_param(NULL, is_avro_schema(rschema), "reader schema");
2770
2771 skip_links(rschema);
2772
2773 /*
2774 * First see if we've already matched these two schemas. If so,
2775 * just return that resolver.
2776 */
2777
2778 avro_resolved_writer_t *saved = NULL;
2779 if (avro_memoize_get(&state->mem, wschema, rschema, (void **) &saved)) {
2780 DEBUG("Already resolved %s%s%s->%s",
2781 is_avro_link(wschema)? "[": "",
2782 avro_schema_type_name(wschema),
2783 is_avro_link(wschema)? "]": "",
2784 avro_schema_type_name(rschema));
2785 avro_value_iface_incref(&saved->parent);
2786 return saved;
2787 } else {
2788 DEBUG("Resolving %s%s%s->%s",
2789 is_avro_link(wschema)? "[": "",
2790 avro_schema_type_name(wschema),
2791 is_avro_link(wschema)? "]": "",
2792 avro_schema_type_name(rschema));
2793 }
2794
2795 /*
2796 * Otherwise we have some work to do.
2797 */
2798
2799 switch (avro_typeof(wschema))
2800 {
2801 case AVRO_BOOLEAN:
2802 check_simple_writer(state, wschema, rschema, boolean);
2803 return NULL;
2804
2805 case AVRO_BYTES:
2806 check_simple_writer(state, wschema, rschema, bytes);
2807 return NULL;
2808
2809 case AVRO_DOUBLE:
2810 check_simple_writer(state, wschema, rschema, double);
2811 return NULL;
2812
2813 case AVRO_FLOAT:
2814 check_simple_writer(state, wschema, rschema, float);
2815 return NULL;
2816
2817 case AVRO_INT32:
2818 check_simple_writer(state, wschema, rschema, int);
2819 return NULL;
2820
2821 case AVRO_INT64:
2822 check_simple_writer(state, wschema, rschema, long);
2823 return NULL;
2824
2825 case AVRO_NULL:
2826 check_simple_writer(state, wschema, rschema, null);
2827 return NULL;
2828
2829 case AVRO_STRING:
2830 check_simple_writer(state, wschema, rschema, string);
2831 return NULL;
2832
2833 case AVRO_ARRAY:
2834 check_simple_writer(state, wschema, rschema, array);
2835 return NULL;
2836
2837 case AVRO_ENUM:
2838 check_simple_writer(state, wschema, rschema, enum);
2839 return NULL;
2840
2841 case AVRO_FIXED:
2842 check_simple_writer(state, wschema, rschema, fixed);
2843 return NULL;
2844
2845 case AVRO_MAP:
2846 check_simple_writer(state, wschema, rschema, map);
2847 return NULL;
2848
2849 case AVRO_RECORD:
2850 check_simple_writer(state, wschema, rschema, record);
2851 return NULL;
2852
2853 case AVRO_UNION:
2854 return try_union(state, wschema, rschema);
2855
2856 case AVRO_LINK:
2857 check_simple_writer(state, wschema, rschema, link);
2858 return NULL;
2859
2860 default:
2861 avro_set_error("Unknown schema type");
2862 return NULL;
2863 }
2864
2865 return NULL;
2866 }
2867
2868
2869 avro_value_iface_t *
avro_resolved_writer_new(avro_schema_t wschema,avro_schema_t rschema)2870 avro_resolved_writer_new(avro_schema_t wschema, avro_schema_t rschema)
2871 {
2872 /*
2873 * Create a state to keep track of the value implementations
2874 * that we create for each subschema.
2875 */
2876
2877 memoize_state_t state;
2878 avro_memoize_init(&state.mem);
2879 state.links = NULL;
2880
2881 /*
2882 * Create the value implementations.
2883 */
2884
2885 avro_resolved_writer_t *result =
2886 avro_resolved_writer_new_memoized(&state, wschema, rschema);
2887 if (result == NULL) {
2888 avro_memoize_done(&state.mem);
2889 return NULL;
2890 }
2891
2892 /*
2893 * Fix up any link schemas so that their value implementations
2894 * point to their target schemas' implementations.
2895 */
2896
2897 avro_resolved_writer_calculate_size(result);
2898 while (state.links != NULL) {
2899 avro_resolved_link_writer_t *liface = state.links;
2900 avro_resolved_writer_calculate_size(liface->target_resolver);
2901 state.links = liface->next;
2902 liface->next = NULL;
2903 }
2904
2905 /*
2906 * And now we can return.
2907 */
2908
2909 avro_memoize_done(&state.mem);
2910 return &result->parent;
2911 }
2912