summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Haberman <jhaberman@gmail.com>2011-07-29 17:49:59 -0700
committerJoshua Haberman <jhaberman@gmail.com>2011-07-29 17:49:59 -0700
commit56984e8db8e1c43687535cc77fb6ce43df0b3d1f (patch)
treedc8c85d1311458a68408ff4c43d009b6193ac221
parent92b4c38fa5f137cbcf835ad359bed8711c1c9c51 (diff)
Significant work on Lua extension.
Also changes in core library to accommodate.
-rw-r--r--Makefile4
-rw-r--r--lang_ext/lua/test.lua64
-rw-r--r--lang_ext/lua/upb.c577
-rw-r--r--upb/bytestream.h13
-rw-r--r--upb/def.c129
-rw-r--r--upb/def.h58
-rw-r--r--upb/descriptor.c4
-rw-r--r--upb/msg.h9
-rw-r--r--upb/upb.h2
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, <string, submessage, or array fields>}
+
+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 '.'
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback