From 56984e8db8e1c43687535cc77fb6ce43df0b3d1f Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Fri, 29 Jul 2011 17:49:59 -0700 Subject: Significant work on Lua extension. Also changes in core library to accommodate. --- Makefile | 4 +- lang_ext/lua/test.lua | 64 +++++- lang_ext/lua/upb.c | 577 ++++++++++++++++++++++++++++++++------------------ upb/bytestream.h | 13 +- upb/def.c | 129 ++++++++--- upb/def.h | 58 ++--- upb/descriptor.c | 4 +- upb/msg.h | 9 +- upb/upb.h | 2 + 9 files changed, 587 insertions(+), 273 deletions(-) diff --git a/Makefile b/Makefile index c0b9d90..177a221 100644 --- a/Makefile +++ b/Makefile @@ -395,5 +395,5 @@ endif LUAEXT=lang_ext/lua/upb.so lua: $(LUAEXT) lang_ext/lua/upb.so: lang_ext/lua/upb.c $(LIBUPB_PIC) - @echo CC lang_ext/lua/upb.c - @$(CC) $(CFLAGS) $(CPPFLAGS) $(LUA_CPPFLAGS) -fpic -shared -o $@ $< upb/libupb_pic.a $(LUA_LDFLAGS) + $(E) CC lang_ext/lua/upb.c + $(Q) $(CC) $(CFLAGS) $(CPPFLAGS) $(LUA_CPPFLAGS) -fpic -shared -o $@ $< upb/libupb_pic.a $(LUA_LDFLAGS) diff --git a/lang_ext/lua/test.lua b/lang_ext/lua/test.lua index d7f71df..e5bf0ce 100644 --- a/lang_ext/lua/test.lua +++ b/lang_ext/lua/test.lua @@ -1,13 +1,46 @@ require "upb" -symtab = upb.symtab() +symtab = upb.SymbolTable{ + upb.MessageDef{fqname="A", fields={ + upb.FieldDef{name="a", type=upb.TYPE_INT32, number=1}, + upb.FieldDef{name="b", type=upb.TYPE_DOUBLE, number=2}} + } +} + +symtab = upb.SymbolTable{ + upb.MessageDef{fqname="A", fields={ + upb.FieldDef{name="a", type=upb.TYPE_INT32, number=1}, + upb.FieldDef{name="b", type=upb.TYPE_DOUBLE, number=2}} + }, + upb.MessageDef{fqname="B"} +} +A, B, C = symtab:lookup("A", "B") +print(A) +print(B) +print(C) + +a = A() +print("YO! a.a=" .. tostring(a.a)) +a.a = 2 +print("YO! a.a=" .. tostring(a.a)) + +A = symtab:lookup("A") +if not A then + error("Could not find A") +end f = io.open("../../src/descriptor.pb") if not f then error("Couldn't open descriptor.pb, try running 'make descriptorgen'") end symtab:parsedesc(f:read("*all")) +symtab:load_descriptor() +symtab:load_descriptor_file() + +upb.pb.load_descriptor(f:read("*all")) + +upb.pb.load_descriptor_file("../../src/descriptor.pb", symtab) f = io.open("../../benchmarks/google_messages.proto.pb") if not f then @@ -23,10 +56,35 @@ SpeedMessage1 = symtab:lookup("benchmarks.SpeedMessage1") SpeedMessage2 = symtab:lookup("benchmarks.SpeedMessage2") print(SpeedMessage1:name()) -msg = SpeedMessage1() +msg = MyType() +msg:Decode(str) + +msg:DecodeJSON(str) + +msg = upb.pb.decode(str, MyType) +str = upb.pb.encode(msg) + +msg = upb.pb.decode_text(str, MyType) +str = upb.pb.encode_text(msg) + +upb.clear(msg) +upb.msgdef(msg) +upb.has(msg, "foo_bar") + +msg = upb.json.decode(str, MyType) + +msg = upb.pb.DecodeText(str) +msg = upb.pb.EncodeText(msg) +upb. + +upb.pb.decode_into(msg, str) + +str = upb.json.Encode(msg) +upb.json.DecodeInto(msg, str) f = assert(io.open("../../benchmarks/google_message1.dat")) msg:Parse(f:read("*all")) print(msg:ToText()) +print(upb.json.encode(msg)) msg = SpeedMessage2() f = assert(io.open("../../benchmarks/google_message2.dat")) @@ -46,4 +104,4 @@ print(msg:ToText()) -- print(msg.field129) -- msg.field129 = 5 -- print(msg.field129) - +--]] diff --git a/lang_ext/lua/upb.c b/lang_ext/lua/upb.c index 91e0e83..8adf14d 100644 --- a/lang_ext/lua/upb.c +++ b/lang_ext/lua/upb.c @@ -15,7 +15,24 @@ #include "upb/msg.h" #include "upb/pb/glue.h" +static bool streql(const char *a, const char *b) { return strcmp(a, b) == 0; } + +static uint8_t lupb_touint8(lua_State *L, int narg, const char *name) { + lua_Number n = lua_tonumber(L, narg); + if (n > UINT8_MAX || n < 0 || rint(n) != n) + luaL_error(L, "Invalid %s", name); + return n; +} + +static uint32_t lupb_touint32(lua_State *L, int narg, const char *name) { + lua_Number n = lua_tonumber(L, narg); + if (n > UINT32_MAX || n < 0 || rint(n) != n) + luaL_error(L, "Invalid %s", name); + return n; +} + //static void lupb_msg_getorcreate(lua_State *L, upb_msg *msg, upb_msgdef *md); +static void lupb_fielddef_getorcreate(lua_State *L, upb_fielddef *f); // All the def types share the same C layout, even though they are different Lua // types with different metatables. @@ -23,6 +40,23 @@ typedef struct { upb_def *def; } lupb_def; +typedef struct { + upb_fielddef *field; +} lupb_fielddef; + +static lupb_def *lupb_def_check(lua_State *L, int narg) { + void *ldef = luaL_checkudata(L, narg, "upb.msgdef"); + if (!ldef) ldef = luaL_checkudata(L, narg, "upb.enumdef"); + luaL_argcheck(L, ldef != NULL, narg, "upb def expected"); + return ldef; +} + +static lupb_fielddef *lupb_fielddef_check(lua_State *L, int narg) { + lupb_fielddef *f = luaL_checkudata(L, narg, "upb.fielddef"); + luaL_argcheck(L, f != NULL, narg, "upb fielddef expected"); + return f; +} + void lupb_checkstatus(lua_State *L, upb_status *s) { if (!upb_ok(s)) { upb_status_print(s, stderr); @@ -78,52 +112,45 @@ static bool lupb_cache_getorcreate(lua_State *L, void *cobj, const char *type) { return lupb_cache_getorcreate_size(L, cobj, type, sizeof(void*)) != NULL; } +static void lupb_cache_create(lua_State *L, void *cobj, const char *type) { + bool created = + lupb_cache_getorcreate_size(L, cobj, type, sizeof(void*)) != NULL; + (void)created; // For NDEBUG + assert(created); +} -/* lupb_msg********************************************************************/ - -#if 0 -// We prefer field access syntax (foo.bar, foo.bar = 5) over method syntax -// (foo:bar(), foo:set_bar(5)) to make messages behave more like regular tables. -// However, there are methods also, like foo:CopyFrom(other_foo) or foo:Clear(). -typedef struct { - upb_msg *msg; - upb_msgdef *msgdef; -} lupb_msg; +/* lupb_msg********************************************************************/ -static lupb_msg *lupb_msg_check(lua_State *L, int narg) { - return luaL_checkudata(L, narg, "upb.msg"); +// Messages are userdata where we store primitive values (numbers and bools) +// right in the userdata. We also use integer entries in the environment table +// like so: +// {msgdef, } + +static void *lupb_msg_check(lua_State *L, int narg, upb_msgdef **md) { + void *msg = luaL_checkudata(L, narg, "upb.msg"); + luaL_argcheck(L, msg != NULL, narg, "msg expected"); + // If going all the way to the environment table for the msgdef is an + // efficiency issue, we could put the pointer right in the userdata. + lua_getfenv(L, narg); + lua_rawgeti(L, -1, 1); + // Shouldn't have to check msgdef userdata validity, environment table can't + // be accessed from Lua. + lupb_def *lmd = lua_touserdata(L, -1); + *md = upb_downcast_msgdef(lmd->def); + return msg; } static void lupb_msg_pushnew(lua_State *L, upb_msgdef *md) { - upb_msg *msg = upb_msg_new(md); - lupb_msg *m = lupb_cache_getorcreate_size(L, msg, "upb.msg", sizeof(lupb_msg)); - assert(m); - m->msgdef = md; - // We need to ensure that the msgdef outlives the msg. This performs an - // atomic ref, if this turns out to be too expensive there are other - // possible approaches, like creating a separate metatable for every - // msgdef that references the msgdef. - upb_msgdef_ref(md); -} - -// Caller does *not* pass a ref. -static void lupb_msg_getorcreate(lua_State *L, upb_msg *msg, upb_msgdef *md) { - lupb_msg *m = lupb_cache_getorcreate_size(L, msg, "upb.msg", sizeof(lupb_msg)); - if (m) { - // New Lua object, we need to ref the message. - m->msg = upb_msg_getref(msg); - m->msgdef = md; - // See comment above. - upb_msgdef_ref(md); - } -} - -static int lupb_msg_gc(lua_State *L) { - lupb_msg *m = lupb_msg_check(L, 1); - upb_msg_unref(m->msg, m->msgdef); - upb_msgdef_unref(m->msgdef); - return 0; + void *msg = lua_newuserdata(L, upb_msgdef_size(md)); + luaL_getmetatable(L, "upb.msg"); + assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb. + lua_setmetatable(L, -2); + upb_msg_clear(msg, md); + lua_getfenv(L, -1); + lupb_cache_getorcreate(L, md, "upb.msgdef"); + lua_rawseti(L, -2, 1); + lua_pop(L, 1); // Pop the fenv. } static void lupb_pushvalue(lua_State *L, upb_value val, upb_fielddef *f) { @@ -149,138 +176,99 @@ static void lupb_pushvalue(lua_State *L, upb_value val, upb_fielddef *f) { lua_pushnumber(L, upb_value_getfloat(val)); break; case UPB_TYPE(BOOL): lua_pushboolean(L, upb_value_getbool(val)); break; - case UPB_TYPE(STRING): - case UPB_TYPE(BYTES): { - lupb_pushstring(L, upb_value_getstr(val)); break; - } - case UPB_TYPE(MESSAGE): - case UPB_TYPE(GROUP): { - upb_msg *msg = upb_value_getmsg(val); - assert(msg); - lupb_msg_getorcreate(L, msg, upb_downcast_msgdef(f->def)); - } + default: luaL_error(L, "internal error"); } } -static upb_value lupb_getvalue(lua_State *L, int narg, upb_fielddef *f) { +// Returns a scalar value (ie. not a submessage) as a upb_value. +static upb_value lupb_getvalue(lua_State *L, int narg, upb_fielddef *f, + upb_strref *ref) { + assert(!upb_issubmsg(f)); upb_value val; - lua_Number num = 0; - if (!upb_issubmsg(f) && !upb_isstring(f) && f->type != UPB_TYPE(BOOL)) { + if (upb_fielddef_type(f) == UPB_TYPE(BOOL)) { + if (!lua_isboolean(L, narg)) + luaL_error(L, "Must explicitly pass true or false for boolean fields"); + upb_value_setbool(&val, lua_toboolean(L, narg)); + } else if (upb_fielddef_type(f) == UPB_TYPE(STRING)) { + size_t len; + ref->ptr = luaL_checklstring(L, narg, &len); + ref->len = len; + upb_value_setstrref(&val, ref); + } else { + // Numeric type. + lua_Number num = 0; num = luaL_checknumber(L, narg); - if (f->type != UPB_TYPE(DOUBLE) && f->type != UPB_TYPE(FLOAT) && - num != rint(num)) { - luaL_error(L, "Cannot assign non-integer number %f to integer field", num); - } - } - switch (f->type) { - case UPB_TYPE(INT32): - case UPB_TYPE(SINT32): - case UPB_TYPE(SFIXED32): - case UPB_TYPE(ENUM): - if (num > INT32_MAX || num < INT32_MIN) - luaL_error(L, "Number %f is out-of-range for 32-bit integer field.", num); - upb_value_setint32(&val, num); - break; - case UPB_TYPE(INT64): - case UPB_TYPE(SINT64): - case UPB_TYPE(SFIXED64): - if (num > INT64_MAX || num < INT64_MIN) - luaL_error(L, "Number %f is out-of-range for 64-bit integer field.", num); - upb_value_setint64(&val, num); - break; - case UPB_TYPE(UINT32): - case UPB_TYPE(FIXED32): - if (num > UINT32_MAX || num < 0) - luaL_error(L, "Number %f is out-of-range for unsigned 32-bit integer field.", num); - upb_value_setuint32(&val, num); - break; - case UPB_TYPE(UINT64): - case UPB_TYPE(FIXED64): - if (num > UINT64_MAX || num < 0) - luaL_error(L, "Number %f is out-of-range for unsigned 64-bit integer field.", num); - upb_value_setuint64(&val, num); - break; - case UPB_TYPE(DOUBLE): - if (num > DBL_MAX || num < -DBL_MAX) { - // This could happen if lua_Number was long double. - luaL_error(L, "Number %f is out-of-range for double field.", num); - } - upb_value_setdouble(&val, num); - break; - case UPB_TYPE(FLOAT): - if (num > FLT_MAX || num < -FLT_MAX) - luaL_error(L, "Number %f is out-of-range for float field.", num); - upb_value_setfloat(&val, num); - break; - case UPB_TYPE(BOOL): - if (!lua_isboolean(L, narg)) - luaL_error(L, "Must explicitly pass true or false for boolean fields"); - upb_value_setbool(&val, lua_toboolean(L, narg)); - break; - case UPB_TYPE(STRING): - case UPB_TYPE(BYTES): { - // TODO: is there any reasonable way to avoid a copy here? - size_t len; - const char *str = luaL_checklstring(L, narg, &len); - upb_value_setstr(&val, upb_strduplen(str, len)); - break; - } - case UPB_TYPE(MESSAGE): - case UPB_TYPE(GROUP): { - lupb_msg *m = lupb_msg_check(L, narg); - if (m->msgdef != upb_downcast_msgdef(f->def)) - luaL_error(L, "Tried to assign a message of the wrong type."); - upb_value_setmsg(&val, m->msg); - break; + switch (upb_fielddef_type(f)) { + case UPB_TYPE(INT32): + case UPB_TYPE(SINT32): + case UPB_TYPE(SFIXED32): + case UPB_TYPE(ENUM): + if (num > INT32_MAX || num < INT32_MIN || num != rint(num)) + luaL_error(L, "Cannot convert %f to 32-bit integer", num); + upb_value_setint32(&val, num); + break; + case UPB_TYPE(INT64): + case UPB_TYPE(SINT64): + case UPB_TYPE(SFIXED64): + if (num > INT64_MAX || num < INT64_MIN || num != rint(num)) + luaL_error(L, "Cannot convert %f to 64-bit integer", num); + upb_value_setint64(&val, num); + break; + case UPB_TYPE(UINT32): + case UPB_TYPE(FIXED32): + if (num > UINT32_MAX || num < 0 || num != rint(num)) + luaL_error(L, "Cannot convert %f to unsigned 32-bit integer", num); + upb_value_setuint32(&val, num); + break; + case UPB_TYPE(UINT64): + case UPB_TYPE(FIXED64): + if (num > UINT64_MAX || num < 0 || num != rint(num)) + luaL_error(L, "Cannot convert %f to unsigned 64-bit integer", num); + upb_value_setuint64(&val, num); + break; + case UPB_TYPE(DOUBLE): + if (num > DBL_MAX || num < -DBL_MAX) { + // This could happen if lua_Number was long double. + luaL_error(L, "Cannot convert %f to double", num); + } + upb_value_setdouble(&val, num); + break; + case UPB_TYPE(FLOAT): + if (num > FLT_MAX || num < -FLT_MAX) + luaL_error(L, "Cannot convert %f to float", num); + upb_value_setfloat(&val, num); + break; } } return val; } - static int lupb_msg_index(lua_State *L) { assert(lua_gettop(L) == 2); // __index should always be called with 2 args. - lupb_msg *m = lupb_msg_check(L, 1); - size_t len; - const char *name = luaL_checklstring(L, 2, &len); - upb_string namestr = UPB_STACK_STRING_LEN(name, len); - upb_fielddef *f = upb_msgdef_ntof(m->msgdef, &namestr); - if (f) { - if (upb_isarray(f)) { - luaL_error(L, "Access of repeated fields not yet implemented."); - } - lupb_pushvalue(L, upb_msg_get(m->msg, f), f); - } else { - // It wasn't a field, perhaps it's a method? - lua_getmetatable(L, 1); - lua_pushvalue(L, 2); - lua_rawget(L, -2); - if (lua_isnil(L, -1)) { - luaL_error(L, "%s is not a field name or a method name", name); - } - } + upb_msgdef *md; + void *m = lupb_msg_check(L, 1, &md); + const char *name = luaL_checkstring(L, 2); + upb_fielddef *f = upb_msgdef_ntof(md, name); + if (!f) luaL_error(L, "%s is not a field name", name); + if (upb_isseq(f)) luaL_error(L, "NYI: access of repeated fields"); + upb_value val = + upb_msg_has(m, f) ? upb_msg_get(m, f) : upb_fielddef_default(f); + lupb_pushvalue(L, val, f); return 1; } static int lupb_msg_newindex(lua_State *L) { assert(lua_gettop(L) == 3); // __newindex should always be called with 3 args. - lupb_msg *m = lupb_msg_check(L, 1); - size_t len; - const char *name = luaL_checklstring(L, 2, &len); - upb_string namestr = UPB_STACK_STRING_LEN(name, len); - upb_fielddef *f = upb_msgdef_ntof(m->msgdef, &namestr); - if (f) { - upb_value val = lupb_getvalue(L, 3, f); - upb_msg_set(m->msg, f, val); - if (upb_isstring(f)) { - upb_string_unref(upb_value_getstr(val)); - } - } else { - luaL_error(L, "%s is not a field name", name); - } + upb_msgdef *md; + void *m = lupb_msg_check(L, 1, &md); + const char *name = luaL_checkstring(L, 2); + upb_fielddef *f = upb_msgdef_ntof(md, name); + if (!f) luaL_error(L, "%s is not a field name", name); + upb_msg_set(m, f, lupb_getvalue(L, 3, f, NULL)); return 0; } +#if 0 static int lupb_msg_clear(lua_State *L) { lupb_msg *m = lupb_msg_check(L, 1); upb_msg_clear(m->msg, m->msgdef); @@ -306,24 +294,24 @@ static int lupb_msg_totext(lua_State *L) { upb_string_unref(str); return 1; } +#endif static const struct luaL_Reg lupb_msg_mm[] = { - {"__gc", lupb_msg_gc}, {"__index", lupb_msg_index}, {"__newindex", lupb_msg_newindex}, // Our __index mm will look up methods if the index isn't a field name. - {"Clear", lupb_msg_clear}, - {"Parse", lupb_msg_parse}, - {"ToText", lupb_msg_totext}, + //{"Clear", lupb_msg_clear}, + //{"Parse", lupb_msg_parse}, + //{"ToText", lupb_msg_totext}, {NULL, NULL} }; -#endif /* lupb_msgdef ****************************************************************/ static upb_msgdef *lupb_msgdef_check(lua_State *L, int narg) { lupb_def *ldef = luaL_checkudata(L, narg, "upb.msgdef"); + luaL_argcheck(L, ldef != NULL, narg, "upb msgdef expected"); return upb_downcast_msgdef(ldef->def); } @@ -333,17 +321,53 @@ static int lupb_msgdef_gc(lua_State *L) { return 0; } -#if 0 static int lupb_msgdef_call(lua_State *L) { upb_msgdef *md = lupb_msgdef_check(L, 1); lupb_msg_pushnew(L, md); return 1; } -#endif -static void lupb_fielddef_getorcreate(lua_State *L, upb_fielddef *f); +static int lupb_msgdef_new(lua_State *L) { + upb_msgdef *md = upb_msgdef_new(); + lupb_cache_create(L, md, "upb.msgdef"); + + if (lua_gettop(L) == 0) return 1; + + // User can specify initialization values like so: + // upb.MessageDef{fqname="MyMessage", extstart=8000, fields={...}} + luaL_checktype(L, 1, LUA_TTABLE); + // Iterate over table. + lua_pushnil(L); // first key + while (lua_next(L, 1)) { + luaL_checktype(L, -2, LUA_TSTRING); + const char *key = lua_tostring(L, -2); + + if (streql(key, "fqname")) { // fqname="MyMessage" + const char *fqname = lua_tostring(L, -1); + if (!fqname || !upb_def_setfqname(UPB_UPCAST(md), fqname)) + luaL_error(L, "Invalid fqname"); + } else if (streql(key, "fields")) { // fields={...} + // Iterate over the list of fields. + lua_pushnil(L); + luaL_checktype(L, -2, LUA_TTABLE); + while (lua_next(L, -2)) { + lupb_fielddef *f = lupb_fielddef_check(L, -1); + if (!upb_msgdef_addfield(md, f->field)) { + // TODO: more specific error. + luaL_error(L, "Could not add field."); + } + lua_pop(L, 1); + } + } else { + // TODO: extrange= + luaL_error(L, "Unknown initializer key '%s'", key); + } + lua_pop(L, 1); + } + return 1; +} -static int lupb_msgdef_name(lua_State *L) { +static int lupb_msgdef_fqname(lua_State *L) { upb_msgdef *m = lupb_msgdef_check(L, 1); lua_pushstring(L, m->base.fqname); return 1; @@ -373,7 +397,7 @@ static int lupb_msgdef_fieldbynum(lua_State *L) { } static const struct luaL_Reg lupb_msgdef_mm[] = { - //{"__call", lupb_msgdef_call}, + {"__call", lupb_msgdef_call}, {"__gc", lupb_msgdef_gc}, {NULL, NULL} }; @@ -381,7 +405,7 @@ static const struct luaL_Reg lupb_msgdef_mm[] = { static const struct luaL_Reg lupb_msgdef_m[] = { {"fieldbyname", lupb_msgdef_fieldbyname}, {"fieldbynum", lupb_msgdef_fieldbynum}, - {"name", lupb_msgdef_name}, + {"fqname", lupb_msgdef_fqname}, {NULL, NULL} }; @@ -440,57 +464,127 @@ static void lupb_def_getorcreate(lua_State *L, upb_def *def, int owned) { /* lupb_fielddef **************************************************************/ -typedef struct { - upb_fielddef *field; -} lupb_fielddef; - -static void lupb_fielddef_getorcreate(lua_State *L, upb_fielddef *f) { - bool created = lupb_cache_getorcreate(L, f, "upb.fielddef"); - if (created) { - // Need to obtain a ref on this field's msgdef (fielddefs themselves aren't - // refcounted, but they're kept alive by their owning msgdef). - upb_def_ref(UPB_UPCAST(f->msgdef)); - } -} +#if 0 +static const upb_accessor lupb_accessor = { + upb_startfield_handler *appendseq; // Repeated fields only. + upb_startfield_handler *appendsubmsg; // Submsg fields (repeated or no). + upb_value_handler *set; // Scalar fields (repeated or no). + + // Readers. + upb_has_reader *has; + upb_value_reader *get; + upb_seqbegin_handler *seqbegin; + upb_seqnext_handler *seqnext; + upb_seqget_handler *seqget; +}; +#endif -static lupb_fielddef *lupb_fielddef_check(lua_State *L, int narg) { - return luaL_checkudata(L, narg, "upb.fielddef"); +static upb_accessor_vtbl *lupb_accessor(upb_fielddef *f) { + return upb_stdmsg_accessor(f); } static int lupb_fielddef_index(lua_State *L) { lupb_fielddef *f = lupb_fielddef_check(L, 1); const char *str = luaL_checkstring(L, 2); - if (strcmp(str, "name") == 0) { + if (streql(str, "name")) { lua_pushstring(L, upb_fielddef_name(f->field)); - } else if (strcmp(str, "number") == 0) { + } else if (streql(str, "number")) { lua_pushinteger(L, upb_fielddef_number(f->field)); - } else if (strcmp(str, "type") == 0) { + } else if (streql(str, "type")) { lua_pushinteger(L, upb_fielddef_type(f->field)); - } else if (strcmp(str, "label") == 0) { + } else if (streql(str, "label")) { lua_pushinteger(L, upb_fielddef_label(f->field)); - } else if (strcmp(str, "subdef") == 0) { + } else if (streql(str, "subdef")) { lupb_def_getorcreate(L, upb_fielddef_subdef(f->field), false); - } else if (strcmp(str, "msgdef") == 0) { + } else if (streql(str, "msgdef")) { lupb_def_getorcreate(L, UPB_UPCAST(upb_fielddef_msgdef(f->field)), false); } else { - lua_pushnil(L); + luaL_error(L, "Invalid fielddef member '%s'", str); } return 1; } +static void lupb_fielddef_set(lua_State *L, upb_fielddef *f, + const char *field, int narg) { + if (!upb_fielddef_ismutable(f)) luaL_error(L, "fielddef is not mutable."); + if (streql(field, "name")) { + const char *name = lua_tostring(L, narg); + if (!name || !upb_fielddef_setname(f, name)) + luaL_error(L, "Invalid name"); + } else if (streql(field, "number")) { + if (!upb_fielddef_setnumber(f, lupb_touint32(L, narg, "number"))) + luaL_error(L, "Invalid number"); + } else if (streql(field, "type")) { + if (!upb_fielddef_settype(f, lupb_touint8(L, narg, "type"))) + luaL_error(L, "Invalid type"); + } else if (streql(field, "label")) { + if (!upb_fielddef_setlabel(f, lupb_touint8(L, narg, "label"))) + luaL_error(L, "Invalid label"); + } else if (streql(field, "type_name")) { + const char *name = lua_tostring(L, narg); + if (!name || !upb_fielddef_settypename(f, name)) + luaL_error(L, "Invalid type_name"); + } else if (streql(field, "default_value")) { + if (!upb_fielddef_type(f)) + luaL_error(L, "Must set type before setting default_value"); + upb_strref ref; + upb_fielddef_setdefault(f, lupb_getvalue(L, narg, f, &ref)); + } else { + luaL_error(L, "Cannot set fielddef member '%s'", field); + } +} + +static int lupb_fielddef_new(lua_State *L) { + upb_fielddef *f = upb_fielddef_new(); + lupb_cache_create(L, f, "upb.fielddef"); + + if (lua_gettop(L) == 0) return 1; + + // User can specify initialization values like so: + // upb.FieldDef{label=upb.LABEL_REQUIRED, name="my_field", number=5, + // type=upb.TYPE_INT32, default_value=12, type_name="Foo"} + luaL_checktype(L, 1, LUA_TTABLE); + // Iterate over table. + lua_pushnil(L); // first key + while (lua_next(L, 1)) { + luaL_checktype(L, -2, LUA_TSTRING); + const char *key = lua_tostring(L, -2); + lupb_fielddef_set(L, f, key, -1); + lua_pop(L, 1); + } + return 1; +} + +static void lupb_fielddef_getorcreate(lua_State *L, upb_fielddef *f) { + bool created = lupb_cache_getorcreate(L, f, "upb.fielddef"); + if (created) { + // Need to obtain a ref on this field's msgdef (fielddefs themselves aren't + // refcounted, but they're kept alive by their owning msgdef). + upb_def_ref(UPB_UPCAST(f->msgdef)); + } +} + +static int lupb_fielddef_newindex(lua_State *L) { + lupb_fielddef *f = lupb_fielddef_check(L, 1); + lupb_fielddef_set(L, f->field, luaL_checkstring(L, 2), 3); + return 0; +} + static int lupb_fielddef_gc(lua_State *L) { lupb_fielddef *lfielddef = lupb_fielddef_check(L, 1); - upb_def_unref(UPB_UPCAST(lfielddef->field->msgdef)); + upb_fielddef_unref(lfielddef->field); return 0; } static const struct luaL_Reg lupb_fielddef_mm[] = { {"__gc", lupb_fielddef_gc}, {"__index", lupb_fielddef_index}, + {"__newindex", lupb_fielddef_newindex}, {NULL, NULL} }; + /* lupb_symtab ****************************************************************/ typedef struct { @@ -504,6 +598,58 @@ lupb_symtab *lupb_symtab_check(lua_State *L, int narg) { return luaL_checkudata(L, narg, "upb.symtab"); } +// narg is a lua table containing a list of defs to add. +void lupb_symtab_doadd(lua_State *L, upb_symtab *s, int narg) { + luaL_checktype(L, narg, LUA_TTABLE); + // Iterate over table twice. First iteration to count entries and + // check constraints. + int n = 0; + lua_pushnil(L); // first key + while (lua_next(L, narg)) { + lupb_def_check(L, -1); + ++n; + lua_pop(L, 1); + } + + // Second iteration to build deflist and layout. + upb_def **defs = malloc(n * sizeof(*defs)); + n = 0; + lua_pushnil(L); // first key + while (lua_next(L, 1)) { + upb_def *def = lupb_def_check(L, -1)->def; + defs[n++] = def; + upb_msgdef *md = upb_dyncast_msgdef(def); + if (md) { + 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); + upb_fielddef_setaccessor(f, lupb_accessor(f)); + } + upb_msgdef_layout(md); + } + lua_pop(L, 1); + } + + upb_status status = UPB_STATUS_INIT; + upb_symtab_add(s, defs, n, &status); + free(defs); + lupb_checkstatus(L, &status); +} + +static int lupb_symtab_new(lua_State *L) { + upb_symtab *s = upb_symtab_new(); + lupb_cache_create(L, s, "upb.symtab"); + if (lua_gettop(L) == 0) return 1; + lupb_symtab_doadd(L, s, 1); + return 1; +} + +static int lupb_symtab_add(lua_State *L) { + lupb_symtab *s = lupb_symtab_check(L, 1); + lupb_symtab_doadd(L, s->symtab, 2); + return 0; +} + static int lupb_symtab_gc(lua_State *L) { lupb_symtab *s = lupb_symtab_check(L, 1); upb_symtab_unref(s->symtab); @@ -512,13 +658,16 @@ static int lupb_symtab_gc(lua_State *L) { static int lupb_symtab_lookup(lua_State *L) { lupb_symtab *s = lupb_symtab_check(L, 1); - upb_def *def = upb_symtab_lookup(s->symtab, luaL_checkstring(L, 2)); - if (def) { - lupb_def_getorcreate(L, def, true); - } else { - lua_pushnil(L); + for (int i = 2; i <= lua_gettop(L); i++) { + upb_def *def = upb_symtab_lookup(s->symtab, luaL_checkstring(L, i)); + if (def) { + lupb_def_getorcreate(L, def, true); + } else { + lua_pushnil(L); + } + lua_replace(L, i); } - return 1; + return lua_gettop(L) - 1; } static int lupb_symtab_getdefs(lua_State *L) { @@ -551,7 +700,7 @@ static int lupb_symtab_parsedesc(lua_State *L) { } static const struct luaL_Reg lupb_symtab_m[] = { - //{"addfds", lupb_symtab_addfds}, + {"add", lupb_symtab_add}, {"getdefs", lupb_symtab_getdefs}, {"lookup", lupb_symtab_lookup}, {"parsedesc", lupb_symtab_parsedesc}, @@ -567,16 +716,10 @@ static const struct luaL_Reg lupb_symtab_mm[] = { /* lupb toplevel **************************************************************/ -static int lupb_symtab_new(lua_State *L) { - upb_symtab *s = upb_symtab_new(); - bool created = lupb_cache_getorcreate(L, s, "upb.symtab"); - (void)created; // For NDEBUG - assert(created); // It's new, there shouldn't be an obj for it already. - return 1; -} - static const struct luaL_Reg lupb_toplevel_m[] = { - {"symtab", lupb_symtab_new}, + {"SymbolTable", lupb_symtab_new}, + {"MessageDef", lupb_msgdef_new}, + {"FieldDef", lupb_fielddef_new}, {NULL, NULL} }; @@ -595,12 +738,17 @@ static void lupb_register_type(lua_State *L, const char *name, lua_pop(L, 1); // The mt. } +static void lupb_setfieldi(lua_State *L, const char *field, int i) { + lua_pushnumber(L, i); + lua_setfield(L, -2, field); +} + int luaopen_upb(lua_State *L) { lupb_register_type(L, "upb.msgdef", lupb_msgdef_m, lupb_msgdef_mm); lupb_register_type(L, "upb.enumdef", lupb_enumdef_m, lupb_enumdef_mm); lupb_register_type(L, "upb.fielddef", NULL, lupb_fielddef_mm); lupb_register_type(L, "upb.symtab", lupb_symtab_m, lupb_symtab_mm); - //lupb_register_type(L, "upb.msg", NULL, lupb_msg_mm); + lupb_register_type(L, "upb.msg", NULL, lupb_msg_mm); // Create our object cache. lua_createtable(L, 0, 0); @@ -610,5 +758,30 @@ int luaopen_upb(lua_State *L) { lua_setfield(L, LUA_REGISTRYINDEX, "upb.objcache"); luaL_register(L, "upb", lupb_toplevel_m); + + // Register constants. + lupb_setfieldi(L, "LABEL_OPTIONAL", UPB_LABEL(OPTIONAL)); + lupb_setfieldi(L, "LABEL_REQUIRED", UPB_LABEL(REQUIRED)); + lupb_setfieldi(L, "LABEL_REPEATED", UPB_LABEL(REPEATED)); + + lupb_setfieldi(L, "TYPE_DOUBLE", UPB_TYPE(DOUBLE)); + lupb_setfieldi(L, "TYPE_FLOAT", UPB_TYPE(FLOAT)); + lupb_setfieldi(L, "TYPE_INT64", UPB_TYPE(INT64)); + lupb_setfieldi(L, "TYPE_UINT64", UPB_TYPE(UINT64)); + lupb_setfieldi(L, "TYPE_INT32", UPB_TYPE(INT32)); + lupb_setfieldi(L, "TYPE_FIXED64", UPB_TYPE(FIXED64)); + lupb_setfieldi(L, "TYPE_FIXED32", UPB_TYPE(FIXED32)); + lupb_setfieldi(L, "TYPE_BOOL", UPB_TYPE(BOOL)); + lupb_setfieldi(L, "TYPE_STRING", UPB_TYPE(STRING)); + lupb_setfieldi(L, "TYPE_GROUP", UPB_TYPE(GROUP)); + lupb_setfieldi(L, "TYPE_MESSAGE", UPB_TYPE(MESSAGE)); + lupb_setfieldi(L, "TYPE_BYTES", UPB_TYPE(BYTES)); + lupb_setfieldi(L, "TYPE_UINT32", UPB_TYPE(UINT32)); + lupb_setfieldi(L, "TYPE_ENUM", UPB_TYPE(ENUM)); + lupb_setfieldi(L, "TYPE_SFIXED32", UPB_TYPE(SFIXED32)); + lupb_setfieldi(L, "TYPE_SFIXED64", UPB_TYPE(SFIXED64)); + lupb_setfieldi(L, "TYPE_SINT32", UPB_TYPE(SINT32)); + lupb_setfieldi(L, "TYPE_SINT64", UPB_TYPE(SINT64)); + return 1; // Return package table. } diff --git a/upb/bytestream.h b/upb/bytestream.h index 2a6f7d2..6090d6a 100644 --- a/upb/bytestream.h +++ b/upb/bytestream.h @@ -119,16 +119,17 @@ typedef struct _upb_strref { // the actual pointers). const char *ptr; - // Bytesrc from which this string data comes. This is only guaranteed to be - // alive from inside the callback; however if the handler knows more about - // its type and how to prolong its life, it may do so. - upb_bytesrc *bytesrc; + // Length of the string. + uint32_t len; // Offset in the bytesrc that represents the beginning of this string. uint32_t stream_offset; - // Length of the string. - uint32_t len; + // Bytesrc from which this string data comes. May be NULL if ptr is set. If + // non-NULL, the bytesrc is only guaranteed to be alive from inside the + // callback; however if the handler knows more about its type and how to + // prolong its life, it may do so. + upb_bytesrc *bytesrc; // Possibly add optional members here like start_line, start_column, etc. } upb_strref; diff --git a/upb/def.c b/upb/def.c index 889eeea..f3f012b 100644 --- a/upb/def.c +++ b/upb/def.c @@ -38,9 +38,14 @@ static void upb_msgdef_free(upb_msgdef *m); static void upb_enumdef_free(upb_enumdef *e); static void upb_unresolveddef_free(struct _upb_unresolveddef *u); -#ifndef NDEBUG -static bool upb_def_ismutable(upb_def *def) { return def->symtab == NULL; } -#endif +bool upb_def_ismutable(upb_def *def) { return def->symtab == NULL; } + +bool upb_def_setfqname(upb_def *def, const char *fqname) { + assert(upb_def_ismutable(def)); + free(def->fqname); + def->fqname = strdup(fqname); + return true; // TODO: check for acceptable characters. +} static void upb_def_free(upb_def *def) { switch (def->type) { @@ -73,7 +78,7 @@ void upb_def_ref(upb_def *def) { static void upb_def_movetosymtab(upb_def *d, upb_symtab *s) { assert(upb_atomic_read(&d->refcount) > 0); d->symtab = s; - if (!upb_atomic_unref(&d->refcount)) upb_symtab_ref(s); + upb_symtab_ref(s); upb_msgdef *m = upb_dyncast_msgdef(d); if (m) upb_inttable_compact(&m->itof); } @@ -216,6 +221,7 @@ upb_fielddef *upb_fielddef_new() { f->hasbit = 0; f->offset = 0; f->number = 0; // not a valid field number. + f->hasdefault = false; f->name = NULL; f->accessor = NULL; upb_value_setfielddef(&f->fval, f); @@ -260,6 +266,17 @@ upb_fielddef *upb_fielddef_dup(upb_fielddef *f) { return f; } +bool upb_fielddef_ismutable(upb_fielddef *f) { + return !f->msgdef || upb_def_ismutable(UPB_UPCAST(f->msgdef)); +} + +upb_def *upb_fielddef_subdef(upb_fielddef *f) { + if (upb_hassubdef(f) && !upb_fielddef_ismutable(f)) + return f->def; + else + return NULL; +} + static bool upb_fielddef_resolve(upb_fielddef *f, upb_def *def, upb_status *s) { assert(upb_dyncast_unresolveddef(f->def)); upb_def_unref(f->def); @@ -286,25 +303,30 @@ static bool upb_fielddef_resolve(upb_fielddef *f, upb_def *def, upb_status *s) { return true; } -void upb_fielddef_setnumber(upb_fielddef *f, int32_t number) { +bool upb_fielddef_setnumber(upb_fielddef *f, int32_t number) { assert(f->msgdef == NULL); f->number = number; + return true; } -void upb_fielddef_setname(upb_fielddef *f, const char *name) { +bool upb_fielddef_setname(upb_fielddef *f, const char *name) { assert(f->msgdef == NULL); f->name = strdup(name); + return true; } -void upb_fielddef_settype(upb_fielddef *f, uint8_t type) { +bool upb_fielddef_settype(upb_fielddef *f, uint8_t type) { assert(!f->finalized); f->type = type; + return true; } -void upb_fielddef_setlabel(upb_fielddef *f, uint8_t label) { +bool upb_fielddef_setlabel(upb_fielddef *f, uint8_t label) { assert(!f->finalized); f->label = label; + return true; } + void upb_fielddef_setdefault(upb_fielddef *f, upb_value value) { assert(!f->finalized); // TODO: string ownership? @@ -322,9 +344,10 @@ void upb_fielddef_setaccessor(upb_fielddef *f, struct _upb_accessor_vtbl *vtbl) f->accessor = vtbl; } -void upb_fielddef_settypename(upb_fielddef *f, const char *name) { +bool upb_fielddef_settypename(upb_fielddef *f, const char *name) { upb_def_unref(f->def); f->def = UPB_UPCAST(upb_unresolveddef_new(name)); + return true; } // Returns an ordering of fields based on: @@ -363,8 +386,8 @@ upb_msgdef *upb_msgdef_new() { upb_strtable_init(&m->ntof, 4, sizeof(upb_ntof_ent)); m->size = 0; m->hasbit_bytes = 0; - m->extension_start = 0; - m->extension_end = 0; + m->extstart = 0; + m->extend = 0; return m; } @@ -382,11 +405,12 @@ upb_msgdef *upb_msgdef_dup(upb_msgdef *m) { upb_msgdef *newm = upb_msgdef_new(); newm->size = m->size; newm->hasbit_bytes = m->hasbit_bytes; - newm->extension_start = m->extension_start; - newm->extension_end = m->extension_end; + 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)) + 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; } @@ -400,28 +424,38 @@ void upb_msgdef_sethasbit_bytes(upb_msgdef *m, uint16_t bytes) { m->hasbit_bytes = bytes; } -void upb_msgdef_setextension_start(upb_msgdef *m, uint32_t start) { +bool upb_msgdef_setextrange(upb_msgdef *m, uint32_t start, uint32_t end) { assert(upb_def_ismutable(UPB_UPCAST(m))); - m->extension_start = start; + if (start == 0 && end == 0) { + // Clearing the extension range -- ok to fall through. + } else if (start >= end || start < 1 || end > UPB_MAX_FIELDNUMBER) { + return false; + } + m->extstart = start; + m->extend = start; + return true; } -void upb_msgdef_setextension_end(upb_msgdef *m, uint32_t end) { - assert(upb_def_ismutable(UPB_UPCAST(m))); - m->extension_end = end; -} +bool upb_msgdef_addfields(upb_msgdef *m, upb_fielddef **fields, int n) { + // Check constraints for all fields before performing any action. + for (int i = 0; i < n; i++) { + upb_fielddef *f = fields[i]; + assert(upb_atomic_read(&f->refcount) > 0); + if (f->name == NULL || f->number == 0 || + upb_msgdef_itof(m, f->number) || upb_msgdef_ntof(m, f->name)) + return false; + } -bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f) { - assert(upb_atomic_read(&f->refcount) > 0); - if (!upb_atomic_unref(&f->refcount)) upb_msgdef_ref(m); - if (upb_msgdef_itof(m, f->number) || upb_msgdef_ntof(m, f->name)) { - upb_fielddef_unref(f); - return false; + // Constraint checks ok, perform the action. + for (int i = 0; i < n; i++) { + upb_fielddef *f = fields[i]; + upb_msgdef_ref(m); + assert(f->msgdef == NULL); + f->msgdef = m; + upb_itof_ent itof_ent = {0, f}; + upb_inttable_insert(&m->itof, f->number, &itof_ent); + upb_strtable_insert(&m->ntof, f->name, &f); } - assert(f->msgdef == NULL); - f->msgdef = m; - upb_itof_ent itof_ent = {0, f}; - upb_inttable_insert(&m->itof, f->number, &itof_ent); - upb_strtable_insert(&m->ntof, f->name, &f); return true; } @@ -608,7 +642,7 @@ bool upb_symtab_dfs(upb_def *def, upb_def **open_defs, int n, 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_hasdef(f)) continue; + if (!upb_hassubdef(f)) continue; needcopy |= upb_symtab_dfs(f->def, open_defs, n, addtab); } } @@ -664,7 +698,36 @@ bool upb_symtab_add(upb_symtab *s, upb_def **defs, int n, upb_status *status) { upb_msg_iter j; for(j = upb_msg_begin(m); !upb_msg_done(j); j = upb_msg_next(m, j)) { upb_fielddef *f = upb_msg_iter_field(j); - if(!upb_hasdef(f)) continue; // No resolving necessary. + if (f->type == 0) { + upb_status_setf(status, UPB_ERROR, "Field type was not set."); + return false; + } + + // Set default default if none was set explicitly. + if (!f->hasdefault) { + 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(INT32): + case UPB_TYPE(SINT32): + case UPB_TYPE(ENUM): + 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): + case UPB_TYPE(GROUP): + case UPB_TYPE(MESSAGE): break; // do nothing for now. + } + } + + if (!upb_hassubdef(f)) continue; // No resolving necessary. const char *name = upb_downcast_unresolveddef(f->def)->name; // Resolve from either the addtab (pending adds) or symtab (existing diff --git a/upb/def.h b/upb/def.h index 2b9eac4..a487a3c 100644 --- a/upb/def.h +++ b/upb/def.h @@ -14,6 +14,10 @@ * These defs are mutable (and not thread-safe) when first created. * Once they are added to a defbuilder (and later its symtab) they become * immutable. + * + * TODO: consider making thread-safe even when first created by using mutexes + * internally. Would also have to change any methods returning pointers to + * return copies instead. */ #ifndef UPB_DEF_H_ @@ -58,6 +62,11 @@ void upb_def_ref(upb_def *def); void upb_def_unref(upb_def *def); upb_def *upb_def_dup(upb_def *def); +// A def is mutable until it has been added to a symtab. +bool upb_def_ismutable(upb_def *def); +INLINE const char *upb_def_fqname(upb_def *def) { return def->fqname; } +bool upb_def_setfqname(upb_def *def, const char *fqname); // Only if mutable. + #define UPB_UPCAST(ptr) (&(ptr)->base) @@ -77,6 +86,8 @@ typedef struct _upb_fielddef { uint8_t label; // Use UPB_LABEL() constants. int16_t hasbit; uint16_t offset; + bool hasdefault; + bool active; int32_t number; char *name; upb_value defaultval; // Only meaningful for non-repeated scalars and strings. @@ -89,6 +100,9 @@ void upb_fielddef_ref(upb_fielddef *f); void upb_fielddef_unref(upb_fielddef *f); upb_fielddef *upb_fielddef_dup(upb_fielddef *f); +// A fielddef is mutable until its msgdef has been added to a symtab. +bool upb_fielddef_ismutable(upb_fielddef *f); + // Read accessors. May be called any time. INLINE uint8_t upb_fielddef_type(upb_fielddef *f) { return f->type; } INLINE uint8_t upb_fielddef_label(upb_fielddef *f) { return f->label; } @@ -113,18 +127,18 @@ upb_def *upb_fielddef_subdef(upb_fielddef *f); // Write accessors. "Number" and "name" must be set before the fielddef is // added to a msgdef. For the moment we do not allow these to be set once // the fielddef is added to a msgdef -- this could be relaxed in the future. -void upb_fielddef_setnumber(upb_fielddef *f, int32_t number); -void upb_fielddef_setname(upb_fielddef *f, const char *name); +bool upb_fielddef_setnumber(upb_fielddef *f, int32_t number); +bool upb_fielddef_setname(upb_fielddef *f, const char *name); // These writers may be called at any time prior to being put in a symtab. -void upb_fielddef_settype(upb_fielddef *f, uint8_t type); -void upb_fielddef_setlabel(upb_fielddef *f, uint8_t label); +bool upb_fielddef_settype(upb_fielddef *f, uint8_t type); +bool upb_fielddef_setlabel(upb_fielddef *f, uint8_t label); void upb_fielddef_setdefault(upb_fielddef *f, upb_value value); void upb_fielddef_setfval(upb_fielddef *f, upb_value fval); void upb_fielddef_setaccessor(upb_fielddef *f, struct _upb_accessor_vtbl *vtbl); // The name of the message or enum this field is referring to. Must be found -// at name resolution time (when the symtabtxn is committed to the symtab). -void upb_fielddef_settypename(upb_fielddef *f, const char *name); +// at name resolution time (when upb_symtab_add() is called). +bool upb_fielddef_settypename(upb_fielddef *f, const char *name); // A variety of tests about the type of a field. INLINE bool upb_issubmsgtype(upb_fieldtype_t type) { @@ -141,7 +155,7 @@ INLINE bool upb_isstring(upb_fielddef *f) { return upb_isstringtype(f->type); } INLINE bool upb_isseq(upb_fielddef *f) { return f->label == UPB_LABEL(REPEATED); } // Does the type of this field imply that it should contain an associated def? -INLINE bool upb_hasdef(upb_fielddef *f) { +INLINE bool upb_hassubdef(upb_fielddef *f) { return upb_issubmsg(f) || f->type == UPB_TYPE(ENUM); } @@ -160,8 +174,7 @@ typedef struct _upb_msgdef { uint16_t size; uint8_t hasbit_bytes; // The range of tag numbers used to store extensions. - uint32_t extension_start; - uint32_t extension_end; + uint32_t extstart, extend; } upb_msgdef; // Hash table entries for looking up fields by name or number. @@ -170,7 +183,6 @@ typedef struct { upb_fielddef *f; } upb_itof_ent; typedef struct { - upb_strtable_entry e; upb_fielddef *f; } upb_ntof_ent; @@ -189,25 +201,23 @@ INLINE uint16_t upb_msgdef_size(upb_msgdef *m) { return m->size; } INLINE uint8_t upb_msgdef_hasbit_bytes(upb_msgdef *m) { return m->hasbit_bytes; } -INLINE uint32_t upb_msgdef_extension_start(upb_msgdef *m) { - return m->extension_start; -} -INLINE uint32_t upb_msgdef_extension_end(upb_msgdef *m) { - return m->extension_end; -} +INLINE uint32_t upb_msgdef_extstart(upb_msgdef *m) { return m->extstart; } +INLINE uint32_t upb_msgdef_extend(upb_msgdef *m) { return m->extend; } // Write accessors. May only be called before the msgdef is in a symtab. void upb_msgdef_setsize(upb_msgdef *m, uint16_t size); void upb_msgdef_sethasbit_bytes(upb_msgdef *m, uint16_t bytes); -void upb_msgdef_setextension_start(upb_msgdef *m, uint32_t start); -void upb_msgdef_setextension_end(upb_msgdef *m, uint32_t end); +bool upb_msgdef_setextrange(upb_msgdef *m, uint32_t start, uint32_t end); -// Adds a fielddef to a msgdef, and passes a ref on the field to the msgdef. +// Adds a fielddef to a msgdef. Caller retains its ref on the fielddef. // May only be done before the msgdef is in a symtab. The fielddef's name and // number must be set, and the message may not already contain any field with -// this name or number -- if it does, the fielddef is unref'd and false is -// returned. The fielddef may not already belong to another message. -bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f); +// this name or number, and this fielddef may not be part of another message, +// otherwise false is returned and no action is performed. +bool upb_msgdef_addfields(upb_msgdef *m, upb_fielddef **f, int n); +INLINE bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f) { + return upb_msgdef_addfields(m, &f, 1); +} // Sets the layout of all fields according to default rules: // 1. Hasbits for required fields come first, then optional fields. @@ -374,8 +384,8 @@ upb_def **upb_symtab_getdefs(upb_symtab *s, int *n, upb_deftype_t type); // Adds the given defs to the symtab, resolving all symbols. Only one def per // name may be in the list, but defs can replace existing defs in the symtab. // The entire operation either succeeds or fails. If the operation fails, the -// symtab is unchanged, false is returned, and status indicates the error. A -// ref on the defs is passed to the symtab iff the operation succeeds. +// symtab is unchanged, false is returned, and status indicates the error. The +// caller retains its ref on all defs in all cases. bool upb_symtab_add(upb_symtab *s, upb_def **defs, int n, upb_status *status); // Frees defs that are no longer active in the symtab and are no longer diff --git a/upb/descriptor.c b/upb/descriptor.c index 568a0d2..fbaef29 100644 --- a/upb/descriptor.c +++ b/upb/descriptor.c @@ -367,11 +367,13 @@ static void upb_fielddef_endmsg(void *_r, upb_status *status) { upb_fielddef *f = r->f; // TODO: verify that all required fields were present. assert(f->number != -1 && f->name != NULL); - assert((f->def != NULL) == upb_hasdef(f)); + assert((f->def != NULL) == upb_hassubdef(f)); // Field was successfully read, add it as a field of the msgdef. upb_msgdef *m = upb_descreader_top(r); upb_msgdef_addfield(m, f); + upb_fielddef_unref(f); + r->f = NULL; char *dstr = r->default_string; r->default_string = NULL; upb_value val; diff --git a/upb/msg.h b/upb/msg.h index 625d805..ac9e877 100644 --- a/upb/msg.h +++ b/upb/msg.h @@ -92,12 +92,17 @@ INLINE bool upb_msg_has(void *m, upb_fielddef *f) { return f->accessor && f->accessor->has(m, f->fval); } -// May only be called for fields that are known to be set. +// May only be called for fields that have accessors. INLINE upb_value upb_msg_get(void *m, upb_fielddef *f) { - assert(upb_msg_has(m, f)); + assert(f->accessor); return f->accessor->get(m, f->fval); } +INLINE void upb_msg_set(void *m, upb_fielddef *f, upb_value val) { + assert(f->accessor); + f->accessor->set(m, f->fval, val); +} + INLINE void *upb_seq_begin(void *s, upb_fielddef *f) { assert(f->accessor); return f->accessor->seqbegin(s); diff --git a/upb/upb.h b/upb/upb.h index 0c49597..633fd00 100644 --- a/upb/upb.h +++ b/upb/upb.h @@ -64,6 +64,8 @@ INLINE size_t upb_align_up(size_t val, size_t align) { // An individual string or array is unaffected by this 16k byte limit. #define UPB_MAX_FIELDS (2048) +#define UPB_MAX_FIELDNUMBER ((1 << 29) - 1) + // Nested type names are separated by periods. #define UPB_SYMBOL_SEPARATOR '.' -- cgit v1.2.3