google-protobuf 3.0.0.alpha.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

@@ -0,0 +1,577 @@
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 void check_int_range_precision(upb_fieldtype_t type, VALUE val) {
61
+ // NUM2{INT,UINT,LL,ULL} macros do the appropriate range checks on upper
62
+ // bound; we just need to do precision checks (i.e., disallow rounding) and
63
+ // check for < 0 on unsigned types.
64
+ if (TYPE(val) == T_FLOAT) {
65
+ double dbl_val = NUM2DBL(val);
66
+ if (floor(dbl_val) != dbl_val) {
67
+ rb_raise(rb_eRangeError,
68
+ "Non-integral floating point value assigned to integer field.");
69
+ }
70
+ }
71
+ if (type == UPB_TYPE_UINT32 || type == UPB_TYPE_UINT64) {
72
+ if (NUM2DBL(val) < 0) {
73
+ rb_raise(rb_eRangeError,
74
+ "Assigning negative value to unsigned integer field.");
75
+ }
76
+ }
77
+ }
78
+
79
+ static bool is_ruby_num(VALUE value) {
80
+ return (TYPE(value) == T_FLOAT ||
81
+ TYPE(value) == T_FIXNUM ||
82
+ TYPE(value) == T_BIGNUM);
83
+ }
84
+
85
+ void native_slot_validate_string_encoding(upb_fieldtype_t type, VALUE value) {
86
+ bool bad_encoding = false;
87
+ rb_encoding* string_encoding = rb_enc_from_index(ENCODING_GET(value));
88
+ if (type == UPB_TYPE_STRING) {
89
+ bad_encoding =
90
+ string_encoding != kRubyStringUtf8Encoding &&
91
+ string_encoding != kRubyStringASCIIEncoding;
92
+ } else {
93
+ bad_encoding =
94
+ string_encoding != kRubyString8bitEncoding;
95
+ }
96
+ // Check that encoding is UTF-8 or ASCII (for string fields) or ASCII-8BIT
97
+ // (for bytes fields).
98
+ if (bad_encoding) {
99
+ rb_raise(rb_eTypeError, "Encoding for '%s' fields must be %s (was %s)",
100
+ (type == UPB_TYPE_STRING) ? "string" : "bytes",
101
+ (type == UPB_TYPE_STRING) ? "UTF-8 or ASCII" : "ASCII-8BIT",
102
+ rb_enc_name(string_encoding));
103
+ }
104
+ }
105
+
106
+ void native_slot_set(upb_fieldtype_t type, VALUE type_class,
107
+ void* memory, VALUE value) {
108
+ switch (type) {
109
+ case UPB_TYPE_FLOAT:
110
+ if (!is_ruby_num(value)) {
111
+ rb_raise(rb_eTypeError, "Expected number type for float field.");
112
+ }
113
+ DEREF(memory, float) = NUM2DBL(value);
114
+ break;
115
+ case UPB_TYPE_DOUBLE:
116
+ if (!is_ruby_num(value)) {
117
+ rb_raise(rb_eTypeError, "Expected number type for double field.");
118
+ }
119
+ DEREF(memory, double) = NUM2DBL(value);
120
+ break;
121
+ case UPB_TYPE_BOOL: {
122
+ int8_t val = -1;
123
+ if (value == Qtrue) {
124
+ val = 1;
125
+ } else if (value == Qfalse) {
126
+ val = 0;
127
+ } else {
128
+ rb_raise(rb_eTypeError, "Invalid argument for boolean field.");
129
+ }
130
+ DEREF(memory, int8_t) = val;
131
+ break;
132
+ }
133
+ case UPB_TYPE_STRING:
134
+ case UPB_TYPE_BYTES: {
135
+ if (CLASS_OF(value) != rb_cString) {
136
+ rb_raise(rb_eTypeError, "Invalid argument for string field.");
137
+ }
138
+ native_slot_validate_string_encoding(type, value);
139
+ DEREF(memory, VALUE) = value;
140
+ break;
141
+ }
142
+ case UPB_TYPE_MESSAGE: {
143
+ if (CLASS_OF(value) != type_class) {
144
+ rb_raise(rb_eTypeError,
145
+ "Invalid type %s to assign to submessage field.",
146
+ rb_class2name(CLASS_OF(value)));
147
+ }
148
+ DEREF(memory, VALUE) = value;
149
+ break;
150
+ }
151
+ case UPB_TYPE_ENUM: {
152
+ if (!is_ruby_num(value) && TYPE(value) != T_SYMBOL) {
153
+ rb_raise(rb_eTypeError,
154
+ "Expected number or symbol type for enum field.");
155
+ }
156
+ int32_t int_val = 0;
157
+ if (TYPE(value) == T_SYMBOL) {
158
+ // Ensure that the given symbol exists in the enum module.
159
+ VALUE lookup = rb_const_get(type_class, SYM2ID(value));
160
+ if (lookup == Qnil) {
161
+ rb_raise(rb_eRangeError, "Unknown symbol value for enum field.");
162
+ } else {
163
+ int_val = NUM2INT(lookup);
164
+ }
165
+ } else {
166
+ check_int_range_precision(UPB_TYPE_INT32, value);
167
+ int_val = NUM2INT(value);
168
+ }
169
+ DEREF(memory, int32_t) = int_val;
170
+ break;
171
+ }
172
+ case UPB_TYPE_INT32:
173
+ case UPB_TYPE_INT64:
174
+ case UPB_TYPE_UINT32:
175
+ case UPB_TYPE_UINT64:
176
+ if (!is_ruby_num(value)) {
177
+ rb_raise(rb_eTypeError, "Expected number type for integral field.");
178
+ }
179
+ check_int_range_precision(type, value);
180
+ switch (type) {
181
+ case UPB_TYPE_INT32:
182
+ DEREF(memory, int32_t) = NUM2INT(value);
183
+ break;
184
+ case UPB_TYPE_INT64:
185
+ DEREF(memory, int64_t) = NUM2LL(value);
186
+ break;
187
+ case UPB_TYPE_UINT32:
188
+ DEREF(memory, uint32_t) = NUM2UINT(value);
189
+ break;
190
+ case UPB_TYPE_UINT64:
191
+ DEREF(memory, uint64_t) = NUM2ULL(value);
192
+ break;
193
+ default:
194
+ break;
195
+ }
196
+ break;
197
+ default:
198
+ break;
199
+ }
200
+ }
201
+
202
+ VALUE native_slot_get(upb_fieldtype_t type, VALUE type_class, void* memory) {
203
+ switch (type) {
204
+ case UPB_TYPE_FLOAT:
205
+ return DBL2NUM(DEREF(memory, float));
206
+ case UPB_TYPE_DOUBLE:
207
+ return DBL2NUM(DEREF(memory, double));
208
+ case UPB_TYPE_BOOL:
209
+ return DEREF(memory, int8_t) ? Qtrue : Qfalse;
210
+ case UPB_TYPE_STRING:
211
+ case UPB_TYPE_BYTES:
212
+ case UPB_TYPE_MESSAGE:
213
+ return *((VALUE *)memory);
214
+ case UPB_TYPE_ENUM: {
215
+ int32_t val = DEREF(memory, int32_t);
216
+ VALUE symbol = enum_lookup(type_class, INT2NUM(val));
217
+ if (symbol == Qnil) {
218
+ return INT2NUM(val);
219
+ } else {
220
+ return symbol;
221
+ }
222
+ }
223
+ case UPB_TYPE_INT32:
224
+ return INT2NUM(DEREF(memory, int32_t));
225
+ case UPB_TYPE_INT64:
226
+ return LL2NUM(DEREF(memory, int64_t));
227
+ case UPB_TYPE_UINT32:
228
+ return UINT2NUM(DEREF(memory, uint32_t));
229
+ case UPB_TYPE_UINT64:
230
+ return ULL2NUM(DEREF(memory, uint64_t));
231
+ default:
232
+ return Qnil;
233
+ }
234
+ }
235
+
236
+ void native_slot_init(upb_fieldtype_t type, void* memory) {
237
+ switch (type) {
238
+ case UPB_TYPE_FLOAT:
239
+ DEREF(memory, float) = 0.0;
240
+ break;
241
+ case UPB_TYPE_DOUBLE:
242
+ DEREF(memory, double) = 0.0;
243
+ break;
244
+ case UPB_TYPE_BOOL:
245
+ DEREF(memory, int8_t) = 0;
246
+ break;
247
+ case UPB_TYPE_STRING:
248
+ case UPB_TYPE_BYTES:
249
+ // TODO(cfallin): set encoding appropriately
250
+ DEREF(memory, VALUE) = rb_str_new2("");
251
+ break;
252
+ case UPB_TYPE_MESSAGE:
253
+ DEREF(memory, VALUE) = Qnil;
254
+ break;
255
+ case UPB_TYPE_ENUM:
256
+ case UPB_TYPE_INT32:
257
+ DEREF(memory, int32_t) = 0;
258
+ break;
259
+ case UPB_TYPE_INT64:
260
+ DEREF(memory, int64_t) = 0;
261
+ break;
262
+ case UPB_TYPE_UINT32:
263
+ DEREF(memory, uint32_t) = 0;
264
+ break;
265
+ case UPB_TYPE_UINT64:
266
+ DEREF(memory, uint64_t) = 0;
267
+ break;
268
+ default:
269
+ break;
270
+ }
271
+ }
272
+
273
+ void native_slot_mark(upb_fieldtype_t type, void* memory) {
274
+ switch (type) {
275
+ case UPB_TYPE_STRING:
276
+ case UPB_TYPE_BYTES:
277
+ case UPB_TYPE_MESSAGE:
278
+ rb_gc_mark(DEREF(memory, VALUE));
279
+ break;
280
+ default:
281
+ break;
282
+ }
283
+ }
284
+
285
+ void native_slot_dup(upb_fieldtype_t type, void* to, void* from) {
286
+ memcpy(to, from, native_slot_size(type));
287
+ }
288
+
289
+ void native_slot_deep_copy(upb_fieldtype_t type, void* to, void* from) {
290
+ switch (type) {
291
+ case UPB_TYPE_STRING:
292
+ case UPB_TYPE_BYTES: {
293
+ VALUE from_val = DEREF(from, VALUE);
294
+ DEREF(to, VALUE) = (from_val != Qnil) ?
295
+ rb_funcall(from_val, rb_intern("dup"), 0) : Qnil;
296
+ break;
297
+ }
298
+ case UPB_TYPE_MESSAGE: {
299
+ VALUE from_val = DEREF(from, VALUE);
300
+ DEREF(to, VALUE) = (from_val != Qnil) ?
301
+ Message_deep_copy(from_val) : Qnil;
302
+ break;
303
+ }
304
+ default:
305
+ memcpy(to, from, native_slot_size(type));
306
+ }
307
+ }
308
+
309
+ bool native_slot_eq(upb_fieldtype_t type, void* mem1, void* mem2) {
310
+ switch (type) {
311
+ case UPB_TYPE_STRING:
312
+ case UPB_TYPE_BYTES:
313
+ case UPB_TYPE_MESSAGE: {
314
+ VALUE val1 = DEREF(mem1, VALUE);
315
+ VALUE val2 = DEREF(mem2, VALUE);
316
+ VALUE ret = rb_funcall(val1, rb_intern("=="), 1, val2);
317
+ return ret == Qtrue;
318
+ }
319
+ default:
320
+ return !memcmp(mem1, mem2, native_slot_size(type));
321
+ }
322
+ }
323
+
324
+ // -----------------------------------------------------------------------------
325
+ // Memory layout management.
326
+ // -----------------------------------------------------------------------------
327
+
328
+ MessageLayout* create_layout(const upb_msgdef* msgdef) {
329
+ MessageLayout* layout = ALLOC(MessageLayout);
330
+ int nfields = upb_msgdef_numfields(msgdef);
331
+ layout->offsets = ALLOC_N(size_t, nfields);
332
+
333
+ upb_msg_iter it;
334
+ size_t off = 0;
335
+ for (upb_msg_begin(&it, msgdef); !upb_msg_done(&it); upb_msg_next(&it)) {
336
+ const upb_fielddef* field = upb_msg_iter_field(&it);
337
+ size_t field_size =
338
+ (upb_fielddef_label(field) == UPB_LABEL_REPEATED) ?
339
+ sizeof(VALUE) : native_slot_size(upb_fielddef_type(field));
340
+ // align current offset
341
+ off = (off + field_size - 1) & ~(field_size - 1);
342
+ layout->offsets[upb_fielddef_index(field)] = off;
343
+ off += field_size;
344
+ }
345
+
346
+ layout->size = off;
347
+
348
+ layout->msgdef = msgdef;
349
+ upb_msgdef_ref(layout->msgdef, &layout->msgdef);
350
+
351
+ return layout;
352
+ }
353
+
354
+ void free_layout(MessageLayout* layout) {
355
+ xfree(layout->offsets);
356
+ upb_msgdef_unref(layout->msgdef, &layout->msgdef);
357
+ xfree(layout);
358
+ }
359
+
360
+ static VALUE get_type_class(const upb_fielddef* field) {
361
+ VALUE type_class = Qnil;
362
+ if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
363
+ VALUE submsgdesc =
364
+ get_def_obj(upb_fielddef_subdef(field));
365
+ type_class = Descriptor_msgclass(submsgdesc);
366
+ } else if (upb_fielddef_type(field) == UPB_TYPE_ENUM) {
367
+ VALUE subenumdesc =
368
+ get_def_obj(upb_fielddef_subdef(field));
369
+ type_class = EnumDescriptor_enummodule(subenumdesc);
370
+ }
371
+ return type_class;
372
+ }
373
+
374
+ VALUE layout_get(MessageLayout* layout,
375
+ void* storage,
376
+ const upb_fielddef* field) {
377
+ void* memory = ((uint8_t *)storage) +
378
+ layout->offsets[upb_fielddef_index(field)];
379
+ if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
380
+ return *((VALUE *)memory);
381
+ } else {
382
+ return native_slot_get(upb_fielddef_type(field),
383
+ get_type_class(field),
384
+ memory);
385
+ }
386
+ }
387
+
388
+ static void check_repeated_field_type(VALUE val, const upb_fielddef* field) {
389
+ assert(upb_fielddef_label(field) == UPB_LABEL_REPEATED);
390
+
391
+ if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
392
+ RTYPEDDATA_TYPE(val) != &RepeatedField_type) {
393
+ rb_raise(rb_eTypeError, "Expected repeated field array");
394
+ }
395
+
396
+ RepeatedField* self = ruby_to_RepeatedField(val);
397
+ if (self->field_type != upb_fielddef_type(field)) {
398
+ rb_raise(rb_eTypeError, "Repeated field array has wrong element type");
399
+ }
400
+
401
+ if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE ||
402
+ upb_fielddef_type(field) == UPB_TYPE_ENUM) {
403
+ RepeatedField* self = ruby_to_RepeatedField(val);
404
+ if (self->field_type_class !=
405
+ get_def_obj(upb_fielddef_subdef(field))) {
406
+ rb_raise(rb_eTypeError,
407
+ "Repeated field array has wrong message/enum class");
408
+ }
409
+ }
410
+ }
411
+
412
+ void layout_set(MessageLayout* layout,
413
+ void* storage,
414
+ const upb_fielddef* field,
415
+ VALUE val) {
416
+ void* memory = ((uint8_t *)storage) +
417
+ layout->offsets[upb_fielddef_index(field)];
418
+ if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
419
+ check_repeated_field_type(val, field);
420
+ *((VALUE *)memory) = val;
421
+ } else {
422
+ native_slot_set(upb_fielddef_type(field), get_type_class(field),
423
+ memory, val);
424
+ }
425
+ }
426
+
427
+ void layout_init(MessageLayout* layout,
428
+ void* storage) {
429
+ upb_msg_iter it;
430
+ for (upb_msg_begin(&it, layout->msgdef);
431
+ !upb_msg_done(&it);
432
+ upb_msg_next(&it)) {
433
+ const upb_fielddef* field = upb_msg_iter_field(&it);
434
+ void* memory = ((uint8_t *)storage) +
435
+ layout->offsets[upb_fielddef_index(field)];
436
+
437
+ if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
438
+ VALUE ary = Qnil;
439
+ VALUE type_class = get_type_class(field);
440
+ if (type_class != Qnil) {
441
+ VALUE args[2] = {
442
+ fieldtype_to_ruby(upb_fielddef_type(field)),
443
+ type_class,
444
+ };
445
+ ary = rb_class_new_instance(2, args, cRepeatedField);
446
+ } else {
447
+ VALUE args[1] = { fieldtype_to_ruby(upb_fielddef_type(field)) };
448
+ ary = rb_class_new_instance(1, args, cRepeatedField);
449
+ }
450
+ *((VALUE *)memory) = ary;
451
+ } else {
452
+ native_slot_init(upb_fielddef_type(field), memory);
453
+ }
454
+ }
455
+ }
456
+
457
+ void layout_mark(MessageLayout* layout, void* storage) {
458
+ upb_msg_iter it;
459
+ for (upb_msg_begin(&it, layout->msgdef);
460
+ !upb_msg_done(&it);
461
+ upb_msg_next(&it)) {
462
+ const upb_fielddef* field = upb_msg_iter_field(&it);
463
+ void* memory = ((uint8_t *)storage) +
464
+ layout->offsets[upb_fielddef_index(field)];
465
+
466
+ if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
467
+ rb_gc_mark(*((VALUE *)memory));
468
+ } else {
469
+ native_slot_mark(upb_fielddef_type(field), memory);
470
+ }
471
+ }
472
+ }
473
+
474
+ void layout_dup(MessageLayout* layout, void* to, void* from) {
475
+ upb_msg_iter it;
476
+ for (upb_msg_begin(&it, layout->msgdef);
477
+ !upb_msg_done(&it);
478
+ upb_msg_next(&it)) {
479
+ const upb_fielddef* field = upb_msg_iter_field(&it);
480
+ void* to_memory = ((uint8_t *)to) +
481
+ layout->offsets[upb_fielddef_index(field)];
482
+ void* from_memory = ((uint8_t *)from) +
483
+ layout->offsets[upb_fielddef_index(field)];
484
+
485
+ if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
486
+ *((VALUE *)to_memory) = RepeatedField_dup(*((VALUE *)from_memory));
487
+ } else {
488
+ native_slot_dup(upb_fielddef_type(field), to_memory, from_memory);
489
+ }
490
+ }
491
+ }
492
+
493
+ void layout_deep_copy(MessageLayout* layout, void* to, void* from) {
494
+ upb_msg_iter it;
495
+ for (upb_msg_begin(&it, layout->msgdef);
496
+ !upb_msg_done(&it);
497
+ upb_msg_next(&it)) {
498
+ const upb_fielddef* field = upb_msg_iter_field(&it);
499
+ void* to_memory = ((uint8_t *)to) +
500
+ layout->offsets[upb_fielddef_index(field)];
501
+ void* from_memory = ((uint8_t *)from) +
502
+ layout->offsets[upb_fielddef_index(field)];
503
+
504
+ if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
505
+ *((VALUE *)to_memory) = RepeatedField_deep_copy(*((VALUE *)from_memory));
506
+ } else {
507
+ native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory);
508
+ }
509
+ }
510
+ }
511
+
512
+ VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2) {
513
+ upb_msg_iter it;
514
+ for (upb_msg_begin(&it, layout->msgdef);
515
+ !upb_msg_done(&it);
516
+ upb_msg_next(&it)) {
517
+ const upb_fielddef* field = upb_msg_iter_field(&it);
518
+ void* msg1_memory = ((uint8_t *)msg1) +
519
+ layout->offsets[upb_fielddef_index(field)];
520
+ void* msg2_memory = ((uint8_t *)msg2) +
521
+ layout->offsets[upb_fielddef_index(field)];
522
+
523
+ if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
524
+ if (RepeatedField_eq(*((VALUE *)msg1_memory),
525
+ *((VALUE *)msg2_memory)) == Qfalse) {
526
+ return Qfalse;
527
+ }
528
+ } else {
529
+ if (!native_slot_eq(upb_fielddef_type(field),
530
+ msg1_memory, msg2_memory)) {
531
+ return Qfalse;
532
+ }
533
+ }
534
+ }
535
+ return Qtrue;
536
+ }
537
+
538
+ VALUE layout_hash(MessageLayout* layout, void* storage) {
539
+ upb_msg_iter it;
540
+ st_index_t h = rb_hash_start(0);
541
+ VALUE hash_sym = rb_intern("hash");
542
+ for (upb_msg_begin(&it, layout->msgdef);
543
+ !upb_msg_done(&it);
544
+ upb_msg_next(&it)) {
545
+ const upb_fielddef* field = upb_msg_iter_field(&it);
546
+ VALUE field_val = layout_get(layout, storage, field);
547
+ h = rb_hash_uint(h, NUM2LONG(rb_funcall(field_val, hash_sym, 0)));
548
+ }
549
+ h = rb_hash_end(h);
550
+
551
+ return INT2FIX(h);
552
+ }
553
+
554
+ VALUE layout_inspect(MessageLayout* layout, void* storage) {
555
+ VALUE str = rb_str_new2("");
556
+
557
+ upb_msg_iter it;
558
+ bool first = true;
559
+ for (upb_msg_begin(&it, layout->msgdef);
560
+ !upb_msg_done(&it);
561
+ upb_msg_next(&it)) {
562
+ const upb_fielddef* field = upb_msg_iter_field(&it);
563
+ VALUE field_val = layout_get(layout, storage, field);
564
+
565
+ if (!first) {
566
+ str = rb_str_cat2(str, ", ");
567
+ } else {
568
+ first = false;
569
+ }
570
+ str = rb_str_cat2(str, upb_fielddef_name(field));
571
+ str = rb_str_cat2(str, ": ");
572
+
573
+ str = rb_str_append(str, rb_funcall(field_val, rb_intern("inspect"), 0));
574
+ }
575
+
576
+ return str;
577
+ }