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); } }
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(cTypeError, "Expected Map instance"); } self = ruby_to_Map(val); if (self->key_type != upb_fielddef_type(key_field)) { rb_raise(cTypeError, "Map key type does not match field's key type"); } if (self->value_type != upb_fielddef_type(value_field)) { rb_raise(cTypeError, "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(cTypeError, "Map value type has wrong message/enum class"); } } }
/** * lupb_map_typecheck() * * Checks that the lupb_map at index |narg| can be safely assigned to the * field |f| of the message at index |msg|. If so, returns a upb_msgval for * this map. Otherwise, raises a Lua error. */ static upb_msgval lupb_map_typecheck(lua_State *L, int narg, int msg, const upb_fielddef *f) { lupb_map *lmap = lupb_map_check(L, narg); upb_map *map = lmap->map; const upb_msgdef *entry = upb_fielddef_msgsubdef(f); const upb_fielddef *key_field = upb_msgdef_itof(entry, UPB_MAPENTRY_KEY); const upb_fielddef *value_field = upb_msgdef_itof(entry, UPB_MAPENTRY_VALUE); UPB_ASSERT(entry && key_field && value_field); if (upb_map_keytype(map) != upb_fielddef_type(key_field)) { luaL_error(L, "Map key type invalid"); } if (upb_map_valuetype(map) != upb_fielddef_type(value_field)) { luaL_error(L, "Map had incorrect value type (expected: %s, got: %s)", upb_fielddef_type(value_field), upb_map_valuetype(map)); } if (upb_map_valuetype(map) == UPB_TYPE_MESSAGE) { lupb_msgclass_typecheck( L, lupb_msg_msgclassfor(L, msg, upb_fielddef_msgsubdef(value_field)), lmap->value_lmsgclass); } return upb_msgval_map(map); }
VALUE layout_get_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); VALUE str_rb = rb_str_new(str, size); rb_enc_associate(str_rb, (upb_fielddef_type(field) == UPB_TYPE_BYTES) ? kRubyString8bitEncoding : kRubyStringUtf8Encoding); rb_obj_freeze(str_rb); return str_rb; } default: return Qnil; } }
static void field_endmsg(void *_r, upb_status *status) { upb_descreader *r = _r; upb_fielddef *f = r->f; // TODO: verify that all required fields were present. assert(upb_fielddef_number(f) != 0 && upb_fielddef_name(f) != NULL); assert((upb_fielddef_subdefname(f) != NULL) == upb_fielddef_hassubdef(f)); if (r->default_string) { if (upb_fielddef_issubmsg(f)) { upb_status_seterrliteral(status, "Submessages cannot have defaults."); return; } if (upb_fielddef_isstring(f) || upb_fielddef_type(f) == UPB_TYPE(ENUM)) { upb_fielddef_setdefaultcstr(f, r->default_string); } else { upb_value val; upb_value_setptr(&val, NULL); // Silence inaccurate compiler warnings. if (!parse_default(r->default_string, &val, upb_fielddef_type(f))) { // We don't worry too much about giving a great error message since the // compiler should have ensured this was correct. upb_status_seterrliteral(status, "Error converting default value."); return; } upb_fielddef_setdefault(f, val); } } }
// Set up handlers for a singular field. static void add_handlers_for_singular_field(upb_handlers *h, const upb_fielddef *f, size_t offset) { switch (upb_fielddef_type(f)) { case UPB_TYPE_BOOL: case UPB_TYPE_INT32: case UPB_TYPE_UINT32: case UPB_TYPE_ENUM: case UPB_TYPE_FLOAT: case UPB_TYPE_INT64: case UPB_TYPE_UINT64: case UPB_TYPE_DOUBLE: upb_shim_set(h, f, offset, -1); break; case UPB_TYPE_STRING: case UPB_TYPE_BYTES: { bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES; upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset)); upb_handlers_setstartstr(h, f, is_bytes ? bytes_handler : str_handler, &attr); upb_handlers_setstring(h, f, stringdata_handler, &attr); upb_handlerattr_uninit(&attr); break; } case UPB_TYPE_MESSAGE: { upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; upb_handlerattr_sethandlerdata(&attr, newsubmsghandlerdata(h, offset, f)); upb_handlers_setstartsubmsg(h, f, submsg_handler, &attr); upb_handlerattr_uninit(&attr); break; } } }
const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len) { assert(f->type_is_set_); assert(upb_fielddef_type(f) == UPB_TYPE_STRING || upb_fielddef_type(f) == UPB_TYPE_BYTES || upb_fielddef_type(f) == UPB_TYPE_ENUM); if (f->default_is_string) { str_t *str = f->defaultval.bytes; if (len) *len = str->len; return str->str; } return NULL; }
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; }
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_name(field), 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_name(field), upb_fielddef_type(field), field_type_class(field), memory, val); } if (layout->fields[upb_fielddef_index(field)].hasbit != MESSAGE_FIELD_NO_HASBIT) { slot_set_hasbit(layout, storage, field); } }
/** * lupb_msg_index * * Handles: * msg.foo * msg["foo"] * msg[field_descriptor] # (for extensions) (TODO) */ static int lupb_msg_index(lua_State *L) { lupb_msg *lmsg = lupb_msg_check(L, 1); const upb_fielddef *f = lupb_msg_checkfield(L, lmsg, 2); const upb_msglayout *l = lmsg->lmsgclass->layout; if (in_userval(f)) { lupb_uservalgeti(L, 1, lupb_fieldindex(f)); if (lua_isnil(L, -1)) { /* Check if we need to lazily create wrapper. */ if (upb_fielddef_isseq(f)) { /* TODO(haberman) */ } else if (upb_fielddef_issubmsg(f)) { /* TODO(haberman) */ } else { UPB_ASSERT(upb_fielddef_isstring(f)); if (upb_msg_has(lmsg->msg, f, l)) { upb_msgval val = upb_msg_get(lmsg->msg, f, l); lua_pop(L, 1); lua_pushlstring(L, val.str.ptr, val.str.len); lupb_uservalseti(L, 1, lupb_fieldindex(f), -1); } } } } else { lupb_pushmsgval(L, upb_fielddef_type(f), upb_msg_get(lmsg->msg, f, l)); } return 1; }
static uint8_t upb_msg_fielddefsize(const upb_fielddef *f) { if (upb_fielddef_isseq(f)) { return sizeof(void*); } else { return upb_msgval_sizeof2(upb_fielddef_type(f)); } }
bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset, int32_t hasbit) { upb_shim_data *d = malloc(sizeof(*d)); if (!d) return false; d->offset = offset; d->hasbit = hasbit; upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; upb_handlerattr_sethandlerdata(&attr, d, free); upb_handlerattr_setalwaysok(&attr, true); #define TYPE(u, l) \ case UPB_TYPE_##u: \ ok = upb_handlers_set##l(h, f, upb_shim_set##l, &attr); break; bool ok = false; switch (upb_fielddef_type(f)) { TYPE(INT64, int64); TYPE(INT32, int32); TYPE(ENUM, int32); TYPE(UINT64, uint64); TYPE(UINT32, uint32); TYPE(DOUBLE, double); TYPE(FLOAT, float); TYPE(BOOL, bool); default: assert(false); break; } #undef TYPE upb_handlerattr_uninit(&attr); return ok; }
/* * call-seq: * FieldDescriptor.type => type * * Returns this field's type, as a Ruby symbol, or nil if not yet set. * * Valid field types are: * :int32, :int64, :uint32, :uint64, :float, :double, :bool, :string, * :bytes, :message. */ VALUE FieldDescriptor_type(VALUE _self) { DEFINE_SELF(FieldDescriptor, self, _self); if (!upb_fielddef_typeisset(self->fielddef)) { return Qnil; } return fieldtype_to_ruby(upb_fielddef_type(self->fielddef)); }
/** * lupb_msg_newindex() * * Handles: * msg.foo = bar * msg["foo"] = bar * msg[field_descriptor] = bar # (for extensions) (TODO) */ static int lupb_msg_newindex(lua_State *L) { lupb_msg *lmsg = lupb_msg_check(L, 1); const upb_fielddef *f = lupb_msg_checkfield(L, lmsg, 2); upb_fieldtype_t type = upb_fielddef_type(f); upb_msgval msgval; /* Typecheck and get msgval. */ if (upb_fielddef_isseq(f)) { msgval = lupb_array_typecheck(L, 3, 1, f); } else if (upb_fielddef_ismap(f)) { msgval = lupb_map_typecheck(L, 3, 1, f); } else { const lupb_msgclass *lmsgclass = NULL; if (type == UPB_TYPE_MESSAGE) { lmsgclass = lupb_msg_getsubmsgclass(L, 1, f); } msgval = lupb_tomsgval(L, type, 3, lmsgclass); } /* Set in upb_msg and userval (if necessary). */ upb_msg_set(lmsg->msg, f, msgval, lmsg->lmsgclass->layout); if (in_userval(f)) { lupb_uservalseti(L, 1, lupb_fieldindex(f), 3); } return 0; /* 1 for chained assignments? */ }
static void putmap(VALUE map, const upb_fielddef *f, upb_sink *sink, int depth) { if (map == Qnil) return; Map* self = ruby_to_Map(map); upb_sink subsink; upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink); assert(upb_fielddef_type(f) == UPB_TYPE_MESSAGE); const upb_fielddef* key_field = map_field_key(f); const upb_fielddef* value_field = map_field_value(f); Map_iter it; for (Map_begin(map, &it); !Map_done(&it); Map_next(&it)) { VALUE key = Map_iter_key(&it); VALUE value = Map_iter_value(&it); upb_sink entry_sink; upb_sink_startsubmsg(&subsink, getsel(f, UPB_HANDLER_STARTSUBMSG), &entry_sink); upb_sink_startmsg(&entry_sink); put_ruby_value(key, key_field, Qnil, depth + 1, &entry_sink); put_ruby_value(value, value_field, self->value_type_class, depth + 1, &entry_sink); upb_status status; upb_sink_endmsg(&entry_sink, &status); upb_sink_endsubmsg(&subsink, getsel(f, UPB_HANDLER_ENDSUBMSG)); } upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ)); }
void upb_fielddef_setdefaultint32(upb_fielddef *f, int32_t value) { if ((upb_fielddef_type(f) == UPB_TYPE_ENUM && checksetdefault(f, UPB_TYPE_ENUM)) || checksetdefault(f, UPB_TYPE_INT32)) { f->defaultval.sint = value; } }
static bool field_endmsg(void *closure, const void *hd, upb_status *status) { UPB_UNUSED(hd); upb_descreader *r = closure; upb_fielddef *f = r->f; // TODO: verify that all required fields were present. assert(upb_fielddef_number(f) != 0); assert(upb_fielddef_name(f) != NULL); assert((upb_fielddef_subdefname(f) != NULL) == upb_fielddef_hassubdef(f)); if (r->default_string) { if (upb_fielddef_issubmsg(f)) { upb_status_seterrmsg(status, "Submessages cannot have defaults."); return false; } if (upb_fielddef_isstring(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM) { upb_fielddef_setdefaultcstr(f, r->default_string, NULL); } else { if (r->default_string && !parse_default(r->default_string, f)) { // We don't worry too much about giving a great error message since the // compiler should have ensured this was correct. upb_status_seterrmsg(status, "Error converting default value."); return false; } } } return true; }
upb_fielddef *upb_fielddef_dup(const upb_fielddef *f, const void *owner) { upb_fielddef *newf = upb_fielddef_new(owner); if (!newf) return NULL; upb_fielddef_settype(newf, upb_fielddef_type(f)); upb_fielddef_setlabel(newf, upb_fielddef_label(f)); upb_fielddef_setnumber(newf, upb_fielddef_number(f), NULL); upb_fielddef_setname(newf, upb_fielddef_name(f), NULL); if (f->default_is_string) { str_t *s = upb_value_getptr(upb_fielddef_default(f)); upb_fielddef_setdefaultstr(newf, s->str, s->len, NULL); } else { upb_fielddef_setdefault(newf, upb_fielddef_default(f)); } const char *srcname; if (f->subdef_is_symbolic) { srcname = f->sub.name; // Might be NULL. } else { srcname = f->sub.def ? upb_def_fullname(f->sub.def) : NULL; } if (srcname) { char *newname = malloc(strlen(f->sub.def->fullname) + 2); if (!newname) { upb_fielddef_unref(newf, owner); return NULL; } strcpy(newname, "."); strcat(newname, f->sub.def->fullname); upb_fielddef_setsubdefname(newf, newname, NULL); free(newname); } return newf; }
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 PyObject *PyUpb_FieldDef_getattro(PyObject *obj, PyObject *attr_name) { upb_fielddef *f = Check_FieldDef(obj, NULL); if (!upb_fielddef_ismutable(f)) { PyErr_SetString(PyExc_TypeError, "fielddef is not mutable."); return NULL; } const char *name = PyString_AsString(attr_name); if (streql(name, "name")) { const char *name = upb_fielddef_name(f); return name == NULL ? Py_None : PyString_FromString(name); } else if (streql(name, "number")) { uint32_t num = upb_fielddef_number(f); return num == 0 ? Py_None : PyInt_FromLong(num); } else if (streql(name, "type")) { uint8_t type = upb_fielddef_type(f); return type == 0 ? Py_None : PyInt_FromLong(type); } else if (streql(name, "label")) { return PyInt_FromLong(upb_fielddef_label(f)); } else if (streql(name, "type_name")) { const char *name = upb_fielddef_typename(f); return name == NULL ? Py_None : PyString_FromString(name); } else if (streql(name, "subdef")) { // NYI; return NULL; } else if (streql(name, "msgdef")) { // NYI; return NULL; } else { return PyUpb_Error("Invalid fielddef member."); } }
static void upb_fielddef_init_default(upb_fielddef *f) { f->default_is_string = false; switch (upb_fielddef_type(f)) { case UPB_TYPE(DOUBLE): upb_value_setdouble(&f->defaultval, 0); break; case UPB_TYPE(FLOAT): upb_value_setfloat(&f->defaultval, 0); break; case UPB_TYPE(UINT64): case UPB_TYPE(FIXED64): upb_value_setuint64(&f->defaultval, 0); break; case UPB_TYPE(INT64): case UPB_TYPE(SFIXED64): case UPB_TYPE(SINT64): upb_value_setint64(&f->defaultval, 0); break; case UPB_TYPE(ENUM): case UPB_TYPE(INT32): case UPB_TYPE(SINT32): case UPB_TYPE(SFIXED32): upb_value_setint32(&f->defaultval, 0); break; case UPB_TYPE(UINT32): case UPB_TYPE(FIXED32): upb_value_setuint32(&f->defaultval, 0); break; case UPB_TYPE(BOOL): upb_value_setbool(&f->defaultval, false); break; case UPB_TYPE(STRING): case UPB_TYPE(BYTES): upb_value_setbyteregion(&f->defaultval, upb_byteregion_new("")); f->default_is_string = true; break; case UPB_TYPE(GROUP): case UPB_TYPE(MESSAGE): upb_value_setptr(&f->defaultval, NULL); break; case UPB_TYPE_NONE: break; } }
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(cTypeError, "Expected repeated field array"); } self = ruby_to_RepeatedField(val); if (self->field_type != upb_fielddef_type(field)) { rb_raise(cTypeError, "Repeated field array has wrong element type"); } if (self->field_type == UPB_TYPE_MESSAGE) { if (self->field_type_class != Descriptor_msgclass(get_def_obj(upb_fielddef_subdef(field)))) { rb_raise(cTypeError, "Repeated field array has wrong message class"); } } if (self->field_type == UPB_TYPE_ENUM) { if (self->field_type_class != EnumDescriptor_enummodule(get_def_obj(upb_fielddef_subdef(field)))) { rb_raise(cTypeError, "Repeated field array has wrong enum class"); } } }
/* * 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; }
/** * lupb_array_typecheck() * * Verifies that the lupb_array object at index |narg| can be safely assigned * to the field |f| of the lupb_msg object at index |msg|. If this is safe, * returns a upb_msgval representing the array. Otherwise, throws a Lua error. */ static upb_msgval lupb_array_typecheck(lua_State *L, int narg, int msg, const upb_fielddef *f) { lupb_array *larray = lupb_array_check(L, narg); if (upb_array_type(larray->arr) != upb_fielddef_type(f) || lupb_msg_getsubmsgclass(L, msg, f) != larray->lmsgclass) { luaL_error(L, "Array had incorrect type (expected: %d, got: %d)", (int)upb_fielddef_type(f), (int)upb_array_type(larray->arr)); } if (upb_array_type(larray->arr) == UPB_TYPE_MESSAGE) { lupb_msgclass_typecheck(L, lupb_msg_getsubmsgclass(L, msg, f), larray->lmsgclass); } return upb_msgval_arr(larray->arr); }
/** * lupb_msgclass_getsubmsgclass() * * Given a MessageClass at index |narg| and the submessage field |f|, returns * the message class for this field. * * Currently we do a hash table lookup for this. If we wanted we could try to * optimize this by caching these pointers in our msgclass, in an array indexed * by field index. We would still need to fall back to calling msgclassfor(), * unless we wanted to eagerly create message classes for all submessages. But * for big schemas that might be a lot of things to build, and we might end up * not using most of them. */ static const lupb_msgclass *lupb_msgclass_getsubmsgclass(lua_State *L, int narg, const upb_fielddef *f) { if (upb_fielddef_type(f) != UPB_TYPE_MESSAGE) { return NULL; } return lupb_msgclass_msgclassfor(L, narg, upb_fielddef_msgsubdef(f)); }
bool is_map_field(const upb_fielddef* field) { if (upb_fielddef_label(field) != UPB_LABEL_REPEATED || upb_fielddef_type(field) != UPB_TYPE_MESSAGE) { return false; } const upb_msgdef* subdef = upb_fielddef_msgsubdef(field); return upb_msgdef_mapentry(subdef); }
static void onmreg(const void *c, upb_handlers *h) { const upb_msgdef *m = upb_handlers_msgdef(h); upb_msg_field_iter i; UPB_UNUSED(c); upb_handlers_setstartmsg(h, textprinter_startmsg, NULL); upb_handlers_setendmsg(h, textprinter_endmsg, NULL); for(upb_msg_field_begin(&i, m); !upb_msg_field_done(&i); upb_msg_field_next(&i)) { upb_fielddef *f = upb_msg_iter_field(&i); upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; upb_handlerattr_sethandlerdata(&attr, f); switch (upb_fielddef_type(f)) { case UPB_TYPE_INT32: upb_handlers_setint32(h, f, textprinter_putint32, &attr); break; case UPB_TYPE_INT64: upb_handlers_setint64(h, f, textprinter_putint64, &attr); break; case UPB_TYPE_UINT32: upb_handlers_setuint32(h, f, textprinter_putuint32, &attr); break; case UPB_TYPE_UINT64: upb_handlers_setuint64(h, f, textprinter_putuint64, &attr); break; case UPB_TYPE_FLOAT: upb_handlers_setfloat(h, f, textprinter_putfloat, &attr); break; case UPB_TYPE_DOUBLE: upb_handlers_setdouble(h, f, textprinter_putdouble, &attr); break; case UPB_TYPE_BOOL: upb_handlers_setbool(h, f, textprinter_putbool, &attr); break; case UPB_TYPE_STRING: case UPB_TYPE_BYTES: upb_handlers_setstartstr(h, f, textprinter_startstr, &attr); upb_handlers_setstring(h, f, textprinter_putstr, &attr); upb_handlers_setendstr(h, f, textprinter_endstr, &attr); break; case UPB_TYPE_MESSAGE: { const char *name = upb_fielddef_istagdelim(f) ? shortname(upb_msgdef_fullname(upb_fielddef_msgsubdef(f))) : upb_fielddef_name(f); upb_handlerattr_sethandlerdata(&attr, name); upb_handlers_setstartsubmsg(h, f, textprinter_startsubmsg, &attr); upb_handlers_setendsubmsg(h, f, textprinter_endsubmsg, &attr); break; } case UPB_TYPE_ENUM: upb_handlers_setint32(h, f, textprinter_putenum, &attr); break; } } }
// Allocates a new map_handlerdata_t given the map entry message definition. If // the offset of the field within the parent message is also given, that is // added to the handler data as well. Note that this is called *twice* per map // field: once in the parent message handler setup when setting the startsubmsg // handler and once in the map entry message handler setup when setting the // key/value and endmsg handlers. The reason is that there is no easy way to // pass the handlerdata down to the sub-message handler setup. static map_handlerdata_t* new_map_handlerdata( size_t ofs, const upb_msgdef* mapentry_def, Descriptor* desc) { const upb_fielddef* key_field; const upb_fielddef* value_field; map_handlerdata_t* hd = ALLOC(map_handlerdata_t); hd->ofs = ofs; key_field = upb_msgdef_itof(mapentry_def, MAP_KEY_FIELD); assert(key_field != NULL); hd->key_field_type = upb_fielddef_type(key_field); value_field = upb_msgdef_itof(mapentry_def, MAP_VALUE_FIELD); assert(value_field != NULL); hd->value_field_type = upb_fielddef_type(value_field); hd->value_field_subdef = upb_fielddef_subdef(value_field); return hd; }
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; }