Significant work on Lua extension.

Also changes in core library to accommodate.
pull/13171/head
Joshua Haberman 14 years ago
parent 92b4c38fa5
commit 56984e8db8
  1. 4
      Makefile
  2. 64
      lang_ext/lua/test.lua
  3. 509
      lang_ext/lua/upb.c
  4. 13
      upb/bytestream.h
  5. 117
      upb/def.c
  6. 58
      upb/def.h
  7. 4
      upb/descriptor.c
  8. 9
      upb/msg.h
  9. 2
      upb/upb.h

@ -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)

@ -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)
--]]

@ -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;
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;
if (!upb_issubmsg(f) && !upb_isstring(f) && f->type != UPB_TYPE(BOOL)) {
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) {
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)
luaL_error(L, "Number %f is out-of-range for 32-bit integer field.", num);
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)
luaL_error(L, "Number %f is out-of-range for 64-bit integer field.", num);
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)
luaL_error(L, "Number %f is out-of-range for unsigned 32-bit integer field.", num);
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)
luaL_error(L, "Number %f is out-of-range for unsigned 64-bit integer field.", num);
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, "Number %f is out-of-range for double field.", num);
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, "Number %f is out-of-range for float field.", num);
luaL_error(L, "Cannot convert %f to float", 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;
}
}
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));
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);
}
return 1;
lua_replace(L, i);
}
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.
}

@ -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;

@ -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) {
assert(upb_def_ismutable(UPB_UPCAST(m)));
m->extension_start = 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) {
assert(upb_def_ismutable(UPB_UPCAST(m)));
m->extension_end = end;
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;
}
bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f) {
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 (!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);
if (f->name == NULL || f->number == 0 ||
upb_msgdef_itof(m, f->number) || upb_msgdef_ntof(m, f->name))
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);
}
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

@ -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

@ -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;

@ -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);

@ -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 '.'

Loading…
Cancel
Save