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 { if (field_contains_hasbit(layout, field)) { if (!slot_is_hasbit_set(layout, from, field)) continue; slot_set_hasbit(layout, to, field); } native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory); } } }
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); bool field_set; if (field_contains_hasbit(layout, field)) { field_set = slot_is_hasbit_set(layout, storage, field); } else { field_set = true; } if (upb_fielddef_containingoneof(field)) { if (*oneof_case != upb_fielddef_number(field)) { return layout_get_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 if (!field_set) { return layout_get_default(field); } else { return native_slot_get(upb_fielddef_type(field), field_type_class(field), memory); } }
void layout_clear(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 (field_contains_hasbit(layout, field)) { slot_clear_hasbit(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_set(upb_fielddef_name(field), upb_fielddef_type(field), field_type_class(field), memory, layout_get_default(field)); } }
/* * call-seq: * Message.to_h => {} * * Returns the message as a Ruby Hash object, with keys as symbols. */ VALUE Message_to_h(VALUE _self) { MessageHeader* self; VALUE hash; upb_msg_field_iter it; TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); hash = rb_hash_new(); for (upb_msg_field_begin(&it, self->descriptor->msgdef); !upb_msg_field_done(&it); upb_msg_field_next(&it)) { const upb_fielddef* field = upb_msg_iter_field(&it); // For proto2, do not include fields which are not set. if (upb_msgdef_syntax(self->descriptor->msgdef) == UPB_SYNTAX_PROTO2 && field_contains_hasbit(self->descriptor->layout, field) && !layout_has(self->descriptor->layout, Message_data(self), field)) { continue; } VALUE msg_value = layout_get(self->descriptor->layout, Message_data(self), field); VALUE msg_key = ID2SYM(rb_intern(upb_fielddef_name(field))); if (is_map_field(field)) { msg_value = Map_to_h(msg_value); } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { msg_value = RepeatedField_to_ary(msg_value); if (upb_msgdef_syntax(self->descriptor->msgdef) == UPB_SYNTAX_PROTO2 && RARRAY_LEN(msg_value) == 0) { continue; } if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) { for (int i = 0; i < RARRAY_LEN(msg_value); i++) { VALUE elem = rb_ary_entry(msg_value, i); rb_ary_store(msg_value, i, Message_to_h(elem)); } } } else if (msg_value != Qnil && upb_fielddef_type(field) == UPB_TYPE_MESSAGE) { msg_value = Message_to_h(msg_value); } rb_hash_aset(hash, msg_key, msg_value); } return hash; }
VALUE layout_has(MessageLayout* layout, const void* storage, const upb_fielddef* field) { assert(field_contains_hasbit(layout, field)); return slot_is_hasbit_set(layout, storage, field) ? Qtrue : Qfalse; }