OLD | NEW |
| (Empty) |
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 if (!is_ruby_num(value) && TYPE(value) != T_SYMBOL) { | |
170 rb_raise(rb_eTypeError, | |
171 "Expected number or symbol type for enum field."); | |
172 } | |
173 int32_t int_val = 0; | |
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 bool is_map_field(const upb_fielddef* field) { | |
350 if (upb_fielddef_label(field) != UPB_LABEL_REPEATED || | |
351 upb_fielddef_type(field) != UPB_TYPE_MESSAGE) { | |
352 return false; | |
353 } | |
354 const upb_msgdef* subdef = upb_fielddef_msgsubdef(field); | |
355 return upb_msgdef_mapentry(subdef); | |
356 } | |
357 | |
358 const upb_fielddef* map_field_key(const upb_fielddef* field) { | |
359 assert(is_map_field(field)); | |
360 const upb_msgdef* subdef = upb_fielddef_msgsubdef(field); | |
361 return map_entry_key(subdef); | |
362 } | |
363 | |
364 const upb_fielddef* map_field_value(const upb_fielddef* field) { | |
365 assert(is_map_field(field)); | |
366 const upb_msgdef* subdef = upb_fielddef_msgsubdef(field); | |
367 return map_entry_value(subdef); | |
368 } | |
369 | |
370 const upb_fielddef* map_entry_key(const upb_msgdef* msgdef) { | |
371 const upb_fielddef* key_field = upb_msgdef_itof(msgdef, MAP_KEY_FIELD); | |
372 assert(key_field != NULL); | |
373 return key_field; | |
374 } | |
375 | |
376 const upb_fielddef* map_entry_value(const upb_msgdef* msgdef) { | |
377 const upb_fielddef* value_field = upb_msgdef_itof(msgdef, MAP_VALUE_FIELD); | |
378 assert(value_field != NULL); | |
379 return value_field; | |
380 } | |
381 | |
382 // ----------------------------------------------------------------------------- | |
383 // Memory layout management. | |
384 // ----------------------------------------------------------------------------- | |
385 | |
386 static size_t align_up_to(size_t offset, size_t granularity) { | |
387 // Granularity must be a power of two. | |
388 return (offset + granularity - 1) & ~(granularity - 1); | |
389 } | |
390 | |
391 MessageLayout* create_layout(const upb_msgdef* msgdef) { | |
392 MessageLayout* layout = ALLOC(MessageLayout); | |
393 int nfields = upb_msgdef_numfields(msgdef); | |
394 layout->fields = ALLOC_N(MessageField, nfields); | |
395 | |
396 upb_msg_field_iter it; | |
397 size_t off = 0; | |
398 for (upb_msg_field_begin(&it, msgdef); | |
399 !upb_msg_field_done(&it); | |
400 upb_msg_field_next(&it)) { | |
401 const upb_fielddef* field = upb_msg_iter_field(&it); | |
402 | |
403 if (upb_fielddef_containingoneof(field)) { | |
404 // Oneofs are handled separately below. | |
405 continue; | |
406 } | |
407 | |
408 // Allocate |field_size| bytes for this field in the layout. | |
409 size_t field_size = 0; | |
410 if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { | |
411 field_size = sizeof(VALUE); | |
412 } else { | |
413 field_size = native_slot_size(upb_fielddef_type(field)); | |
414 } | |
415 // Align current offset up to |size| granularity. | |
416 off = align_up_to(off, field_size); | |
417 layout->fields[upb_fielddef_index(field)].offset = off; | |
418 layout->fields[upb_fielddef_index(field)].case_offset = | |
419 MESSAGE_FIELD_NO_CASE; | |
420 off += field_size; | |
421 } | |
422 | |
423 // Handle oneofs now -- we iterate over oneofs specifically and allocate only | |
424 // one slot per oneof. | |
425 // | |
426 // We assign all value slots first, then pack the 'case' fields at the end, | |
427 // since in the common case (modern 64-bit platform) these are 8 bytes and 4 | |
428 // bytes respectively and we want to avoid alignment overhead. | |
429 // | |
430 // Note that we reserve 4 bytes (a uint32) per 'case' slot because the value | |
431 // space for oneof cases is conceptually as wide as field tag numbers. In | |
432 // practice, it's unlikely that a oneof would have more than e.g. 256 or 64K | |
433 // members (8 or 16 bits respectively), so conceivably we could assign | |
434 // consecutive case numbers and then pick a smaller oneof case slot size, but | |
435 // the complexity to implement this indirection is probably not worthwhile. | |
436 upb_msg_oneof_iter oit; | |
437 for (upb_msg_oneof_begin(&oit, msgdef); | |
438 !upb_msg_oneof_done(&oit); | |
439 upb_msg_oneof_next(&oit)) { | |
440 const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit); | |
441 | |
442 // Always allocate NATIVE_SLOT_MAX_SIZE bytes, but share the slot between | |
443 // all fields. | |
444 size_t field_size = NATIVE_SLOT_MAX_SIZE; | |
445 // Align the offset. | |
446 off = align_up_to(off, field_size); | |
447 // Assign all fields in the oneof this same offset. | |
448 upb_oneof_iter fit; | |
449 for (upb_oneof_begin(&fit, oneof); | |
450 !upb_oneof_done(&fit); | |
451 upb_oneof_next(&fit)) { | |
452 const upb_fielddef* field = upb_oneof_iter_field(&fit); | |
453 layout->fields[upb_fielddef_index(field)].offset = off; | |
454 } | |
455 off += field_size; | |
456 } | |
457 | |
458 // Now the case fields. | |
459 for (upb_msg_oneof_begin(&oit, msgdef); | |
460 !upb_msg_oneof_done(&oit); | |
461 upb_msg_oneof_next(&oit)) { | |
462 const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit); | |
463 | |
464 size_t field_size = sizeof(uint32_t); | |
465 // Align the offset. | |
466 off = (off + field_size - 1) & ~(field_size - 1); | |
467 // Assign all fields in the oneof this same offset. | |
468 upb_oneof_iter fit; | |
469 for (upb_oneof_begin(&fit, oneof); | |
470 !upb_oneof_done(&fit); | |
471 upb_oneof_next(&fit)) { | |
472 const upb_fielddef* field = upb_oneof_iter_field(&fit); | |
473 layout->fields[upb_fielddef_index(field)].case_offset = off; | |
474 } | |
475 off += field_size; | |
476 } | |
477 | |
478 layout->size = off; | |
479 | |
480 layout->msgdef = msgdef; | |
481 upb_msgdef_ref(layout->msgdef, &layout->msgdef); | |
482 | |
483 return layout; | |
484 } | |
485 | |
486 void free_layout(MessageLayout* layout) { | |
487 xfree(layout->fields); | |
488 upb_msgdef_unref(layout->msgdef, &layout->msgdef); | |
489 xfree(layout); | |
490 } | |
491 | |
492 VALUE field_type_class(const upb_fielddef* field) { | |
493 VALUE type_class = Qnil; | |
494 if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) { | |
495 VALUE submsgdesc = | |
496 get_def_obj(upb_fielddef_subdef(field)); | |
497 type_class = Descriptor_msgclass(submsgdesc); | |
498 } else if (upb_fielddef_type(field) == UPB_TYPE_ENUM) { | |
499 VALUE subenumdesc = | |
500 get_def_obj(upb_fielddef_subdef(field)); | |
501 type_class = EnumDescriptor_enummodule(subenumdesc); | |
502 } | |
503 return type_class; | |
504 } | |
505 | |
506 static void* slot_memory(MessageLayout* layout, | |
507 const void* storage, | |
508 const upb_fielddef* field) { | |
509 return ((uint8_t *)storage) + | |
510 layout->fields[upb_fielddef_index(field)].offset; | |
511 } | |
512 | |
513 static uint32_t* slot_oneof_case(MessageLayout* layout, | |
514 const void* storage, | |
515 const upb_fielddef* field) { | |
516 return (uint32_t *)(((uint8_t *)storage) + | |
517 layout->fields[upb_fielddef_index(field)].case_offset); | |
518 } | |
519 | |
520 | |
521 VALUE layout_get(MessageLayout* layout, | |
522 const void* storage, | |
523 const upb_fielddef* field) { | |
524 void* memory = slot_memory(layout, storage, field); | |
525 uint32_t* oneof_case = slot_oneof_case(layout, storage, field); | |
526 | |
527 if (upb_fielddef_containingoneof(field)) { | |
528 if (*oneof_case != upb_fielddef_number(field)) { | |
529 return Qnil; | |
530 } | |
531 return native_slot_get(upb_fielddef_type(field), | |
532 field_type_class(field), | |
533 memory); | |
534 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { | |
535 return *((VALUE *)memory); | |
536 } else { | |
537 return native_slot_get(upb_fielddef_type(field), | |
538 field_type_class(field), | |
539 memory); | |
540 } | |
541 } | |
542 | |
543 static void check_repeated_field_type(VALUE val, const upb_fielddef* field) { | |
544 assert(upb_fielddef_label(field) == UPB_LABEL_REPEATED); | |
545 | |
546 if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) || | |
547 RTYPEDDATA_TYPE(val) != &RepeatedField_type) { | |
548 rb_raise(rb_eTypeError, "Expected repeated field array"); | |
549 } | |
550 | |
551 RepeatedField* self = ruby_to_RepeatedField(val); | |
552 if (self->field_type != upb_fielddef_type(field)) { | |
553 rb_raise(rb_eTypeError, "Repeated field array has wrong element type"); | |
554 } | |
555 | |
556 if (self->field_type == UPB_TYPE_MESSAGE || | |
557 self->field_type == UPB_TYPE_ENUM) { | |
558 if (self->field_type_class != | |
559 get_def_obj(upb_fielddef_subdef(field))) { | |
560 rb_raise(rb_eTypeError, | |
561 "Repeated field array has wrong message/enum class"); | |
562 } | |
563 } | |
564 } | |
565 | |
566 static void check_map_field_type(VALUE val, const upb_fielddef* field) { | |
567 assert(is_map_field(field)); | |
568 const upb_fielddef* key_field = map_field_key(field); | |
569 const upb_fielddef* value_field = map_field_value(field); | |
570 | |
571 if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) || | |
572 RTYPEDDATA_TYPE(val) != &Map_type) { | |
573 rb_raise(rb_eTypeError, "Expected Map instance"); | |
574 } | |
575 | |
576 Map* self = ruby_to_Map(val); | |
577 if (self->key_type != upb_fielddef_type(key_field)) { | |
578 rb_raise(rb_eTypeError, "Map key type does not match field's key type"); | |
579 } | |
580 if (self->value_type != upb_fielddef_type(value_field)) { | |
581 rb_raise(rb_eTypeError, "Map value type does not match field's value type"); | |
582 } | |
583 if (upb_fielddef_type(value_field) == UPB_TYPE_MESSAGE || | |
584 upb_fielddef_type(value_field) == UPB_TYPE_ENUM) { | |
585 if (self->value_type_class != | |
586 get_def_obj(upb_fielddef_subdef(value_field))) { | |
587 rb_raise(rb_eTypeError, | |
588 "Map value type has wrong message/enum class"); | |
589 } | |
590 } | |
591 } | |
592 | |
593 | |
594 void layout_set(MessageLayout* layout, | |
595 void* storage, | |
596 const upb_fielddef* field, | |
597 VALUE val) { | |
598 void* memory = slot_memory(layout, storage, field); | |
599 uint32_t* oneof_case = slot_oneof_case(layout, storage, field); | |
600 | |
601 if (upb_fielddef_containingoneof(field)) { | |
602 if (val == Qnil) { | |
603 // Assigning nil to a oneof field clears the oneof completely. | |
604 *oneof_case = ONEOF_CASE_NONE; | |
605 memset(memory, 0, NATIVE_SLOT_MAX_SIZE); | |
606 } else { | |
607 // The transition between field types for a single oneof (union) slot is | |
608 // somewhat complex because we need to ensure that a GC triggered at any | |
609 // point by a call into the Ruby VM sees a valid state for this field and | |
610 // does not either go off into the weeds (following what it thinks is a | |
611 // VALUE but is actually a different field type) or miss an object (seeing | |
612 // what it thinks is a primitive field but is actually a VALUE for the new | |
613 // field type). | |
614 // | |
615 // In order for the transition to be safe, the oneof case slot must be in | |
616 // sync with the value slot whenever the Ruby VM has been called. Thus, we | |
617 // use native_slot_set_value_and_case(), which ensures that both the value | |
618 // and case number are altered atomically (w.r.t. the Ruby VM). | |
619 native_slot_set_value_and_case( | |
620 upb_fielddef_type(field), field_type_class(field), | |
621 memory, val, | |
622 oneof_case, upb_fielddef_number(field)); | |
623 } | |
624 } else if (is_map_field(field)) { | |
625 check_map_field_type(val, field); | |
626 DEREF(memory, VALUE) = val; | |
627 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { | |
628 check_repeated_field_type(val, field); | |
629 DEREF(memory, VALUE) = val; | |
630 } else { | |
631 native_slot_set(upb_fielddef_type(field), field_type_class(field), | |
632 memory, val); | |
633 } | |
634 } | |
635 | |
636 void layout_init(MessageLayout* layout, | |
637 void* storage) { | |
638 upb_msg_field_iter it; | |
639 for (upb_msg_field_begin(&it, layout->msgdef); | |
640 !upb_msg_field_done(&it); | |
641 upb_msg_field_next(&it)) { | |
642 const upb_fielddef* field = upb_msg_iter_field(&it); | |
643 void* memory = slot_memory(layout, storage, field); | |
644 uint32_t* oneof_case = slot_oneof_case(layout, storage, field); | |
645 | |
646 if (upb_fielddef_containingoneof(field)) { | |
647 memset(memory, 0, NATIVE_SLOT_MAX_SIZE); | |
648 *oneof_case = ONEOF_CASE_NONE; | |
649 } else if (is_map_field(field)) { | |
650 VALUE map = Qnil; | |
651 | |
652 const upb_fielddef* key_field = map_field_key(field); | |
653 const upb_fielddef* value_field = map_field_value(field); | |
654 VALUE type_class = field_type_class(value_field); | |
655 | |
656 if (type_class != Qnil) { | |
657 VALUE args[3] = { | |
658 fieldtype_to_ruby(upb_fielddef_type(key_field)), | |
659 fieldtype_to_ruby(upb_fielddef_type(value_field)), | |
660 type_class, | |
661 }; | |
662 map = rb_class_new_instance(3, args, cMap); | |
663 } else { | |
664 VALUE args[2] = { | |
665 fieldtype_to_ruby(upb_fielddef_type(key_field)), | |
666 fieldtype_to_ruby(upb_fielddef_type(value_field)), | |
667 }; | |
668 map = rb_class_new_instance(2, args, cMap); | |
669 } | |
670 | |
671 DEREF(memory, VALUE) = map; | |
672 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { | |
673 VALUE ary = Qnil; | |
674 | |
675 VALUE type_class = field_type_class(field); | |
676 | |
677 if (type_class != Qnil) { | |
678 VALUE args[2] = { | |
679 fieldtype_to_ruby(upb_fielddef_type(field)), | |
680 type_class, | |
681 }; | |
682 ary = rb_class_new_instance(2, args, cRepeatedField); | |
683 } else { | |
684 VALUE args[1] = { fieldtype_to_ruby(upb_fielddef_type(field)) }; | |
685 ary = rb_class_new_instance(1, args, cRepeatedField); | |
686 } | |
687 | |
688 DEREF(memory, VALUE) = ary; | |
689 } else { | |
690 native_slot_init(upb_fielddef_type(field), memory); | |
691 } | |
692 } | |
693 } | |
694 | |
695 void layout_mark(MessageLayout* layout, void* storage) { | |
696 upb_msg_field_iter it; | |
697 for (upb_msg_field_begin(&it, layout->msgdef); | |
698 !upb_msg_field_done(&it); | |
699 upb_msg_field_next(&it)) { | |
700 const upb_fielddef* field = upb_msg_iter_field(&it); | |
701 void* memory = slot_memory(layout, storage, field); | |
702 uint32_t* oneof_case = slot_oneof_case(layout, storage, field); | |
703 | |
704 if (upb_fielddef_containingoneof(field)) { | |
705 if (*oneof_case == upb_fielddef_number(field)) { | |
706 native_slot_mark(upb_fielddef_type(field), memory); | |
707 } | |
708 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { | |
709 rb_gc_mark(DEREF(memory, VALUE)); | |
710 } else { | |
711 native_slot_mark(upb_fielddef_type(field), memory); | |
712 } | |
713 } | |
714 } | |
715 | |
716 void layout_dup(MessageLayout* layout, void* to, void* from) { | |
717 upb_msg_field_iter it; | |
718 for (upb_msg_field_begin(&it, layout->msgdef); | |
719 !upb_msg_field_done(&it); | |
720 upb_msg_field_next(&it)) { | |
721 const upb_fielddef* field = upb_msg_iter_field(&it); | |
722 | |
723 void* to_memory = slot_memory(layout, to, field); | |
724 uint32_t* to_oneof_case = slot_oneof_case(layout, to, field); | |
725 void* from_memory = slot_memory(layout, from, field); | |
726 uint32_t* from_oneof_case = slot_oneof_case(layout, from, field); | |
727 | |
728 if (upb_fielddef_containingoneof(field)) { | |
729 if (*from_oneof_case == upb_fielddef_number(field)) { | |
730 *to_oneof_case = *from_oneof_case; | |
731 native_slot_dup(upb_fielddef_type(field), to_memory, from_memory); | |
732 } | |
733 } else if (is_map_field(field)) { | |
734 DEREF(to_memory, VALUE) = Map_dup(DEREF(from_memory, VALUE)); | |
735 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { | |
736 DEREF(to_memory, VALUE) = RepeatedField_dup(DEREF(from_memory, VALUE)); | |
737 } else { | |
738 native_slot_dup(upb_fielddef_type(field), to_memory, from_memory); | |
739 } | |
740 } | |
741 } | |
742 | |
743 void layout_deep_copy(MessageLayout* layout, void* to, void* from) { | |
744 upb_msg_field_iter it; | |
745 for (upb_msg_field_begin(&it, layout->msgdef); | |
746 !upb_msg_field_done(&it); | |
747 upb_msg_field_next(&it)) { | |
748 const upb_fielddef* field = upb_msg_iter_field(&it); | |
749 | |
750 void* to_memory = slot_memory(layout, to, field); | |
751 uint32_t* to_oneof_case = slot_oneof_case(layout, to, field); | |
752 void* from_memory = slot_memory(layout, from, field); | |
753 uint32_t* from_oneof_case = slot_oneof_case(layout, from, field); | |
754 | |
755 if (upb_fielddef_containingoneof(field)) { | |
756 if (*from_oneof_case == upb_fielddef_number(field)) { | |
757 *to_oneof_case = *from_oneof_case; | |
758 native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory); | |
759 } | |
760 } else if (is_map_field(field)) { | |
761 DEREF(to_memory, VALUE) = | |
762 Map_deep_copy(DEREF(from_memory, VALUE)); | |
763 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { | |
764 DEREF(to_memory, VALUE) = | |
765 RepeatedField_deep_copy(DEREF(from_memory, VALUE)); | |
766 } else { | |
767 native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory); | |
768 } | |
769 } | |
770 } | |
771 | |
772 VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2) { | |
773 upb_msg_field_iter it; | |
774 for (upb_msg_field_begin(&it, layout->msgdef); | |
775 !upb_msg_field_done(&it); | |
776 upb_msg_field_next(&it)) { | |
777 const upb_fielddef* field = upb_msg_iter_field(&it); | |
778 | |
779 void* msg1_memory = slot_memory(layout, msg1, field); | |
780 uint32_t* msg1_oneof_case = slot_oneof_case(layout, msg1, field); | |
781 void* msg2_memory = slot_memory(layout, msg2, field); | |
782 uint32_t* msg2_oneof_case = slot_oneof_case(layout, msg2, field); | |
783 | |
784 if (upb_fielddef_containingoneof(field)) { | |
785 if (*msg1_oneof_case != *msg2_oneof_case || | |
786 (*msg1_oneof_case == upb_fielddef_number(field) && | |
787 !native_slot_eq(upb_fielddef_type(field), | |
788 msg1_memory, | |
789 msg2_memory))) { | |
790 return Qfalse; | |
791 } | |
792 } else if (is_map_field(field)) { | |
793 if (!Map_eq(DEREF(msg1_memory, VALUE), | |
794 DEREF(msg2_memory, VALUE))) { | |
795 return Qfalse; | |
796 } | |
797 } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { | |
798 if (!RepeatedField_eq(DEREF(msg1_memory, VALUE), | |
799 DEREF(msg2_memory, VALUE))) { | |
800 return Qfalse; | |
801 } | |
802 } else { | |
803 if (!native_slot_eq(upb_fielddef_type(field), | |
804 msg1_memory, msg2_memory)) { | |
805 return Qfalse; | |
806 } | |
807 } | |
808 } | |
809 return Qtrue; | |
810 } | |
811 | |
812 VALUE layout_hash(MessageLayout* layout, void* storage) { | |
813 upb_msg_field_iter it; | |
814 st_index_t h = rb_hash_start(0); | |
815 VALUE hash_sym = rb_intern("hash"); | |
816 for (upb_msg_field_begin(&it, layout->msgdef); | |
817 !upb_msg_field_done(&it); | |
818 upb_msg_field_next(&it)) { | |
819 const upb_fielddef* field = upb_msg_iter_field(&it); | |
820 VALUE field_val = layout_get(layout, storage, field); | |
821 h = rb_hash_uint(h, NUM2LONG(rb_funcall(field_val, hash_sym, 0))); | |
822 } | |
823 h = rb_hash_end(h); | |
824 | |
825 return INT2FIX(h); | |
826 } | |
827 | |
828 VALUE layout_inspect(MessageLayout* layout, void* storage) { | |
829 VALUE str = rb_str_new2(""); | |
830 | |
831 upb_msg_field_iter it; | |
832 bool first = true; | |
833 for (upb_msg_field_begin(&it, layout->msgdef); | |
834 !upb_msg_field_done(&it); | |
835 upb_msg_field_next(&it)) { | |
836 const upb_fielddef* field = upb_msg_iter_field(&it); | |
837 VALUE field_val = layout_get(layout, storage, field); | |
838 | |
839 if (!first) { | |
840 str = rb_str_cat2(str, ", "); | |
841 } else { | |
842 first = false; | |
843 } | |
844 str = rb_str_cat2(str, upb_fielddef_name(field)); | |
845 str = rb_str_cat2(str, ": "); | |
846 | |
847 str = rb_str_append(str, rb_funcall(field_val, rb_intern("inspect"), 0)); | |
848 } | |
849 | |
850 return str; | |
851 } | |
OLD | NEW |