google-protobuf 3.0.0.alpha.1.0

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,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
+ }