diff options
Diffstat (limited to 'third_party/protobuf/3.2.0/ruby/ext/google/protobuf_c/storage.c')
-rw-r--r-- | third_party/protobuf/3.2.0/ruby/ext/google/protobuf_c/storage.c | 893 |
1 files changed, 0 insertions, 893 deletions
diff --git a/third_party/protobuf/3.2.0/ruby/ext/google/protobuf_c/storage.c b/third_party/protobuf/3.2.0/ruby/ext/google/protobuf_c/storage.c deleted file mode 100644 index 3ff2bda6bb..0000000000 --- a/third_party/protobuf/3.2.0/ruby/ext/google/protobuf_c/storage.c +++ /dev/null @@ -1,893 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2014 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "protobuf.h" - -#include <math.h> - -#include <ruby/encoding.h> - -// ----------------------------------------------------------------------------- -// Ruby <-> native slot management. -// ----------------------------------------------------------------------------- - -#define DEREF(memory, type) *(type*)(memory) - -size_t native_slot_size(upb_fieldtype_t type) { - switch (type) { - case UPB_TYPE_FLOAT: return 4; - case UPB_TYPE_DOUBLE: return 8; - case UPB_TYPE_BOOL: return 1; - case UPB_TYPE_STRING: return sizeof(VALUE); - case UPB_TYPE_BYTES: return sizeof(VALUE); - case UPB_TYPE_MESSAGE: return sizeof(VALUE); - case UPB_TYPE_ENUM: return 4; - case UPB_TYPE_INT32: return 4; - case UPB_TYPE_INT64: return 8; - case UPB_TYPE_UINT32: return 4; - case UPB_TYPE_UINT64: return 8; - default: return 0; - } -} - -static VALUE value_from_default(const upb_fielddef *field) { - switch (upb_fielddef_type(field)) { - case UPB_TYPE_FLOAT: return DBL2NUM(upb_fielddef_defaultfloat(field)); - case UPB_TYPE_DOUBLE: return DBL2NUM(upb_fielddef_defaultdouble(field)); - case UPB_TYPE_BOOL: - return upb_fielddef_defaultbool(field) ? Qtrue : Qfalse; - case UPB_TYPE_MESSAGE: return Qnil; - case UPB_TYPE_ENUM: { - const upb_enumdef *enumdef = upb_fielddef_enumsubdef(field); - int32_t num = upb_fielddef_defaultint32(field); - const char *label = upb_enumdef_iton(enumdef, num); - if (label) { - return ID2SYM(rb_intern(label)); - } else { - return INT2NUM(num); - } - } - case UPB_TYPE_INT32: return INT2NUM(upb_fielddef_defaultint32(field)); - case UPB_TYPE_INT64: return LL2NUM(upb_fielddef_defaultint64(field));; - case UPB_TYPE_UINT32: return UINT2NUM(upb_fielddef_defaultuint32(field)); - case UPB_TYPE_UINT64: return ULL2NUM(upb_fielddef_defaultuint64(field)); - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - size_t size; - const char *str = upb_fielddef_defaultstr(field, &size); - return rb_str_new(str, size); - } - default: return Qnil; - } -} - -static bool is_ruby_num(VALUE value) { - return (TYPE(value) == T_FLOAT || - TYPE(value) == T_FIXNUM || - TYPE(value) == T_BIGNUM); -} - -void native_slot_check_int_range_precision(upb_fieldtype_t type, VALUE val) { - if (!is_ruby_num(val)) { - rb_raise(rb_eTypeError, "Expected number type for integral field."); - } - - // NUM2{INT,UINT,LL,ULL} macros do the appropriate range checks on upper - // bound; we just need to do precision checks (i.e., disallow rounding) and - // check for < 0 on unsigned types. - if (TYPE(val) == T_FLOAT) { - double dbl_val = NUM2DBL(val); - if (floor(dbl_val) != dbl_val) { - rb_raise(rb_eRangeError, - "Non-integral floating point value assigned to integer field."); - } - } - if (type == UPB_TYPE_UINT32 || type == UPB_TYPE_UINT64) { - if (NUM2DBL(val) < 0) { - rb_raise(rb_eRangeError, - "Assigning negative value to unsigned integer field."); - } - } -} - -VALUE native_slot_encode_and_freeze_string(upb_fieldtype_t type, VALUE value) { - rb_encoding* desired_encoding = (type == UPB_TYPE_STRING) ? - kRubyStringUtf8Encoding : kRubyString8bitEncoding; - VALUE desired_encoding_value = rb_enc_from_encoding(desired_encoding); - - // Note: this will not duplicate underlying string data unless necessary. - value = rb_str_encode(value, desired_encoding_value, 0, Qnil); - - if (type == UPB_TYPE_STRING && - rb_enc_str_coderange(value) == ENC_CODERANGE_BROKEN) { - rb_raise(rb_eEncodingError, "String is invalid UTF-8"); - } - - // Ensure the data remains valid. Since we called #encode a moment ago, - // this does not freeze the string the user assigned. - rb_obj_freeze(value); - - return value; -} - -void native_slot_set(upb_fieldtype_t type, VALUE type_class, - void* memory, VALUE value) { - native_slot_set_value_and_case(type, type_class, memory, value, NULL, 0); -} - -void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class, - void* memory, VALUE value, - uint32_t* case_memory, - uint32_t case_number) { - // Note that in order to atomically change the value in memory and the case - // value (w.r.t. Ruby VM calls), we must set the value at |memory| only after - // all Ruby VM calls are complete. The case is then set at the bottom of this - // function. - switch (type) { - case UPB_TYPE_FLOAT: - if (!is_ruby_num(value)) { - rb_raise(rb_eTypeError, "Expected number type for float field."); - } - DEREF(memory, float) = NUM2DBL(value); - break; - case UPB_TYPE_DOUBLE: - if (!is_ruby_num(value)) { - rb_raise(rb_eTypeError, "Expected number type for double field."); - } - DEREF(memory, double) = NUM2DBL(value); - break; - case UPB_TYPE_BOOL: { - int8_t val = -1; - if (value == Qtrue) { - val = 1; - } else if (value == Qfalse) { - val = 0; - } else { - rb_raise(rb_eTypeError, "Invalid argument for boolean field."); - } - DEREF(memory, int8_t) = val; - break; - } - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - if (CLASS_OF(value) != rb_cString) { - rb_raise(rb_eTypeError, "Invalid argument for string field."); - } - - DEREF(memory, VALUE) = native_slot_encode_and_freeze_string(type, value); - break; - } - case UPB_TYPE_MESSAGE: { - if (CLASS_OF(value) == CLASS_OF(Qnil)) { - value = Qnil; - } else if (CLASS_OF(value) != type_class) { - rb_raise(rb_eTypeError, - "Invalid type %s to assign to submessage field.", - rb_class2name(CLASS_OF(value))); - } - DEREF(memory, VALUE) = value; - break; - } - case UPB_TYPE_ENUM: { - int32_t int_val = 0; - if (!is_ruby_num(value) && TYPE(value) != T_SYMBOL) { - rb_raise(rb_eTypeError, - "Expected number or symbol type for enum field."); - } - if (TYPE(value) == T_SYMBOL) { - // Ensure that the given symbol exists in the enum module. - VALUE lookup = rb_funcall(type_class, rb_intern("resolve"), 1, value); - if (lookup == Qnil) { - rb_raise(rb_eRangeError, "Unknown symbol value for enum field."); - } else { - int_val = NUM2INT(lookup); - } - } else { - native_slot_check_int_range_precision(UPB_TYPE_INT32, value); - int_val = NUM2INT(value); - } - DEREF(memory, int32_t) = int_val; - break; - } - case UPB_TYPE_INT32: - case UPB_TYPE_INT64: - case UPB_TYPE_UINT32: - case UPB_TYPE_UINT64: - native_slot_check_int_range_precision(type, value); - switch (type) { - case UPB_TYPE_INT32: - DEREF(memory, int32_t) = NUM2INT(value); - break; - case UPB_TYPE_INT64: - DEREF(memory, int64_t) = NUM2LL(value); - break; - case UPB_TYPE_UINT32: - DEREF(memory, uint32_t) = NUM2UINT(value); - break; - case UPB_TYPE_UINT64: - DEREF(memory, uint64_t) = NUM2ULL(value); - break; - default: - break; - } - break; - default: - break; - } - - if (case_memory != NULL) { - *case_memory = case_number; - } -} - -VALUE native_slot_get(upb_fieldtype_t type, - VALUE type_class, - const void* memory) { - switch (type) { - case UPB_TYPE_FLOAT: - return DBL2NUM(DEREF(memory, float)); - case UPB_TYPE_DOUBLE: - return DBL2NUM(DEREF(memory, double)); - case UPB_TYPE_BOOL: - return DEREF(memory, int8_t) ? Qtrue : Qfalse; - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - case UPB_TYPE_MESSAGE: - return DEREF(memory, VALUE); - case UPB_TYPE_ENUM: { - int32_t val = DEREF(memory, int32_t); - VALUE symbol = enum_lookup(type_class, INT2NUM(val)); - if (symbol == Qnil) { - return INT2NUM(val); - } else { - return symbol; - } - } - case UPB_TYPE_INT32: - return INT2NUM(DEREF(memory, int32_t)); - case UPB_TYPE_INT64: - return LL2NUM(DEREF(memory, int64_t)); - case UPB_TYPE_UINT32: - return UINT2NUM(DEREF(memory, uint32_t)); - case UPB_TYPE_UINT64: - return ULL2NUM(DEREF(memory, uint64_t)); - default: - return Qnil; - } -} - -void native_slot_init(upb_fieldtype_t type, void* memory) { - switch (type) { - case UPB_TYPE_FLOAT: - DEREF(memory, float) = 0.0; - break; - case UPB_TYPE_DOUBLE: - DEREF(memory, double) = 0.0; - break; - case UPB_TYPE_BOOL: - DEREF(memory, int8_t) = 0; - break; - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - DEREF(memory, VALUE) = rb_str_new2(""); - rb_enc_associate(DEREF(memory, VALUE), (type == UPB_TYPE_BYTES) ? - kRubyString8bitEncoding : kRubyStringUtf8Encoding); - break; - case UPB_TYPE_MESSAGE: - DEREF(memory, VALUE) = Qnil; - break; - case UPB_TYPE_ENUM: - case UPB_TYPE_INT32: - DEREF(memory, int32_t) = 0; - break; - case UPB_TYPE_INT64: - DEREF(memory, int64_t) = 0; - break; - case UPB_TYPE_UINT32: - DEREF(memory, uint32_t) = 0; - break; - case UPB_TYPE_UINT64: - DEREF(memory, uint64_t) = 0; - break; - default: - break; - } -} - -void native_slot_mark(upb_fieldtype_t type, void* memory) { - switch (type) { - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - case UPB_TYPE_MESSAGE: - rb_gc_mark(DEREF(memory, VALUE)); - break; - default: - break; - } -} - -void native_slot_dup(upb_fieldtype_t type, void* to, void* from) { - memcpy(to, from, native_slot_size(type)); -} - -void native_slot_deep_copy(upb_fieldtype_t type, void* to, void* from) { - switch (type) { - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - VALUE from_val = DEREF(from, VALUE); - DEREF(to, VALUE) = (from_val != Qnil) ? - rb_funcall(from_val, rb_intern("dup"), 0) : Qnil; - break; - } - case UPB_TYPE_MESSAGE: { - VALUE from_val = DEREF(from, VALUE); - DEREF(to, VALUE) = (from_val != Qnil) ? - Message_deep_copy(from_val) : Qnil; - break; - } - default: - memcpy(to, from, native_slot_size(type)); - } -} - -bool native_slot_eq(upb_fieldtype_t type, void* mem1, void* mem2) { - switch (type) { - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - case UPB_TYPE_MESSAGE: { - VALUE val1 = DEREF(mem1, VALUE); - VALUE val2 = DEREF(mem2, VALUE); - VALUE ret = rb_funcall(val1, rb_intern("=="), 1, val2); - return ret == Qtrue; - } - default: - return !memcmp(mem1, mem2, native_slot_size(type)); - } -} - -// ----------------------------------------------------------------------------- -// Map field utilities. -// ----------------------------------------------------------------------------- - -const upb_msgdef* tryget_map_entry_msgdef(const upb_fielddef* field) { - const upb_msgdef* subdef; - if (upb_fielddef_label(field) != UPB_LABEL_REPEATED || - upb_fielddef_type(field) != UPB_TYPE_MESSAGE) { - return NULL; - } - subdef = upb_fielddef_msgsubdef(field); - return upb_msgdef_mapentry(subdef) ? subdef : NULL; -} - -const upb_msgdef *map_entry_msgdef(const upb_fielddef* field) { - const upb_msgdef* subdef = tryget_map_entry_msgdef(field); - assert(subdef); - return subdef; -} - -bool is_map_field(const upb_fielddef *field) { - return tryget_map_entry_msgdef(field) != NULL; -} - -const upb_fielddef* map_field_key(const upb_fielddef* field) { - const upb_msgdef* subdef = map_entry_msgdef(field); - return map_entry_key(subdef); -} - -const upb_fielddef* map_field_value(const upb_fielddef* field) { - const upb_msgdef* subdef = map_entry_msgdef(field); - return map_entry_value(subdef); -} - -const upb_fielddef* map_entry_key(const upb_msgdef* msgdef) { - const upb_fielddef* key_field = upb_msgdef_itof(msgdef, MAP_KEY_FIELD); - assert(key_field != NULL); - return key_field; -} - -const upb_fielddef* map_entry_value(const upb_msgdef* msgdef) { - const upb_fielddef* value_field = upb_msgdef_itof(msgdef, MAP_VALUE_FIELD); - assert(value_field != NULL); - return value_field; -} - -// ----------------------------------------------------------------------------- -// Memory layout management. -// ----------------------------------------------------------------------------- - -static size_t align_up_to(size_t offset, size_t granularity) { - // Granularity must be a power of two. - return (offset + granularity - 1) & ~(granularity - 1); -} - -MessageLayout* create_layout(const upb_msgdef* msgdef) { - MessageLayout* layout = ALLOC(MessageLayout); - int nfields = upb_msgdef_numfields(msgdef); - upb_msg_field_iter it; - upb_msg_oneof_iter oit; - size_t off = 0; - - layout->fields = ALLOC_N(MessageField, nfields); - - for (upb_msg_field_begin(&it, msgdef); - !upb_msg_field_done(&it); - upb_msg_field_next(&it)) { - const upb_fielddef* field = upb_msg_iter_field(&it); - size_t field_size; - - if (upb_fielddef_containingoneof(field)) { - // Oneofs are handled separately below. - continue; - } - - // Allocate |field_size| bytes for this field in the layout. - field_size = 0; - if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - field_size = sizeof(VALUE); - } else { - field_size = native_slot_size(upb_fielddef_type(field)); - } - // Align current offset up to |size| granularity. - off = align_up_to(off, field_size); - layout->fields[upb_fielddef_index(field)].offset = off; - layout->fields[upb_fielddef_index(field)].case_offset = - MESSAGE_FIELD_NO_CASE; - off += field_size; - } - - // Handle oneofs now -- we iterate over oneofs specifically and allocate only - // one slot per oneof. - // - // We assign all value slots first, then pack the 'case' fields at the end, - // since in the common case (modern 64-bit platform) these are 8 bytes and 4 - // bytes respectively and we want to avoid alignment overhead. - // - // Note that we reserve 4 bytes (a uint32) per 'case' slot because the value - // space for oneof cases is conceptually as wide as field tag numbers. In - // practice, it's unlikely that a oneof would have more than e.g. 256 or 64K - // members (8 or 16 bits respectively), so conceivably we could assign - // consecutive case numbers and then pick a smaller oneof case slot size, but - // the complexity to implement this indirection is probably not worthwhile. - for (upb_msg_oneof_begin(&oit, msgdef); - !upb_msg_oneof_done(&oit); - upb_msg_oneof_next(&oit)) { - const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit); - upb_oneof_iter fit; - - // Always allocate NATIVE_SLOT_MAX_SIZE bytes, but share the slot between - // all fields. - size_t field_size = NATIVE_SLOT_MAX_SIZE; - // Align the offset. - off = align_up_to(off, field_size); - // Assign all fields in the oneof this same offset. - for (upb_oneof_begin(&fit, oneof); - !upb_oneof_done(&fit); - upb_oneof_next(&fit)) { - const upb_fielddef* field = upb_oneof_iter_field(&fit); - layout->fields[upb_fielddef_index(field)].offset = off; - } - off += field_size; - } - - // Now the case fields. - for (upb_msg_oneof_begin(&oit, msgdef); - !upb_msg_oneof_done(&oit); - upb_msg_oneof_next(&oit)) { - const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit); - upb_oneof_iter fit; - - size_t field_size = sizeof(uint32_t); - // Align the offset. - off = (off + field_size - 1) & ~(field_size - 1); - // Assign all fields in the oneof this same offset. - for (upb_oneof_begin(&fit, oneof); - !upb_oneof_done(&fit); - upb_oneof_next(&fit)) { - const upb_fielddef* field = upb_oneof_iter_field(&fit); - layout->fields[upb_fielddef_index(field)].case_offset = off; - } - off += field_size; - } - - layout->size = off; - - layout->msgdef = msgdef; - upb_msgdef_ref(layout->msgdef, &layout->msgdef); - - return layout; -} - -void free_layout(MessageLayout* layout) { - xfree(layout->fields); - upb_msgdef_unref(layout->msgdef, &layout->msgdef); - xfree(layout); -} - -VALUE field_type_class(const upb_fielddef* field) { - VALUE type_class = Qnil; - if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) { - VALUE submsgdesc = - get_def_obj(upb_fielddef_subdef(field)); - type_class = Descriptor_msgclass(submsgdesc); - } else if (upb_fielddef_type(field) == UPB_TYPE_ENUM) { - VALUE subenumdesc = - get_def_obj(upb_fielddef_subdef(field)); - type_class = EnumDescriptor_enummodule(subenumdesc); - } - return type_class; -} - -static void* slot_memory(MessageLayout* layout, - const void* storage, - const upb_fielddef* field) { - return ((uint8_t *)storage) + - layout->fields[upb_fielddef_index(field)].offset; -} - -static uint32_t* slot_oneof_case(MessageLayout* layout, - const void* storage, - const upb_fielddef* field) { - return (uint32_t *)(((uint8_t *)storage) + - layout->fields[upb_fielddef_index(field)].case_offset); -} - - -VALUE layout_get(MessageLayout* layout, - const void* storage, - const upb_fielddef* field) { - void* memory = slot_memory(layout, storage, field); - uint32_t* oneof_case = slot_oneof_case(layout, storage, field); - - if (upb_fielddef_containingoneof(field)) { - if (*oneof_case != upb_fielddef_number(field)) { - return value_from_default(field); - } - return native_slot_get(upb_fielddef_type(field), - field_type_class(field), - memory); - } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - return *((VALUE *)memory); - } else { - return native_slot_get(upb_fielddef_type(field), - field_type_class(field), - memory); - } -} - -static void check_repeated_field_type(VALUE val, const upb_fielddef* field) { - RepeatedField* self; - assert(upb_fielddef_label(field) == UPB_LABEL_REPEATED); - - if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) || - RTYPEDDATA_TYPE(val) != &RepeatedField_type) { - rb_raise(rb_eTypeError, "Expected repeated field array"); - } - - self = ruby_to_RepeatedField(val); - if (self->field_type != upb_fielddef_type(field)) { - rb_raise(rb_eTypeError, "Repeated field array has wrong element type"); - } - - if (self->field_type == UPB_TYPE_MESSAGE || - self->field_type == UPB_TYPE_ENUM) { - if (self->field_type_class != - get_def_obj(upb_fielddef_subdef(field))) { - rb_raise(rb_eTypeError, - "Repeated field array has wrong message/enum class"); - } - } -} - -static void check_map_field_type(VALUE val, const upb_fielddef* field) { - const upb_fielddef* key_field = map_field_key(field); - const upb_fielddef* value_field = map_field_value(field); - Map* self; - - if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) || - RTYPEDDATA_TYPE(val) != &Map_type) { - rb_raise(rb_eTypeError, "Expected Map instance"); - } - - self = ruby_to_Map(val); - if (self->key_type != upb_fielddef_type(key_field)) { - rb_raise(rb_eTypeError, "Map key type does not match field's key type"); - } - if (self->value_type != upb_fielddef_type(value_field)) { - rb_raise(rb_eTypeError, "Map value type does not match field's value type"); - } - if (upb_fielddef_type(value_field) == UPB_TYPE_MESSAGE || - upb_fielddef_type(value_field) == UPB_TYPE_ENUM) { - if (self->value_type_class != - get_def_obj(upb_fielddef_subdef(value_field))) { - rb_raise(rb_eTypeError, - "Map value type has wrong message/enum class"); - } - } -} - - -void layout_set(MessageLayout* layout, - void* storage, - const upb_fielddef* field, - VALUE val) { - void* memory = slot_memory(layout, storage, field); - uint32_t* oneof_case = slot_oneof_case(layout, storage, field); - - if (upb_fielddef_containingoneof(field)) { - if (val == Qnil) { - // Assigning nil to a oneof field clears the oneof completely. - *oneof_case = ONEOF_CASE_NONE; - memset(memory, 0, NATIVE_SLOT_MAX_SIZE); - } else { - // The transition between field types for a single oneof (union) slot is - // somewhat complex because we need to ensure that a GC triggered at any - // point by a call into the Ruby VM sees a valid state for this field and - // does not either go off into the weeds (following what it thinks is a - // VALUE but is actually a different field type) or miss an object (seeing - // what it thinks is a primitive field but is actually a VALUE for the new - // field type). - // - // In order for the transition to be safe, the oneof case slot must be in - // sync with the value slot whenever the Ruby VM has been called. Thus, we - // use native_slot_set_value_and_case(), which ensures that both the value - // and case number are altered atomically (w.r.t. the Ruby VM). - native_slot_set_value_and_case( - upb_fielddef_type(field), field_type_class(field), - memory, val, - oneof_case, upb_fielddef_number(field)); - } - } else if (is_map_field(field)) { - check_map_field_type(val, field); - DEREF(memory, VALUE) = val; - } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - check_repeated_field_type(val, field); - DEREF(memory, VALUE) = val; - } else { - native_slot_set(upb_fielddef_type(field), field_type_class(field), - memory, val); - } -} - -void layout_init(MessageLayout* layout, - void* storage) { - upb_msg_field_iter it; - for (upb_msg_field_begin(&it, layout->msgdef); - !upb_msg_field_done(&it); - upb_msg_field_next(&it)) { - const upb_fielddef* field = upb_msg_iter_field(&it); - void* memory = slot_memory(layout, storage, field); - uint32_t* oneof_case = slot_oneof_case(layout, storage, field); - - if (upb_fielddef_containingoneof(field)) { - memset(memory, 0, NATIVE_SLOT_MAX_SIZE); - *oneof_case = ONEOF_CASE_NONE; - } else if (is_map_field(field)) { - VALUE map = Qnil; - - const upb_fielddef* key_field = map_field_key(field); - const upb_fielddef* value_field = map_field_value(field); - VALUE type_class = field_type_class(value_field); - - if (type_class != Qnil) { - VALUE args[3] = { - fieldtype_to_ruby(upb_fielddef_type(key_field)), - fieldtype_to_ruby(upb_fielddef_type(value_field)), - type_class, - }; - map = rb_class_new_instance(3, args, cMap); - } else { - VALUE args[2] = { - fieldtype_to_ruby(upb_fielddef_type(key_field)), - fieldtype_to_ruby(upb_fielddef_type(value_field)), - }; - map = rb_class_new_instance(2, args, cMap); - } - - DEREF(memory, VALUE) = map; - } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - VALUE ary = Qnil; - - VALUE type_class = field_type_class(field); - - if (type_class != Qnil) { - VALUE args[2] = { - fieldtype_to_ruby(upb_fielddef_type(field)), - type_class, - }; - ary = rb_class_new_instance(2, args, cRepeatedField); - } else { - VALUE args[1] = { fieldtype_to_ruby(upb_fielddef_type(field)) }; - ary = rb_class_new_instance(1, args, cRepeatedField); - } - - DEREF(memory, VALUE) = ary; - } else { - native_slot_init(upb_fielddef_type(field), memory); - } - } -} - -void layout_mark(MessageLayout* layout, void* storage) { - upb_msg_field_iter it; - for (upb_msg_field_begin(&it, layout->msgdef); - !upb_msg_field_done(&it); - upb_msg_field_next(&it)) { - const upb_fielddef* field = upb_msg_iter_field(&it); - void* memory = slot_memory(layout, storage, field); - uint32_t* oneof_case = slot_oneof_case(layout, storage, field); - - if (upb_fielddef_containingoneof(field)) { - if (*oneof_case == upb_fielddef_number(field)) { - native_slot_mark(upb_fielddef_type(field), memory); - } - } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - rb_gc_mark(DEREF(memory, VALUE)); - } else { - native_slot_mark(upb_fielddef_type(field), memory); - } - } -} - -void layout_dup(MessageLayout* layout, void* to, void* from) { - upb_msg_field_iter it; - for (upb_msg_field_begin(&it, layout->msgdef); - !upb_msg_field_done(&it); - upb_msg_field_next(&it)) { - const upb_fielddef* field = upb_msg_iter_field(&it); - - void* to_memory = slot_memory(layout, to, field); - uint32_t* to_oneof_case = slot_oneof_case(layout, to, field); - void* from_memory = slot_memory(layout, from, field); - uint32_t* from_oneof_case = slot_oneof_case(layout, from, field); - - if (upb_fielddef_containingoneof(field)) { - if (*from_oneof_case == upb_fielddef_number(field)) { - *to_oneof_case = *from_oneof_case; - native_slot_dup(upb_fielddef_type(field), to_memory, from_memory); - } - } else if (is_map_field(field)) { - DEREF(to_memory, VALUE) = Map_dup(DEREF(from_memory, VALUE)); - } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - DEREF(to_memory, VALUE) = RepeatedField_dup(DEREF(from_memory, VALUE)); - } else { - native_slot_dup(upb_fielddef_type(field), to_memory, from_memory); - } - } -} - -void layout_deep_copy(MessageLayout* layout, void* to, void* from) { - upb_msg_field_iter it; - for (upb_msg_field_begin(&it, layout->msgdef); - !upb_msg_field_done(&it); - upb_msg_field_next(&it)) { - const upb_fielddef* field = upb_msg_iter_field(&it); - - void* to_memory = slot_memory(layout, to, field); - uint32_t* to_oneof_case = slot_oneof_case(layout, to, field); - void* from_memory = slot_memory(layout, from, field); - uint32_t* from_oneof_case = slot_oneof_case(layout, from, field); - - if (upb_fielddef_containingoneof(field)) { - if (*from_oneof_case == upb_fielddef_number(field)) { - *to_oneof_case = *from_oneof_case; - native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory); - } - } else if (is_map_field(field)) { - DEREF(to_memory, VALUE) = - Map_deep_copy(DEREF(from_memory, VALUE)); - } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - DEREF(to_memory, VALUE) = - RepeatedField_deep_copy(DEREF(from_memory, VALUE)); - } else { - native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory); - } - } -} - -VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2) { - upb_msg_field_iter it; - for (upb_msg_field_begin(&it, layout->msgdef); - !upb_msg_field_done(&it); - upb_msg_field_next(&it)) { - const upb_fielddef* field = upb_msg_iter_field(&it); - - void* msg1_memory = slot_memory(layout, msg1, field); - uint32_t* msg1_oneof_case = slot_oneof_case(layout, msg1, field); - void* msg2_memory = slot_memory(layout, msg2, field); - uint32_t* msg2_oneof_case = slot_oneof_case(layout, msg2, field); - - if (upb_fielddef_containingoneof(field)) { - if (*msg1_oneof_case != *msg2_oneof_case || - (*msg1_oneof_case == upb_fielddef_number(field) && - !native_slot_eq(upb_fielddef_type(field), - msg1_memory, - msg2_memory))) { - return Qfalse; - } - } else if (is_map_field(field)) { - if (!Map_eq(DEREF(msg1_memory, VALUE), - DEREF(msg2_memory, VALUE))) { - return Qfalse; - } - } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - if (!RepeatedField_eq(DEREF(msg1_memory, VALUE), - DEREF(msg2_memory, VALUE))) { - return Qfalse; - } - } else { - if (!native_slot_eq(upb_fielddef_type(field), - msg1_memory, msg2_memory)) { - return Qfalse; - } - } - } - return Qtrue; -} - -VALUE layout_hash(MessageLayout* layout, void* storage) { - upb_msg_field_iter it; - st_index_t h = rb_hash_start(0); - VALUE hash_sym = rb_intern("hash"); - for (upb_msg_field_begin(&it, layout->msgdef); - !upb_msg_field_done(&it); - upb_msg_field_next(&it)) { - const upb_fielddef* field = upb_msg_iter_field(&it); - VALUE field_val = layout_get(layout, storage, field); - h = rb_hash_uint(h, NUM2LONG(rb_funcall(field_val, hash_sym, 0))); - } - h = rb_hash_end(h); - - return INT2FIX(h); -} - -VALUE layout_inspect(MessageLayout* layout, void* storage) { - VALUE str = rb_str_new2(""); - - upb_msg_field_iter it; - bool first = true; - for (upb_msg_field_begin(&it, layout->msgdef); - !upb_msg_field_done(&it); - upb_msg_field_next(&it)) { - const upb_fielddef* field = upb_msg_iter_field(&it); - VALUE field_val = layout_get(layout, storage, field); - - if (!first) { - str = rb_str_cat2(str, ", "); - } else { - first = false; - } - str = rb_str_cat2(str, upb_fielddef_name(field)); - str = rb_str_cat2(str, ": "); - - str = rb_str_append(str, rb_funcall(field_val, rb_intern("inspect"), 0)); - } - - return str; -} |