google-protobuf 3.0.0.alpha.5.0.3-x86-linux

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of google-protobuf might be problematic. Click here for more details.

@@ -0,0 +1,863 @@
1
+ // Protocol Buffers - Google's data interchange format
2
+ // Copyright 2014 Google Inc. All rights reserved.
3
+ // https://developers.google.com/protocol-buffers/
4
+ //
5
+ // Redistribution and use in source and binary forms, with or without
6
+ // modification, are permitted provided that the following conditions are
7
+ // met:
8
+ //
9
+ // * Redistributions of source code must retain the above copyright
10
+ // notice, this list of conditions and the following disclaimer.
11
+ // * Redistributions in binary form must reproduce the above
12
+ // copyright notice, this list of conditions and the following disclaimer
13
+ // in the documentation and/or other materials provided with the
14
+ // distribution.
15
+ // * Neither the name of Google Inc. nor the names of its
16
+ // contributors may be used to endorse or promote products derived from
17
+ // this software without specific prior written permission.
18
+ //
19
+ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
+ // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
+ // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
+ // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23
+ // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
+ // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
+ // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
+ // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
+ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
+ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+
31
+ #include "protobuf.h"
32
+
33
+ #include <math.h>
34
+
35
+ #include <ruby/encoding.h>
36
+
37
+ // -----------------------------------------------------------------------------
38
+ // Ruby <-> native slot management.
39
+ // -----------------------------------------------------------------------------
40
+
41
+ #define DEREF(memory, type) *(type*)(memory)
42
+
43
+ size_t native_slot_size(upb_fieldtype_t type) {
44
+ switch (type) {
45
+ case UPB_TYPE_FLOAT: return 4;
46
+ case UPB_TYPE_DOUBLE: return 8;
47
+ case UPB_TYPE_BOOL: return 1;
48
+ case UPB_TYPE_STRING: return sizeof(VALUE);
49
+ case UPB_TYPE_BYTES: return sizeof(VALUE);
50
+ case UPB_TYPE_MESSAGE: return sizeof(VALUE);
51
+ case UPB_TYPE_ENUM: return 4;
52
+ case UPB_TYPE_INT32: return 4;
53
+ case UPB_TYPE_INT64: return 8;
54
+ case UPB_TYPE_UINT32: return 4;
55
+ case UPB_TYPE_UINT64: return 8;
56
+ default: return 0;
57
+ }
58
+ }
59
+
60
+ static bool is_ruby_num(VALUE value) {
61
+ return (TYPE(value) == T_FLOAT ||
62
+ TYPE(value) == T_FIXNUM ||
63
+ TYPE(value) == T_BIGNUM);
64
+ }
65
+
66
+ void native_slot_check_int_range_precision(upb_fieldtype_t type, VALUE val) {
67
+ if (!is_ruby_num(val)) {
68
+ rb_raise(rb_eTypeError, "Expected number type for integral field.");
69
+ }
70
+
71
+ // NUM2{INT,UINT,LL,ULL} macros do the appropriate range checks on upper
72
+ // bound; we just need to do precision checks (i.e., disallow rounding) and
73
+ // check for < 0 on unsigned types.
74
+ if (TYPE(val) == T_FLOAT) {
75
+ double dbl_val = NUM2DBL(val);
76
+ if (floor(dbl_val) != dbl_val) {
77
+ rb_raise(rb_eRangeError,
78
+ "Non-integral floating point value assigned to integer field.");
79
+ }
80
+ }
81
+ if (type == UPB_TYPE_UINT32 || type == UPB_TYPE_UINT64) {
82
+ if (NUM2DBL(val) < 0) {
83
+ rb_raise(rb_eRangeError,
84
+ "Assigning negative value to unsigned integer field.");
85
+ }
86
+ }
87
+ }
88
+
89
+ void native_slot_validate_string_encoding(upb_fieldtype_t type, VALUE value) {
90
+ bool bad_encoding = false;
91
+ rb_encoding* string_encoding = rb_enc_from_index(ENCODING_GET(value));
92
+ if (type == UPB_TYPE_STRING) {
93
+ bad_encoding =
94
+ string_encoding != kRubyStringUtf8Encoding &&
95
+ string_encoding != kRubyStringASCIIEncoding;
96
+ } else {
97
+ bad_encoding =
98
+ string_encoding != kRubyString8bitEncoding;
99
+ }
100
+ // Check that encoding is UTF-8 or ASCII (for string fields) or ASCII-8BIT
101
+ // (for bytes fields).
102
+ if (bad_encoding) {
103
+ rb_raise(rb_eTypeError, "Encoding for '%s' fields must be %s (was %s)",
104
+ (type == UPB_TYPE_STRING) ? "string" : "bytes",
105
+ (type == UPB_TYPE_STRING) ? "UTF-8 or ASCII" : "ASCII-8BIT",
106
+ rb_enc_name(string_encoding));
107
+ }
108
+ }
109
+
110
+ void native_slot_set(upb_fieldtype_t type, VALUE type_class,
111
+ void* memory, VALUE value) {
112
+ native_slot_set_value_and_case(type, type_class, memory, value, NULL, 0);
113
+ }
114
+
115
+ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class,
116
+ void* memory, VALUE value,
117
+ uint32_t* case_memory,
118
+ uint32_t case_number) {
119
+ // Note that in order to atomically change the value in memory and the case
120
+ // value (w.r.t. Ruby VM calls), we must set the value at |memory| only after
121
+ // all Ruby VM calls are complete. The case is then set at the bottom of this
122
+ // function.
123
+ switch (type) {
124
+ case UPB_TYPE_FLOAT:
125
+ if (!is_ruby_num(value)) {
126
+ rb_raise(rb_eTypeError, "Expected number type for float field.");
127
+ }
128
+ DEREF(memory, float) = NUM2DBL(value);
129
+ break;
130
+ case UPB_TYPE_DOUBLE:
131
+ if (!is_ruby_num(value)) {
132
+ rb_raise(rb_eTypeError, "Expected number type for double field.");
133
+ }
134
+ DEREF(memory, double) = NUM2DBL(value);
135
+ break;
136
+ case UPB_TYPE_BOOL: {
137
+ int8_t val = -1;
138
+ if (value == Qtrue) {
139
+ val = 1;
140
+ } else if (value == Qfalse) {
141
+ val = 0;
142
+ } else {
143
+ rb_raise(rb_eTypeError, "Invalid argument for boolean field.");
144
+ }
145
+ DEREF(memory, int8_t) = val;
146
+ break;
147
+ }
148
+ case UPB_TYPE_STRING:
149
+ case UPB_TYPE_BYTES: {
150
+ if (CLASS_OF(value) != rb_cString) {
151
+ rb_raise(rb_eTypeError, "Invalid argument for string field.");
152
+ }
153
+ native_slot_validate_string_encoding(type, value);
154
+ DEREF(memory, VALUE) = value;
155
+ break;
156
+ }
157
+ case UPB_TYPE_MESSAGE: {
158
+ if (CLASS_OF(value) == CLASS_OF(Qnil)) {
159
+ value = Qnil;
160
+ } else if (CLASS_OF(value) != type_class) {
161
+ rb_raise(rb_eTypeError,
162
+ "Invalid type %s to assign to submessage field.",
163
+ rb_class2name(CLASS_OF(value)));
164
+ }
165
+ DEREF(memory, VALUE) = value;
166
+ break;
167
+ }
168
+ case UPB_TYPE_ENUM: {
169
+ int32_t int_val = 0;
170
+ if (!is_ruby_num(value) && TYPE(value) != T_SYMBOL) {
171
+ rb_raise(rb_eTypeError,
172
+ "Expected number or symbol type for enum field.");
173
+ }
174
+ if (TYPE(value) == T_SYMBOL) {
175
+ // Ensure that the given symbol exists in the enum module.
176
+ VALUE lookup = rb_funcall(type_class, rb_intern("resolve"), 1, value);
177
+ if (lookup == Qnil) {
178
+ rb_raise(rb_eRangeError, "Unknown symbol value for enum field.");
179
+ } else {
180
+ int_val = NUM2INT(lookup);
181
+ }
182
+ } else {
183
+ native_slot_check_int_range_precision(UPB_TYPE_INT32, value);
184
+ int_val = NUM2INT(value);
185
+ }
186
+ DEREF(memory, int32_t) = int_val;
187
+ break;
188
+ }
189
+ case UPB_TYPE_INT32:
190
+ case UPB_TYPE_INT64:
191
+ case UPB_TYPE_UINT32:
192
+ case UPB_TYPE_UINT64:
193
+ native_slot_check_int_range_precision(type, value);
194
+ switch (type) {
195
+ case UPB_TYPE_INT32:
196
+ DEREF(memory, int32_t) = NUM2INT(value);
197
+ break;
198
+ case UPB_TYPE_INT64:
199
+ DEREF(memory, int64_t) = NUM2LL(value);
200
+ break;
201
+ case UPB_TYPE_UINT32:
202
+ DEREF(memory, uint32_t) = NUM2UINT(value);
203
+ break;
204
+ case UPB_TYPE_UINT64:
205
+ DEREF(memory, uint64_t) = NUM2ULL(value);
206
+ break;
207
+ default:
208
+ break;
209
+ }
210
+ break;
211
+ default:
212
+ break;
213
+ }
214
+
215
+ if (case_memory != NULL) {
216
+ *case_memory = case_number;
217
+ }
218
+ }
219
+
220
+ VALUE native_slot_get(upb_fieldtype_t type,
221
+ VALUE type_class,
222
+ const void* memory) {
223
+ switch (type) {
224
+ case UPB_TYPE_FLOAT:
225
+ return DBL2NUM(DEREF(memory, float));
226
+ case UPB_TYPE_DOUBLE:
227
+ return DBL2NUM(DEREF(memory, double));
228
+ case UPB_TYPE_BOOL:
229
+ return DEREF(memory, int8_t) ? Qtrue : Qfalse;
230
+ case UPB_TYPE_STRING:
231
+ case UPB_TYPE_BYTES:
232
+ case UPB_TYPE_MESSAGE:
233
+ return DEREF(memory, VALUE);
234
+ case UPB_TYPE_ENUM: {
235
+ int32_t val = DEREF(memory, int32_t);
236
+ VALUE symbol = enum_lookup(type_class, INT2NUM(val));
237
+ if (symbol == Qnil) {
238
+ return INT2NUM(val);
239
+ } else {
240
+ return symbol;
241
+ }
242
+ }
243
+ case UPB_TYPE_INT32:
244
+ return INT2NUM(DEREF(memory, int32_t));
245
+ case UPB_TYPE_INT64:
246
+ return LL2NUM(DEREF(memory, int64_t));
247
+ case UPB_TYPE_UINT32:
248
+ return UINT2NUM(DEREF(memory, uint32_t));
249
+ case UPB_TYPE_UINT64:
250
+ return ULL2NUM(DEREF(memory, uint64_t));
251
+ default:
252
+ return Qnil;
253
+ }
254
+ }
255
+
256
+ void native_slot_init(upb_fieldtype_t type, void* memory) {
257
+ switch (type) {
258
+ case UPB_TYPE_FLOAT:
259
+ DEREF(memory, float) = 0.0;
260
+ break;
261
+ case UPB_TYPE_DOUBLE:
262
+ DEREF(memory, double) = 0.0;
263
+ break;
264
+ case UPB_TYPE_BOOL:
265
+ DEREF(memory, int8_t) = 0;
266
+ break;
267
+ case UPB_TYPE_STRING:
268
+ case UPB_TYPE_BYTES:
269
+ DEREF(memory, VALUE) = rb_str_new2("");
270
+ rb_enc_associate(DEREF(memory, VALUE), (type == UPB_TYPE_BYTES) ?
271
+ kRubyString8bitEncoding : kRubyStringUtf8Encoding);
272
+ break;
273
+ case UPB_TYPE_MESSAGE:
274
+ DEREF(memory, VALUE) = Qnil;
275
+ break;
276
+ case UPB_TYPE_ENUM:
277
+ case UPB_TYPE_INT32:
278
+ DEREF(memory, int32_t) = 0;
279
+ break;
280
+ case UPB_TYPE_INT64:
281
+ DEREF(memory, int64_t) = 0;
282
+ break;
283
+ case UPB_TYPE_UINT32:
284
+ DEREF(memory, uint32_t) = 0;
285
+ break;
286
+ case UPB_TYPE_UINT64:
287
+ DEREF(memory, uint64_t) = 0;
288
+ break;
289
+ default:
290
+ break;
291
+ }
292
+ }
293
+
294
+ void native_slot_mark(upb_fieldtype_t type, void* memory) {
295
+ switch (type) {
296
+ case UPB_TYPE_STRING:
297
+ case UPB_TYPE_BYTES:
298
+ case UPB_TYPE_MESSAGE:
299
+ rb_gc_mark(DEREF(memory, VALUE));
300
+ break;
301
+ default:
302
+ break;
303
+ }
304
+ }
305
+
306
+ void native_slot_dup(upb_fieldtype_t type, void* to, void* from) {
307
+ memcpy(to, from, native_slot_size(type));
308
+ }
309
+
310
+ void native_slot_deep_copy(upb_fieldtype_t type, void* to, void* from) {
311
+ switch (type) {
312
+ case UPB_TYPE_STRING:
313
+ case UPB_TYPE_BYTES: {
314
+ VALUE from_val = DEREF(from, VALUE);
315
+ DEREF(to, VALUE) = (from_val != Qnil) ?
316
+ rb_funcall(from_val, rb_intern("dup"), 0) : Qnil;
317
+ break;
318
+ }
319
+ case UPB_TYPE_MESSAGE: {
320
+ VALUE from_val = DEREF(from, VALUE);
321
+ DEREF(to, VALUE) = (from_val != Qnil) ?
322
+ Message_deep_copy(from_val) : Qnil;
323
+ break;
324
+ }
325
+ default:
326
+ memcpy(to, from, native_slot_size(type));
327
+ }
328
+ }
329
+
330
+ bool native_slot_eq(upb_fieldtype_t type, void* mem1, void* mem2) {
331
+ switch (type) {
332
+ case UPB_TYPE_STRING:
333
+ case UPB_TYPE_BYTES:
334
+ case UPB_TYPE_MESSAGE: {
335
+ VALUE val1 = DEREF(mem1, VALUE);
336
+ VALUE val2 = DEREF(mem2, VALUE);
337
+ VALUE ret = rb_funcall(val1, rb_intern("=="), 1, val2);
338
+ return ret == Qtrue;
339
+ }
340
+ default:
341
+ return !memcmp(mem1, mem2, native_slot_size(type));
342
+ }
343
+ }
344
+
345
+ // -----------------------------------------------------------------------------
346
+ // Map field utilities.
347
+ // -----------------------------------------------------------------------------
348
+
349
+ const upb_msgdef* tryget_map_entry_msgdef(const upb_fielddef* field) {
350
+ const upb_msgdef* subdef;
351
+ if (upb_fielddef_label(field) != UPB_LABEL_REPEATED ||
352
+ upb_fielddef_type(field) != UPB_TYPE_MESSAGE) {
353
+ return NULL;
354
+ }
355
+ subdef = upb_fielddef_msgsubdef(field);
356
+ return upb_msgdef_mapentry(subdef) ? subdef : NULL;
357
+ }
358
+
359
+ const upb_msgdef *map_entry_msgdef(const upb_fielddef* field) {
360
+ const upb_msgdef* subdef = tryget_map_entry_msgdef(field);
361
+ assert(subdef);
362
+ return subdef;
363
+ }
364
+
365
+ bool is_map_field(const upb_fielddef *field) {
366
+ return tryget_map_entry_msgdef(field) != NULL;
367
+ }
368
+
369
+ const upb_fielddef* map_field_key(const upb_fielddef* field) {
370
+ const upb_msgdef* subdef = map_entry_msgdef(field);
371
+ return map_entry_key(subdef);
372
+ }
373
+
374
+ const upb_fielddef* map_field_value(const upb_fielddef* field) {
375
+ const upb_msgdef* subdef = map_entry_msgdef(field);
376
+ return map_entry_value(subdef);
377
+ }
378
+
379
+ const upb_fielddef* map_entry_key(const upb_msgdef* msgdef) {
380
+ const upb_fielddef* key_field = upb_msgdef_itof(msgdef, MAP_KEY_FIELD);
381
+ assert(key_field != NULL);
382
+ return key_field;
383
+ }
384
+
385
+ const upb_fielddef* map_entry_value(const upb_msgdef* msgdef) {
386
+ const upb_fielddef* value_field = upb_msgdef_itof(msgdef, MAP_VALUE_FIELD);
387
+ assert(value_field != NULL);
388
+ return value_field;
389
+ }
390
+
391
+ // -----------------------------------------------------------------------------
392
+ // Memory layout management.
393
+ // -----------------------------------------------------------------------------
394
+
395
+ static size_t align_up_to(size_t offset, size_t granularity) {
396
+ // Granularity must be a power of two.
397
+ return (offset + granularity - 1) & ~(granularity - 1);
398
+ }
399
+
400
+ MessageLayout* create_layout(const upb_msgdef* msgdef) {
401
+ MessageLayout* layout = ALLOC(MessageLayout);
402
+ int nfields = upb_msgdef_numfields(msgdef);
403
+ upb_msg_field_iter it;
404
+ upb_msg_oneof_iter oit;
405
+ size_t off = 0;
406
+
407
+ layout->fields = ALLOC_N(MessageField, nfields);
408
+
409
+ for (upb_msg_field_begin(&it, msgdef);
410
+ !upb_msg_field_done(&it);
411
+ upb_msg_field_next(&it)) {
412
+ const upb_fielddef* field = upb_msg_iter_field(&it);
413
+ size_t field_size;
414
+
415
+ if (upb_fielddef_containingoneof(field)) {
416
+ // Oneofs are handled separately below.
417
+ continue;
418
+ }
419
+
420
+ // Allocate |field_size| bytes for this field in the layout.
421
+ field_size = 0;
422
+ if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
423
+ field_size = sizeof(VALUE);
424
+ } else {
425
+ field_size = native_slot_size(upb_fielddef_type(field));
426
+ }
427
+ // Align current offset up to |size| granularity.
428
+ off = align_up_to(off, field_size);
429
+ layout->fields[upb_fielddef_index(field)].offset = off;
430
+ layout->fields[upb_fielddef_index(field)].case_offset =
431
+ MESSAGE_FIELD_NO_CASE;
432
+ off += field_size;
433
+ }
434
+
435
+ // Handle oneofs now -- we iterate over oneofs specifically and allocate only
436
+ // one slot per oneof.
437
+ //
438
+ // We assign all value slots first, then pack the 'case' fields at the end,
439
+ // since in the common case (modern 64-bit platform) these are 8 bytes and 4
440
+ // bytes respectively and we want to avoid alignment overhead.
441
+ //
442
+ // Note that we reserve 4 bytes (a uint32) per 'case' slot because the value
443
+ // space for oneof cases is conceptually as wide as field tag numbers. In
444
+ // practice, it's unlikely that a oneof would have more than e.g. 256 or 64K
445
+ // members (8 or 16 bits respectively), so conceivably we could assign
446
+ // consecutive case numbers and then pick a smaller oneof case slot size, but
447
+ // the complexity to implement this indirection is probably not worthwhile.
448
+ for (upb_msg_oneof_begin(&oit, msgdef);
449
+ !upb_msg_oneof_done(&oit);
450
+ upb_msg_oneof_next(&oit)) {
451
+ const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit);
452
+ upb_oneof_iter fit;
453
+
454
+ // Always allocate NATIVE_SLOT_MAX_SIZE bytes, but share the slot between
455
+ // all fields.
456
+ size_t field_size = NATIVE_SLOT_MAX_SIZE;
457
+ // Align the offset.
458
+ off = align_up_to(off, field_size);
459
+ // Assign all fields in the oneof this same offset.
460
+ for (upb_oneof_begin(&fit, oneof);
461
+ !upb_oneof_done(&fit);
462
+ upb_oneof_next(&fit)) {
463
+ const upb_fielddef* field = upb_oneof_iter_field(&fit);
464
+ layout->fields[upb_fielddef_index(field)].offset = off;
465
+ }
466
+ off += field_size;
467
+ }
468
+
469
+ // Now the case fields.
470
+ for (upb_msg_oneof_begin(&oit, msgdef);
471
+ !upb_msg_oneof_done(&oit);
472
+ upb_msg_oneof_next(&oit)) {
473
+ const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit);
474
+ upb_oneof_iter fit;
475
+
476
+ size_t field_size = sizeof(uint32_t);
477
+ // Align the offset.
478
+ off = (off + field_size - 1) & ~(field_size - 1);
479
+ // Assign all fields in the oneof this same offset.
480
+ for (upb_oneof_begin(&fit, oneof);
481
+ !upb_oneof_done(&fit);
482
+ upb_oneof_next(&fit)) {
483
+ const upb_fielddef* field = upb_oneof_iter_field(&fit);
484
+ layout->fields[upb_fielddef_index(field)].case_offset = off;
485
+ }
486
+ off += field_size;
487
+ }
488
+
489
+ layout->size = off;
490
+
491
+ layout->msgdef = msgdef;
492
+ upb_msgdef_ref(layout->msgdef, &layout->msgdef);
493
+
494
+ return layout;
495
+ }
496
+
497
+ void free_layout(MessageLayout* layout) {
498
+ xfree(layout->fields);
499
+ upb_msgdef_unref(layout->msgdef, &layout->msgdef);
500
+ xfree(layout);
501
+ }
502
+
503
+ VALUE field_type_class(const upb_fielddef* field) {
504
+ VALUE type_class = Qnil;
505
+ if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
506
+ VALUE submsgdesc =
507
+ get_def_obj(upb_fielddef_subdef(field));
508
+ type_class = Descriptor_msgclass(submsgdesc);
509
+ } else if (upb_fielddef_type(field) == UPB_TYPE_ENUM) {
510
+ VALUE subenumdesc =
511
+ get_def_obj(upb_fielddef_subdef(field));
512
+ type_class = EnumDescriptor_enummodule(subenumdesc);
513
+ }
514
+ return type_class;
515
+ }
516
+
517
+ static void* slot_memory(MessageLayout* layout,
518
+ const void* storage,
519
+ const upb_fielddef* field) {
520
+ return ((uint8_t *)storage) +
521
+ layout->fields[upb_fielddef_index(field)].offset;
522
+ }
523
+
524
+ static uint32_t* slot_oneof_case(MessageLayout* layout,
525
+ const void* storage,
526
+ const upb_fielddef* field) {
527
+ return (uint32_t *)(((uint8_t *)storage) +
528
+ layout->fields[upb_fielddef_index(field)].case_offset);
529
+ }
530
+
531
+
532
+ VALUE layout_get(MessageLayout* layout,
533
+ const void* storage,
534
+ const upb_fielddef* field) {
535
+ void* memory = slot_memory(layout, storage, field);
536
+ uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
537
+
538
+ if (upb_fielddef_containingoneof(field)) {
539
+ if (*oneof_case != upb_fielddef_number(field)) {
540
+ return Qnil;
541
+ }
542
+ return native_slot_get(upb_fielddef_type(field),
543
+ field_type_class(field),
544
+ memory);
545
+ } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
546
+ return *((VALUE *)memory);
547
+ } else {
548
+ return native_slot_get(upb_fielddef_type(field),
549
+ field_type_class(field),
550
+ memory);
551
+ }
552
+ }
553
+
554
+ static void check_repeated_field_type(VALUE val, const upb_fielddef* field) {
555
+ RepeatedField* self;
556
+ assert(upb_fielddef_label(field) == UPB_LABEL_REPEATED);
557
+
558
+ if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
559
+ RTYPEDDATA_TYPE(val) != &RepeatedField_type) {
560
+ rb_raise(rb_eTypeError, "Expected repeated field array");
561
+ }
562
+
563
+ self = ruby_to_RepeatedField(val);
564
+ if (self->field_type != upb_fielddef_type(field)) {
565
+ rb_raise(rb_eTypeError, "Repeated field array has wrong element type");
566
+ }
567
+
568
+ if (self->field_type == UPB_TYPE_MESSAGE ||
569
+ self->field_type == UPB_TYPE_ENUM) {
570
+ if (self->field_type_class !=
571
+ get_def_obj(upb_fielddef_subdef(field))) {
572
+ rb_raise(rb_eTypeError,
573
+ "Repeated field array has wrong message/enum class");
574
+ }
575
+ }
576
+ }
577
+
578
+ static void check_map_field_type(VALUE val, const upb_fielddef* field) {
579
+ const upb_fielddef* key_field = map_field_key(field);
580
+ const upb_fielddef* value_field = map_field_value(field);
581
+ Map* self;
582
+
583
+ if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
584
+ RTYPEDDATA_TYPE(val) != &Map_type) {
585
+ rb_raise(rb_eTypeError, "Expected Map instance");
586
+ }
587
+
588
+ self = ruby_to_Map(val);
589
+ if (self->key_type != upb_fielddef_type(key_field)) {
590
+ rb_raise(rb_eTypeError, "Map key type does not match field's key type");
591
+ }
592
+ if (self->value_type != upb_fielddef_type(value_field)) {
593
+ rb_raise(rb_eTypeError, "Map value type does not match field's value type");
594
+ }
595
+ if (upb_fielddef_type(value_field) == UPB_TYPE_MESSAGE ||
596
+ upb_fielddef_type(value_field) == UPB_TYPE_ENUM) {
597
+ if (self->value_type_class !=
598
+ get_def_obj(upb_fielddef_subdef(value_field))) {
599
+ rb_raise(rb_eTypeError,
600
+ "Map value type has wrong message/enum class");
601
+ }
602
+ }
603
+ }
604
+
605
+
606
+ void layout_set(MessageLayout* layout,
607
+ void* storage,
608
+ const upb_fielddef* field,
609
+ VALUE val) {
610
+ void* memory = slot_memory(layout, storage, field);
611
+ uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
612
+
613
+ if (upb_fielddef_containingoneof(field)) {
614
+ if (val == Qnil) {
615
+ // Assigning nil to a oneof field clears the oneof completely.
616
+ *oneof_case = ONEOF_CASE_NONE;
617
+ memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
618
+ } else {
619
+ // The transition between field types for a single oneof (union) slot is
620
+ // somewhat complex because we need to ensure that a GC triggered at any
621
+ // point by a call into the Ruby VM sees a valid state for this field and
622
+ // does not either go off into the weeds (following what it thinks is a
623
+ // VALUE but is actually a different field type) or miss an object (seeing
624
+ // what it thinks is a primitive field but is actually a VALUE for the new
625
+ // field type).
626
+ //
627
+ // In order for the transition to be safe, the oneof case slot must be in
628
+ // sync with the value slot whenever the Ruby VM has been called. Thus, we
629
+ // use native_slot_set_value_and_case(), which ensures that both the value
630
+ // and case number are altered atomically (w.r.t. the Ruby VM).
631
+ native_slot_set_value_and_case(
632
+ upb_fielddef_type(field), field_type_class(field),
633
+ memory, val,
634
+ oneof_case, upb_fielddef_number(field));
635
+ }
636
+ } else if (is_map_field(field)) {
637
+ check_map_field_type(val, field);
638
+ DEREF(memory, VALUE) = val;
639
+ } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
640
+ check_repeated_field_type(val, field);
641
+ DEREF(memory, VALUE) = val;
642
+ } else {
643
+ native_slot_set(upb_fielddef_type(field), field_type_class(field),
644
+ memory, val);
645
+ }
646
+ }
647
+
648
+ void layout_init(MessageLayout* layout,
649
+ void* storage) {
650
+ upb_msg_field_iter it;
651
+ for (upb_msg_field_begin(&it, layout->msgdef);
652
+ !upb_msg_field_done(&it);
653
+ upb_msg_field_next(&it)) {
654
+ const upb_fielddef* field = upb_msg_iter_field(&it);
655
+ void* memory = slot_memory(layout, storage, field);
656
+ uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
657
+
658
+ if (upb_fielddef_containingoneof(field)) {
659
+ memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
660
+ *oneof_case = ONEOF_CASE_NONE;
661
+ } else if (is_map_field(field)) {
662
+ VALUE map = Qnil;
663
+
664
+ const upb_fielddef* key_field = map_field_key(field);
665
+ const upb_fielddef* value_field = map_field_value(field);
666
+ VALUE type_class = field_type_class(value_field);
667
+
668
+ if (type_class != Qnil) {
669
+ VALUE args[3] = {
670
+ fieldtype_to_ruby(upb_fielddef_type(key_field)),
671
+ fieldtype_to_ruby(upb_fielddef_type(value_field)),
672
+ type_class,
673
+ };
674
+ map = rb_class_new_instance(3, args, cMap);
675
+ } else {
676
+ VALUE args[2] = {
677
+ fieldtype_to_ruby(upb_fielddef_type(key_field)),
678
+ fieldtype_to_ruby(upb_fielddef_type(value_field)),
679
+ };
680
+ map = rb_class_new_instance(2, args, cMap);
681
+ }
682
+
683
+ DEREF(memory, VALUE) = map;
684
+ } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
685
+ VALUE ary = Qnil;
686
+
687
+ VALUE type_class = field_type_class(field);
688
+
689
+ if (type_class != Qnil) {
690
+ VALUE args[2] = {
691
+ fieldtype_to_ruby(upb_fielddef_type(field)),
692
+ type_class,
693
+ };
694
+ ary = rb_class_new_instance(2, args, cRepeatedField);
695
+ } else {
696
+ VALUE args[1] = { fieldtype_to_ruby(upb_fielddef_type(field)) };
697
+ ary = rb_class_new_instance(1, args, cRepeatedField);
698
+ }
699
+
700
+ DEREF(memory, VALUE) = ary;
701
+ } else {
702
+ native_slot_init(upb_fielddef_type(field), memory);
703
+ }
704
+ }
705
+ }
706
+
707
+ void layout_mark(MessageLayout* layout, void* storage) {
708
+ upb_msg_field_iter it;
709
+ for (upb_msg_field_begin(&it, layout->msgdef);
710
+ !upb_msg_field_done(&it);
711
+ upb_msg_field_next(&it)) {
712
+ const upb_fielddef* field = upb_msg_iter_field(&it);
713
+ void* memory = slot_memory(layout, storage, field);
714
+ uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
715
+
716
+ if (upb_fielddef_containingoneof(field)) {
717
+ if (*oneof_case == upb_fielddef_number(field)) {
718
+ native_slot_mark(upb_fielddef_type(field), memory);
719
+ }
720
+ } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
721
+ rb_gc_mark(DEREF(memory, VALUE));
722
+ } else {
723
+ native_slot_mark(upb_fielddef_type(field), memory);
724
+ }
725
+ }
726
+ }
727
+
728
+ void layout_dup(MessageLayout* layout, void* to, void* from) {
729
+ upb_msg_field_iter it;
730
+ for (upb_msg_field_begin(&it, layout->msgdef);
731
+ !upb_msg_field_done(&it);
732
+ upb_msg_field_next(&it)) {
733
+ const upb_fielddef* field = upb_msg_iter_field(&it);
734
+
735
+ void* to_memory = slot_memory(layout, to, field);
736
+ uint32_t* to_oneof_case = slot_oneof_case(layout, to, field);
737
+ void* from_memory = slot_memory(layout, from, field);
738
+ uint32_t* from_oneof_case = slot_oneof_case(layout, from, field);
739
+
740
+ if (upb_fielddef_containingoneof(field)) {
741
+ if (*from_oneof_case == upb_fielddef_number(field)) {
742
+ *to_oneof_case = *from_oneof_case;
743
+ native_slot_dup(upb_fielddef_type(field), to_memory, from_memory);
744
+ }
745
+ } else if (is_map_field(field)) {
746
+ DEREF(to_memory, VALUE) = Map_dup(DEREF(from_memory, VALUE));
747
+ } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
748
+ DEREF(to_memory, VALUE) = RepeatedField_dup(DEREF(from_memory, VALUE));
749
+ } else {
750
+ native_slot_dup(upb_fielddef_type(field), to_memory, from_memory);
751
+ }
752
+ }
753
+ }
754
+
755
+ void layout_deep_copy(MessageLayout* layout, void* to, void* from) {
756
+ upb_msg_field_iter it;
757
+ for (upb_msg_field_begin(&it, layout->msgdef);
758
+ !upb_msg_field_done(&it);
759
+ upb_msg_field_next(&it)) {
760
+ const upb_fielddef* field = upb_msg_iter_field(&it);
761
+
762
+ void* to_memory = slot_memory(layout, to, field);
763
+ uint32_t* to_oneof_case = slot_oneof_case(layout, to, field);
764
+ void* from_memory = slot_memory(layout, from, field);
765
+ uint32_t* from_oneof_case = slot_oneof_case(layout, from, field);
766
+
767
+ if (upb_fielddef_containingoneof(field)) {
768
+ if (*from_oneof_case == upb_fielddef_number(field)) {
769
+ *to_oneof_case = *from_oneof_case;
770
+ native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory);
771
+ }
772
+ } else if (is_map_field(field)) {
773
+ DEREF(to_memory, VALUE) =
774
+ Map_deep_copy(DEREF(from_memory, VALUE));
775
+ } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
776
+ DEREF(to_memory, VALUE) =
777
+ RepeatedField_deep_copy(DEREF(from_memory, VALUE));
778
+ } else {
779
+ native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory);
780
+ }
781
+ }
782
+ }
783
+
784
+ VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2) {
785
+ upb_msg_field_iter it;
786
+ for (upb_msg_field_begin(&it, layout->msgdef);
787
+ !upb_msg_field_done(&it);
788
+ upb_msg_field_next(&it)) {
789
+ const upb_fielddef* field = upb_msg_iter_field(&it);
790
+
791
+ void* msg1_memory = slot_memory(layout, msg1, field);
792
+ uint32_t* msg1_oneof_case = slot_oneof_case(layout, msg1, field);
793
+ void* msg2_memory = slot_memory(layout, msg2, field);
794
+ uint32_t* msg2_oneof_case = slot_oneof_case(layout, msg2, field);
795
+
796
+ if (upb_fielddef_containingoneof(field)) {
797
+ if (*msg1_oneof_case != *msg2_oneof_case ||
798
+ (*msg1_oneof_case == upb_fielddef_number(field) &&
799
+ !native_slot_eq(upb_fielddef_type(field),
800
+ msg1_memory,
801
+ msg2_memory))) {
802
+ return Qfalse;
803
+ }
804
+ } else if (is_map_field(field)) {
805
+ if (!Map_eq(DEREF(msg1_memory, VALUE),
806
+ DEREF(msg2_memory, VALUE))) {
807
+ return Qfalse;
808
+ }
809
+ } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
810
+ if (!RepeatedField_eq(DEREF(msg1_memory, VALUE),
811
+ DEREF(msg2_memory, VALUE))) {
812
+ return Qfalse;
813
+ }
814
+ } else {
815
+ if (!native_slot_eq(upb_fielddef_type(field),
816
+ msg1_memory, msg2_memory)) {
817
+ return Qfalse;
818
+ }
819
+ }
820
+ }
821
+ return Qtrue;
822
+ }
823
+
824
+ VALUE layout_hash(MessageLayout* layout, void* storage) {
825
+ upb_msg_field_iter it;
826
+ st_index_t h = rb_hash_start(0);
827
+ VALUE hash_sym = rb_intern("hash");
828
+ for (upb_msg_field_begin(&it, layout->msgdef);
829
+ !upb_msg_field_done(&it);
830
+ upb_msg_field_next(&it)) {
831
+ const upb_fielddef* field = upb_msg_iter_field(&it);
832
+ VALUE field_val = layout_get(layout, storage, field);
833
+ h = rb_hash_uint(h, NUM2LONG(rb_funcall(field_val, hash_sym, 0)));
834
+ }
835
+ h = rb_hash_end(h);
836
+
837
+ return INT2FIX(h);
838
+ }
839
+
840
+ VALUE layout_inspect(MessageLayout* layout, void* storage) {
841
+ VALUE str = rb_str_new2("");
842
+
843
+ upb_msg_field_iter it;
844
+ bool first = true;
845
+ for (upb_msg_field_begin(&it, layout->msgdef);
846
+ !upb_msg_field_done(&it);
847
+ upb_msg_field_next(&it)) {
848
+ const upb_fielddef* field = upb_msg_iter_field(&it);
849
+ VALUE field_val = layout_get(layout, storage, field);
850
+
851
+ if (!first) {
852
+ str = rb_str_cat2(str, ", ");
853
+ } else {
854
+ first = false;
855
+ }
856
+ str = rb_str_cat2(str, upb_fielddef_name(field));
857
+ str = rb_str_cat2(str, ": ");
858
+
859
+ str = rb_str_append(str, rb_funcall(field_val, rb_intern("inspect"), 0));
860
+ }
861
+
862
+ return str;
863
+ }