// Returns the effective closure type for this handler (which will propagate // from outer frames if this frame has no START* handler). Not implemented for // UPB_HANDLER_STRING at the moment since this is not needed. Returns NULL is // the effective closure type is unspecified (either no handler was registered // to specify it or the handler that was registered did not specify the closure // type). const void *effective_closure_type(upb_handlers *h, const upb_fielddef *f, upb_handlertype_t type) { assert(type != UPB_HANDLER_STRING); const void *ret = h->top_closure_type; upb_selector_t sel; if (upb_fielddef_isseq(f) && type != UPB_HANDLER_STARTSEQ && type != UPB_HANDLER_ENDSEQ && h->table[sel = getsel(h, f, UPB_HANDLER_STARTSEQ)].func) { ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr); } if (type == UPB_HANDLER_STRING && h->table[sel = getsel(h, f, UPB_HANDLER_STARTSTR)].func) { ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr); } // The effective type of the submessage; not used yet. // if (type == SUBMESSAGE && // h->table[sel = getsel(h, f, UPB_HANDLER_STARTSUBMSG)].func) { // ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr); // } return ret; }
/** * 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; }
/** * 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 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)); } }
uint32_t upb_handlers_selectorcount(const upb_fielddef *f) { uint32_t ret = 1; if (upb_fielddef_isseq(f)) ret += 2; // STARTSEQ/ENDSEQ if (upb_fielddef_isstring(f)) ret += 2; // [STRING]/STARTSTR/ENDSTR if (upb_fielddef_issubmsg(f)) { // ENDSUBMSG (STARTSUBMSG is at table beginning) ret += 0; if (upb_fielddef_lazy(f)) { // STARTSTR/ENDSTR/STRING (for lazy) ret += 3; } } return ret; }
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 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); }
static bool in_userval(const upb_fielddef *f) { return lupb_istypewrapped(upb_fielddef_type(f)) || upb_fielddef_isseq(f) || upb_fielddef_ismap(f); }
uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f) { return upb_fielddef_isseq(f) ? 2 : 0; }
bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type, upb_selector_t *s) { switch (type) { case UPB_HANDLER_INT32: case UPB_HANDLER_INT64: case UPB_HANDLER_UINT32: case UPB_HANDLER_UINT64: case UPB_HANDLER_FLOAT: case UPB_HANDLER_DOUBLE: case UPB_HANDLER_BOOL: if (!upb_fielddef_isprimitive(f) || upb_handlers_getprimitivehandlertype(f) != type) return false; *s = f->selector_base; break; case UPB_HANDLER_STRING: if (upb_fielddef_isstring(f)) { *s = f->selector_base; } else if (upb_fielddef_issubmsg(f)) { *s = f->selector_base + 3; } else { return false; } break; case UPB_HANDLER_STARTSTR: if (upb_fielddef_isstring(f) || upb_fielddef_issubmsg(f)) { *s = f->selector_base + 1; } else { return false; } break; case UPB_HANDLER_ENDSTR: if (upb_fielddef_isstring(f) || upb_fielddef_issubmsg(f)) { *s = f->selector_base + 2; } else { return false; } break; case UPB_HANDLER_STARTSEQ: if (!upb_fielddef_isseq(f)) return false; *s = f->selector_base - 2; break; case UPB_HANDLER_ENDSEQ: if (!upb_fielddef_isseq(f)) return false; *s = f->selector_base - 1; break; case UPB_HANDLER_STARTSUBMSG: if (!upb_fielddef_issubmsg(f)) return false; // Selectors for STARTSUBMSG are at the beginning of the table so that the // selector can also be used as an index into the "sub" array of // subhandlers. The indexes for the two into these two tables are the // same, except that in the handler table the static selectors come first. *s = f->index_ + UPB_STATIC_SELECTOR_COUNT; break; case UPB_HANDLER_ENDSUBMSG: if (!upb_fielddef_issubmsg(f)) return false; *s = f->selector_base; break; } assert(*s < upb_fielddef_containingtype(f)->selector_count); return true; }
bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) { // TODO: verify we have a transitive closure. for (int i = 0; i < n; i++) { upb_handlers *h = handlers[i]; if (!upb_ok(&h->status_)) { upb_status_seterrf(s, "handlers for message %s had error status: %s", upb_msgdef_fullname(upb_handlers_msgdef(h)), upb_status_errmsg(&h->status_)); return false; } // Check that there are no closure mismatches due to missing Start* handlers // or subhandlers with different type-level types. upb_msg_iter j; for(upb_msg_begin(&j, h->msg); !upb_msg_done(&j); upb_msg_next(&j)) { const upb_fielddef *f = upb_msg_iter_field(&j); if (upb_fielddef_isseq(f)) { if (!checkstart(h, f, UPB_HANDLER_STARTSEQ, s)) return false; } if (upb_fielddef_isstring(f)) { if (!checkstart(h, f, UPB_HANDLER_STARTSTR, s)) return false; } if (upb_fielddef_issubmsg(f)) { bool hashandler = false; if (upb_handlers_gethandler(h, getsel(h, f, UPB_HANDLER_STARTSUBMSG)) || upb_handlers_gethandler(h, getsel(h, f, UPB_HANDLER_ENDSUBMSG))) { hashandler = true; } if (upb_fielddef_isseq(f) && (upb_handlers_gethandler(h, getsel(h, f, UPB_HANDLER_STARTSEQ)) || upb_handlers_gethandler(h, getsel(h, f, UPB_HANDLER_ENDSEQ)))) { hashandler = true; } if (hashandler && !upb_handlers_getsubhandlers(h, f)) { // For now we add an empty subhandlers in this case. It makes the // decoder code generator simpler, because it only has to handle two // cases (submessage has handlers or not) as opposed to three // (submessage has handlers in enclosing message but no subhandlers). // // This makes parsing less efficient in the case that we want to // notice a submessage but skip its contents (like if we're testing // for submessage presence or counting the number of repeated // submessages). In this case we will end up parsing the submessage // field by field and throwing away the results for each, instead of // skipping the whole delimited thing at once. If this is an issue we // can revisit it, but do remember that this only arises when you have // handlers (startseq/startsubmsg/endsubmsg/endseq) set for the // submessage but no subhandlers. The uses cases for this are // limited. upb_handlers *sub = upb_handlers_new(upb_fielddef_msgsubdef(f), &sub); upb_handlers_setsubhandlers(h, f, sub); upb_handlers_unref(sub, &sub); } // TODO(haberman): check type of submessage. // This is slightly tricky; also consider whether we should check that // they match at setsubhandlers time. } } } if (!upb_refcounted_freeze((upb_refcounted*const*)handlers, n, s, UPB_MAX_HANDLER_DEPTH)) { return false; } return true; }
static bool doset(upb_handlers *h, int32_t sel, const upb_fielddef *f, upb_handlertype_t type, upb_func *func, upb_handlerattr *attr) { assert(!upb_handlers_isfrozen(h)); if (sel < 0) { upb_status_seterrmsg(&h->status_, "incorrect handler type for this field."); return false; } if (h->table[sel].func) { upb_status_seterrmsg(&h->status_, "cannot change handler once it has been set."); return false; } upb_handlerattr set_attr = UPB_HANDLERATTR_INITIALIZER; if (attr) { set_attr = *attr; } // Check that the given closure type matches the closure type that has been // established for this context (if any). const void *closure_type = upb_handlerattr_closuretype(&set_attr); const void **context_closure_type; if (type == UPB_HANDLER_STRING) { context_closure_type = returntype(h, f, UPB_HANDLER_STARTSTR); } else if (f && upb_fielddef_isseq(f) && type != UPB_HANDLER_STARTSEQ && type != UPB_HANDLER_ENDSEQ) { context_closure_type = returntype(h, f, UPB_HANDLER_STARTSEQ); } else { context_closure_type = &h->top_closure_type; } if (closure_type && *context_closure_type && closure_type != *context_closure_type) { // TODO(haberman): better message for debugging. upb_status_seterrmsg(&h->status_, "closure type does not match"); return false; } if (closure_type) *context_closure_type = closure_type; // If this is a STARTSEQ or STARTSTR handler, check that the returned pointer // matches any pre-existing expectations about what type is expected. if (type == UPB_HANDLER_STARTSEQ || type == UPB_HANDLER_STARTSTR) { const void *return_type = upb_handlerattr_returnclosuretype(&set_attr); const void *table_return_type = upb_handlerattr_returnclosuretype(&h->table[sel].attr); if (return_type && table_return_type && return_type != table_return_type) { upb_status_seterrmsg(&h->status_, "closure return type does not match"); return false; } if (table_return_type && !return_type) upb_handlerattr_setreturnclosuretype(&set_attr, table_return_type); } h->table[sel].func = (upb_func*)func; h->table[sel].attr = set_attr; return true; }
static void newhandlers_callback(const void *closure, upb_handlers *h) { UPB_UNUSED(closure); upb_handlers_setstartmsg(h, startmsg, NULL); upb_handlers_setendmsg(h, endmsg, NULL); const upb_msgdef *m = upb_handlers_msgdef(h); upb_msg_field_iter i; for(upb_msg_field_begin(&i, m); !upb_msg_field_done(&i); upb_msg_field_next(&i)) { const upb_fielddef *f = upb_msg_iter_field(&i); bool packed = upb_fielddef_isseq(f) && upb_fielddef_isprimitive(f) && upb_fielddef_packed(f); upb_handlerattr attr; upb_wiretype_t wt = packed ? UPB_WIRE_TYPE_DELIMITED : upb_pb_native_wire_types[upb_fielddef_descriptortype(f)]; // Pre-encode the tag for this field. new_tag(h, f, wt, &attr); if (packed) { upb_handlers_setstartseq(h, f, encode_startdelimfield, &attr); upb_handlers_setendseq(h, f, encode_enddelimfield, &attr); } #define T(upper, lower, upbtype) \ case UPB_DESCRIPTOR_TYPE_##upper: \ if (packed) { \ upb_handlers_set##upbtype(h, f, encode_packed_##lower, &attr); \ } else { \ upb_handlers_set##upbtype(h, f, encode_scalar_##lower, &attr); \ } \ break; switch (upb_fielddef_descriptortype(f)) { T(DOUBLE, double, double); T(FLOAT, float, float); T(INT64, int64, int64); T(INT32, int32, int32); T(FIXED64, fixed64, uint64); T(FIXED32, fixed32, uint32); T(BOOL, bool, bool); T(UINT32, uint32, uint32); T(UINT64, uint64, uint64); T(ENUM, enum, int32); T(SFIXED32, sfixed32, int32); T(SFIXED64, sfixed64, int64); T(SINT32, sint32, int32); T(SINT64, sint64, int64); case UPB_DESCRIPTOR_TYPE_STRING: case UPB_DESCRIPTOR_TYPE_BYTES: upb_handlers_setstartstr(h, f, encode_startstr, &attr); upb_handlers_setendstr(h, f, encode_enddelimfield, &attr); upb_handlers_setstring(h, f, encode_strbuf, &attr); break; case UPB_DESCRIPTOR_TYPE_MESSAGE: upb_handlers_setstartsubmsg(h, f, encode_startdelimfield, &attr); upb_handlers_setendsubmsg(h, f, encode_enddelimfield, &attr); break; case UPB_DESCRIPTOR_TYPE_GROUP: { // Endgroup takes a different tag (wire_type = END_GROUP). upb_handlerattr attr2; new_tag(h, f, UPB_WIRE_TYPE_END_GROUP, &attr2); upb_handlers_setstartsubmsg(h, f, encode_startgroup, &attr); upb_handlers_setendsubmsg(h, f, encode_endgroup, &attr2); upb_handlerattr_uninit(&attr2); break; } } #undef T upb_handlerattr_uninit(&attr); } }