// TODO(haberman): discard upb_handlers* objects that do not actually have any // handlers set and cannot reach any upb_handlers* object that does. This is // slightly tricky to do correctly. static upb_handlers *newformsg(const upb_msgdef *m, const void *owner, dfs_state *s) { upb_handlers *h = upb_handlers_new(m, owner); if (!h) return NULL; if (!upb_inttable_insertptr(&s->tab, m, upb_value_ptr(h))) goto oom; s->callback(s->closure, h); // For each submessage field, get or create a handlers object and set it as // the subhandlers. upb_msg_iter i; for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) { upb_fielddef *f = upb_msg_iter_field(&i); if (!upb_fielddef_issubmsg(f)) continue; const upb_msgdef *subdef = upb_downcast_msgdef(upb_fielddef_subdef(f)); upb_value subm_ent; if (upb_inttable_lookupptr(&s->tab, subdef, &subm_ent)) { upb_handlers_setsubhandlers(h, f, upb_value_getptr(subm_ent)); } else { upb_handlers *sub_mh = newformsg(subdef, &sub_mh, s); if (!sub_mh) goto oom; upb_handlers_setsubhandlers(h, f, sub_mh); upb_handlers_unref(sub_mh, &sub_mh); } } return h; oom: upb_handlers_unref(h, owner); return NULL; }
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); } } }
bool upb_symtab_dfs(upb_def *def, upb_def **open_defs, int n, upb_strtable *addtab) { // This linear search makes the DFS O(n^2) in the length of the paths. // Could make this O(n) with a hash table, but n is small. for (int i = 0; i < n; i++) { if (def == open_defs[i]) return false; } bool needcopy = false; upb_msgdef *m = upb_dyncast_msgdef(def); if (m) { upb_msg_iter i; open_defs[n++] = def; for(i = upb_msg_begin(m); !upb_msg_done(i); i = upb_msg_next(m, i)) { upb_fielddef *f = upb_msg_iter_field(i); if (!upb_hassubdef(f)) continue; needcopy |= upb_symtab_dfs(f->def, open_defs, n, addtab); } } bool replacing = (upb_strtable_lookup(addtab, m->base.fqname) != NULL); if (needcopy && !replacing) { upb_symtab_ent e = {upb_def_dup(def)}; upb_strtable_insert(addtab, def->fqname, &e); replacing = true; } return replacing; }
// narg is a lua table containing a list of defs to add. static PyObject *PyUpb_SymbolTable_add_defs(PyObject *o, PyObject *defs) { upb_symtab *s = Check_SymbolTable(o, NULL); if (!PySequence_Check(defs)) return PyUpb_Error("Must be a sequence"); Py_ssize_t n = PySequence_Length(defs); // Prevent stack overflow. if (n > 2048) return PyUpb_Error("Too many defs"); upb_def *cdefs[n]; int i = 0; for (i = 0; i < n; i++) { PyObject *pydef = PySequence_GetItem(defs, i); upb_def *def = Check_MessageDef(pydef, NULL); cdefs[i++] = def; upb_msgdef *md = upb_dyncast_msgdef(def); if (!md) continue; upb_msg_field_iter j; for(upb_msg_field_begin(&j, md); !upb_msg_field_done(&j); upb_msg_field_next(&j)) { upb_fielddef *f = upb_msg_iter_field(j); upb_fielddef_setaccessor(f, PyUpb_AccessorForField(f)); } upb_msgdef_layout(md); } upb_status status = UPB_STATUS_INIT; upb_symtab_add(s, cdefs, n, &status); PyUpb_CheckStatus(&status); return Py_None; }
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); } } }
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; } } }
static void visitmsg(const upb_refcounted *r, upb_refcounted_visit *visit, void *closure) { const upb_msgdef *m = (const upb_msgdef*)r; upb_msg_iter i; for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) { upb_fielddef *f = upb_msg_iter_field(&i); visit(r, upb_upcast2(f), closure); } }
static void upb_msgdef_free(upb_msgdef *m) { upb_msg_iter i; for(i = upb_msg_begin(m); !upb_msg_done(i); i = upb_msg_next(m, i)) upb_fielddef_free(upb_msg_iter_field(i)); upb_strtable_free(&m->ntof); upb_inttable_free(&m->itof); upb_def_uninit(&m->base); free(m); }
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)) { layout_clear(layout, storage, upb_msg_iter_field(&it)); } }
static void validate_msgdef(const upb_msgdef* msgdef) { // Verify that no required fields exist. proto3 does not support these. upb_msg_iter it; for (upb_msg_begin(&it, msgdef); !upb_msg_done(&it); upb_msg_next(&it)) { const upb_fielddef* field = upb_msg_iter_field(&it); if (upb_fielddef_label(field) == UPB_LABEL_REQUIRED) { rb_raise(rb_eTypeError, "Required fields are unsupported in proto3."); } } }
static void visithandlers(const upb_refcounted *r, upb_refcounted_visit *visit, void *closure) { const upb_handlers *h = (const upb_handlers*)r; upb_msg_iter i; for(upb_msg_begin(&i, h->msg); !upb_msg_done(&i); upb_msg_next(&i)) { upb_fielddef *f = upb_msg_iter_field(&i); if (!upb_fielddef_issubmsg(f)) continue; const upb_handlers *sub = upb_handlers_getsubhandlers(h, f); if (sub) visit(r, UPB_UPCAST(sub), closure); } }
upb_msgdef *upb_msgdef_dup(const upb_msgdef *m) { upb_msgdef *newm = upb_msgdef_new(); newm->size = m->size; newm->hasbit_bytes = m->hasbit_bytes; newm->extstart = m->extstart; newm->extend = m->extend; upb_msg_iter i; for(i = upb_msg_begin(m); !upb_msg_done(i); i = upb_msg_next(m, i)) { upb_msgdef_addfield(newm, upb_fielddef_dup(upb_msg_iter_field(i))); } return newm; }
static PyObject *PyUpb_MessageDef_fields(PyObject *obj, PyObject *args) { upb_msgdef *m = Check_MessageDef(obj, NULL); PyObject *ret = PyList_New(0); upb_msg_field_iter i; for(upb_msg_field_begin(&i, m); !upb_msg_field_done(&i); upb_msg_field_next(&ii)) { upb_fielddef *f = upb_msg_iter_field(&i); PyList_Append(ret, PyUpb_FieldDef_GetOrCreate(f)); } return ret; }
/* * call-seq: * Descriptor.each(&block) * * Iterates over fields in this message type, yielding to the block on each one. */ VALUE Descriptor_each(VALUE _self) { DEFINE_SELF(Descriptor, self, _self); upb_msg_iter it; for (upb_msg_begin(&it, self->msgdef); !upb_msg_done(&it); upb_msg_next(&it)) { const upb_fielddef* field = upb_msg_iter_field(&it); VALUE obj = get_def_obj(field); rb_yield(obj); } return Qnil; }
upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner) { upb_msgdef *newm = upb_msgdef_new(owner); if (!newm) return NULL; upb_def_setfullname(upb_upcast(newm), upb_def_fullname(upb_upcast(m))); upb_msg_iter i; for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) { upb_fielddef *f = upb_fielddef_dup(upb_msg_iter_field(&i), &f); if (!f || !upb_msgdef_addfield(newm, f, &f)) { upb_msgdef_unref(newm, owner); return NULL; } } return newm; }
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); }
bool upb_def_freeze(upb_def *const* defs, int n, upb_status *s) { // First perform validation, in two passes so we can check that we have a // transitive closure without needing to search. for (int i = 0; i < n; i++) { upb_def *def = defs[i]; if (upb_def_isfrozen(def)) { // Could relax this requirement if it's annoying. upb_status_seterrliteral(s, "def is already frozen"); goto err; } else if (def->type == UPB_DEF_FIELD) { upb_status_seterrliteral(s, "standalone fielddefs can not be frozen"); goto err; } else { // Set now to detect transitive closure in the second pass. def->came_from_user = true; } } for (int i = 0; i < n; i++) { upb_msgdef *m = upb_dyncast_msgdef_mutable(defs[i]); upb_enumdef *e = upb_dyncast_enumdef_mutable(defs[i]); if (m) { upb_inttable_compact(&m->itof); upb_msg_iter j; uint32_t selector = UPB_STATIC_SELECTOR_COUNT; for(upb_msg_begin(&j, m); !upb_msg_done(&j); upb_msg_next(&j)) { upb_fielddef *f = upb_msg_iter_field(&j); assert(f->msgdef == m); if (!upb_validate_field(f, s)) goto err; f->selector_base = selector + upb_handlers_selectorbaseoffset(f); selector += upb_handlers_selectorcount(f); } m->selector_count = selector; } else if (e) { upb_inttable_compact(&e->iton); } } // Validation all passed; freeze the defs. return upb_refcounted_freeze((upb_refcounted*const*)defs, n, s); err: for (int i = 0; i < n; i++) { defs[i]->came_from_user = false; } assert(!upb_ok(s)); return false; }
upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner) { upb_msgdef *newm = upb_msgdef_new(owner); if (!newm) return NULL; bool ok = upb_def_setfullname(UPB_UPCAST(newm), upb_def_fullname(UPB_UPCAST(m)), NULL); UPB_ASSERT_VAR(ok, ok); upb_msg_iter i; for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) { upb_fielddef *f = upb_fielddef_dup(upb_msg_iter_field(&i), &f); if (!f || !upb_msgdef_addfield(newm, f, &f, NULL)) { upb_msgdef_unref(newm, owner); return NULL; } } return newm; }
/* * 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; }
void upb_msgdef_layout(upb_msgdef *m) { // Create an ordering over the fields, but only include fields with accessors. upb_fielddef **sorted_fields = malloc(sizeof(upb_fielddef*) * upb_msgdef_numfields(m)); int n = 0; upb_msg_iter i; for (i = upb_msg_begin(m); !upb_msg_done(i); i = upb_msg_next(m, i)) { upb_fielddef *f = upb_msg_iter_field(i); if (f->accessor) sorted_fields[n++] = f; } m->hasbit_bytes = upb_div_round_up(n, 8); m->size = m->hasbit_bytes; // + header_size? // Assign hasbits. qsort(sorted_fields, n, sizeof(*sorted_fields), upb_fielddef_cmphasbit); for (int i = 0; i < n; i++) { upb_fielddef *f = sorted_fields[i]; f->hasbit = i; } // Assign value offsets. qsort(sorted_fields, n, sizeof(*sorted_fields), upb_fielddef_cmpval); size_t max_align = 0; for (int i = 0; i < n; i++) { upb_fielddef *f = sorted_fields[i]; const upb_type_info *type_info = &upb_types[f->type]; size_t size = type_info->size; size_t align = type_info->align; if (upb_isseq(f)) { size = sizeof(void*); align = alignof(void*); } // General alignment rules are: each member must be at an address that is a // multiple of that type's alignment. Also, the size of the structure as a // whole must be a multiple of the greatest alignment of any member. f->offset = upb_align_up(m->size, align); m->size = f->offset + size; max_align = UPB_MAX(max_align, align); } if (max_align > 0) m->size = upb_align_up(m->size, max_align); free(sorted_fields); }
static upb_flow_t upb_msg_dispatch(upb_msg *msg, upb_msgdef *md, upb_dispatcher *d) { upb_msg_iter i; for(i = upb_msg_begin(md); !upb_msg_done(i); i = upb_msg_next(md, i)) { upb_fielddef *f = upb_msg_iter_field(i); if (!upb_msg_has(msg, f)) continue; upb_fhandlers *hf = upb_dispatcher_lookup(d, f->number); if (!hf) continue; upb_value val = upb_msg_get(msg, f); if (upb_isarray(f)) { upb_array *arr = upb_value_getarr(val); for (uint32_t j = 0; j < upb_array_len(arr); ++j) { upb_msg_pushval(upb_array_get(arr, f, j), f, d, hf); } } else { upb_msg_pushval(val, f, d, hf); } } return UPB_CONTINUE; }
VALUE Message_to_h(VALUE _self) { MessageHeader* self; TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); VALUE hash = rb_hash_new(); upb_msg_field_iter it; 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); VALUE msg_value = layout_get(self->descriptor->layout, Message_data(self), field); VALUE msg_key = ID2SYM(rb_intern(upb_fielddef_name(field))); if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { msg_value = RepeatedField_to_ary(msg_value); } rb_hash_aset(hash, msg_key, msg_value); } return hash; }
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 upb_stdmsg_free(void *m, const upb_msgdef *md) { if (m == NULL) return; upb_msg_iter i; for(i = upb_msg_begin(md); !upb_msg_done(i); i = upb_msg_next(md, i)) { upb_fielddef *f = upb_msg_iter_field(i); if (!upb_isseq(f) && !upb_issubmsg(f) && !upb_isstring(f)) continue; void *subp = upb_value_getptr(upb_stdmsg_getptr(m, f->fval)); if (subp == NULL) continue; if (upb_isseq(f)) { upb_stdseq_free(subp, f); } else if (upb_issubmsg(f)) { upb_stdmsg_free(subp, upb_downcast_msgdef(f->def)); } else { upb_stdarray *str = subp; free(str->ptr); free(str); } } free(m); }
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 (slot_is_hasbit_set(layout, msg1, field) != slot_is_hasbit_set(layout, msg2, field) || !native_slot_eq(upb_fielddef_type(field), msg1_memory, msg2_memory)) { return Qfalse; } } } return Qtrue; }
static void add_handlers_for_message(const void *closure, upb_handlers *h) { const upb_msgdef* msgdef = upb_handlers_msgdef(h); Descriptor* desc = ruby_to_Descriptor(get_def_obj((void*)msgdef)); upb_msg_field_iter i; // If this is a mapentry message type, set up a special set of handlers and // bail out of the normal (user-defined) message type handling. if (upb_msgdef_mapentry(msgdef)) { add_handlers_for_mapentry(msgdef, h, desc); return; } // Ensure layout exists. We may be invoked to create handlers for a given // message if we are included as a submsg of another message type before our // class is actually built, so to work around this, we just create the layout // (and handlers, in the class-building function) on-demand. if (desc->layout == NULL) { desc->layout = create_layout(desc->msgdef); } for (upb_msg_field_begin(&i, desc->msgdef); !upb_msg_field_done(&i); upb_msg_field_next(&i)) { const upb_fielddef *f = upb_msg_iter_field(&i); size_t offset = desc->layout->fields[upb_fielddef_index(f)].offset + sizeof(MessageHeader); if (upb_fielddef_containingoneof(f)) { size_t oneof_case_offset = desc->layout->fields[upb_fielddef_index(f)].case_offset + sizeof(MessageHeader); add_handlers_for_oneof_field(h, f, offset, oneof_case_offset); } else if (is_map_field(f)) { add_handlers_for_mapfield(h, f, offset, desc); } else if (upb_fielddef_isseq(f)) { add_handlers_for_repeated_field(h, f, offset); } else { add_handlers_for_singular_field(h, f, offset); } } }
static bool assign_msg_indices(upb_msgdef *m, upb_status *s) { // Sort fields. upb internally relies on UPB_TYPE_MESSAGE fields having the // lowest indexes, but we do not publicly guarantee this. int n = upb_msgdef_numfields(m); upb_fielddef **fields = malloc(n * sizeof(*fields)); if (!fields) return false; upb_msg_iter j; int i; m->submsg_field_count = 0; for(i = 0, upb_msg_begin(&j, m); !upb_msg_done(&j); upb_msg_next(&j), i++) { upb_fielddef *f = upb_msg_iter_field(&j); assert(f->msg.def == m); if (!upb_validate_field(f, s)) { free(fields); return false; } if (upb_fielddef_issubmsg(f)) { m->submsg_field_count++; } fields[i] = f; } qsort(fields, n, sizeof(*fields), cmp_fields); uint32_t selector = UPB_STATIC_SELECTOR_COUNT + m->submsg_field_count; for (i = 0; i < n; i++) { upb_fielddef *f = fields[i]; f->index_ = i; f->selector_base = selector + upb_handlers_selectorbaseoffset(f); selector += upb_handlers_selectorcount(f); } m->selector_count = selector; free(fields); return false; }
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; }
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); size_t hasbit = 0; 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); if (upb_fielddef_haspresence(field)) { layout->fields[upb_fielddef_index(field)].hasbit = hasbit++; } else { layout->fields[upb_fielddef_index(field)].hasbit = MESSAGE_FIELD_NO_HASBIT; } } if (hasbit != 0) { off += (hasbit + 8 - 1) / 8; } 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; }
static void putmsg(VALUE msg_rb, const Descriptor* desc, upb_sink *sink, int depth) { MessageHeader* msg; upb_msg_field_iter i; upb_status status; upb_sink_startmsg(sink); // Protect against cycles (possible because users may freely reassign message // and repeated fields) by imposing a maximum recursion depth. if (depth > ENCODE_MAX_NESTING) { rb_raise(rb_eRuntimeError, "Maximum recursion depth exceeded during encoding."); } TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg); for (upb_msg_field_begin(&i, desc->msgdef); !upb_msg_field_done(&i); upb_msg_field_next(&i)) { upb_fielddef *f = upb_msg_iter_field(&i); uint32_t offset = desc->layout->fields[upb_fielddef_index(f)].offset + sizeof(MessageHeader); if (upb_fielddef_containingoneof(f)) { uint32_t oneof_case_offset = desc->layout->fields[upb_fielddef_index(f)].case_offset + sizeof(MessageHeader); // For a oneof, check that this field is actually present -- skip all the // below if not. if (DEREF(msg, oneof_case_offset, uint32_t) != upb_fielddef_number(f)) { continue; } // Otherwise, fall through to the appropriate singular-field handler // below. } if (is_map_field(f)) { VALUE map = DEREF(msg, offset, VALUE); if (map != Qnil) { putmap(map, f, sink, depth); } } else if (upb_fielddef_isseq(f)) { VALUE ary = DEREF(msg, offset, VALUE); if (ary != Qnil) { putary(ary, f, sink, depth); } } else if (upb_fielddef_isstring(f)) { VALUE str = DEREF(msg, offset, VALUE); if (RSTRING_LEN(str) > 0) { putstr(str, f, sink); } } else if (upb_fielddef_issubmsg(f)) { putsubmsg(DEREF(msg, offset, VALUE), f, sink, depth); } else { upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); #define T(upbtypeconst, upbtype, ctype, default_value) \ case upbtypeconst: { \ ctype value = DEREF(msg, offset, ctype); \ if (value != default_value) { \ upb_sink_put##upbtype(sink, sel, value); \ } \ } \ break; switch (upb_fielddef_type(f)) { T(UPB_TYPE_FLOAT, float, float, 0.0) T(UPB_TYPE_DOUBLE, double, double, 0.0) T(UPB_TYPE_BOOL, bool, uint8_t, 0) case UPB_TYPE_ENUM: T(UPB_TYPE_INT32, int32, int32_t, 0) T(UPB_TYPE_UINT32, uint32, uint32_t, 0) T(UPB_TYPE_INT64, int64, int64_t, 0) T(UPB_TYPE_UINT64, uint64, uint64_t, 0) case UPB_TYPE_STRING: case UPB_TYPE_BYTES: case UPB_TYPE_MESSAGE: rb_raise(rb_eRuntimeError, "Internal error."); } #undef T } } upb_sink_endmsg(sink, &status); }