More work on Lua extension, and consequent core refactoring.

pull/13171/head
Joshua Haberman 14 years ago
parent c2c853fa21
commit 6981e468a3
  1. 368
      lang_ext/lua/upb.c
  2. 2
      tests/test_vs_proto2.cc
  3. 2
      tests/tests.c
  4. 91
      upb/msg.c
  5. 25
      upb/msg.h
  6. 2
      upb/pb/glue.c

@ -15,8 +15,14 @@
#include "upb/msg.h" #include "upb/msg.h"
#include "upb/pb/glue.h" #include "upb/pb/glue.h"
#if LUA_VERSION_NUM == 501
#define lua_rawlen lua_objlen
#endif
static bool streql(const char *a, const char *b) { return strcmp(a, b) == 0; } static bool streql(const char *a, const char *b) { return strcmp(a, b) == 0; }
static bool lupb_isint(double n) { return (double)(int)n == n; }
static uint8_t lupb_touint8(lua_State *L, int narg, const char *name) { static uint8_t lupb_touint8(lua_State *L, int narg, const char *name) {
lua_Number n = lua_tonumber(L, narg); lua_Number n = lua_tonumber(L, narg);
if (n > UINT8_MAX || n < 0 || rint(n) != n) if (n > UINT8_MAX || n < 0 || rint(n) != n)
@ -31,6 +37,17 @@ static uint32_t lupb_touint32(lua_State *L, int narg, const char *name) {
return n; return n;
} }
static void lupb_pushstring(lua_State *L, upb_strref *ref) {
if (ref->ptr) {
lua_pushlstring(L, ref->ptr, ref->len);
} else {
// Lua requires a continguous string; must copy+allocate.
char *str = upb_strref_dup(ref);
lua_pushlstring(L, str, ref->len);
free(str);
}
}
static void lupb_pushvalue(lua_State *L, upb_value val, upb_fielddef *f) { static void lupb_pushvalue(lua_State *L, upb_value val, upb_fielddef *f) {
switch (f->type) { switch (f->type) {
case UPB_TYPE(INT32): case UPB_TYPE(INT32):
@ -121,10 +138,15 @@ static upb_value lupb_getvalue(lua_State *L, int narg, upb_fielddef *f,
return val; return val;
} }
static void lupb_typecheck(lua_State *L, int narg, upb_fielddef *f) {
upb_strref ref;
lupb_getvalue(L, narg, f, &ref);
}
//static void lupb_msg_getorcreate(lua_State *L, upb_msg *msg, upb_msgdef *md); //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); static void lupb_fielddef_getorcreate(lua_State *L, upb_fielddef *f);
static upb_msgdef *lupb_msgdef_check(lua_State *L, int narg); static upb_msgdef *lupb_msgdef_check(lua_State *L, int narg);
static void lupb_msg_pushnew(lua_State *L, upb_msgdef *md); static void lupb_msg_pushnew(lua_State *L, void *md);
void lupb_checkstatus(lua_State *L, upb_status *s) { void lupb_checkstatus(lua_State *L, upb_status *s) {
if (!upb_ok(s)) { if (!upb_ok(s)) {
@ -200,7 +222,7 @@ typedef struct {
static lupb_def *lupb_def_check(lua_State *L, int narg) { static lupb_def *lupb_def_check(lua_State *L, int narg) {
void *ldef = luaL_checkudata(L, narg, "upb.msgdef"); void *ldef = luaL_checkudata(L, narg, "upb.msgdef");
if (!ldef) ldef = luaL_checkudata(L, narg, "upb.enumdef"); if (!ldef) ldef = luaL_checkudata(L, narg, "upb.enumdef");
luaL_argcheck(L, ldef != NULL, narg, "upb def expected"); if (!ldef) luaL_typerror(L, narg, "upb def");
return ldef; return ldef;
} }
@ -232,29 +254,10 @@ typedef struct {
static lupb_fielddef *lupb_fielddef_check(lua_State *L, int narg) { static lupb_fielddef *lupb_fielddef_check(lua_State *L, int narg) {
lupb_fielddef *f = luaL_checkudata(L, narg, "upb.fielddef"); lupb_fielddef *f = luaL_checkudata(L, narg, "upb.fielddef");
luaL_argcheck(L, f != NULL, narg, "upb fielddef expected"); if (!f) luaL_typerror(L, narg, "upb fielddef");
return f; return f;
} }
#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 upb_accessor_vtbl *lupb_accessor(upb_fielddef *f) {
return upb_stdmsg_accessor(f);
}
static int lupb_fielddef_index(lua_State *L) { static int lupb_fielddef_index(lua_State *L) {
lupb_fielddef *f = lupb_fielddef_check(L, 1); lupb_fielddef *f = lupb_fielddef_check(L, 1);
const char *str = luaL_checkstring(L, 2); const char *str = luaL_checkstring(L, 2);
@ -329,11 +332,7 @@ static int lupb_fielddef_new(lua_State *L) {
static void lupb_fielddef_getorcreate(lua_State *L, upb_fielddef *f) { static void lupb_fielddef_getorcreate(lua_State *L, upb_fielddef *f) {
bool created = lupb_cache_getorcreate(L, f, "upb.fielddef"); bool created = lupb_cache_getorcreate(L, f, "upb.fielddef");
if (created) { if (created) upb_fielddef_ref(f);
// 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) { static int lupb_fielddef_newindex(lua_State *L) {
@ -495,6 +494,8 @@ typedef struct {
upb_symtab *symtab; upb_symtab *symtab;
} lupb_symtab; } lupb_symtab;
static upb_accessor_vtbl *lupb_accessor(upb_fielddef *f);
// Inherits a ref on the symtab. // Inherits a ref on the symtab.
// Checks that narg is a proper lupb_symtab object. If it is, leaves its // Checks that narg is a proper lupb_symtab object. If it is, leaves its
// metatable on the stack for cache lookups/updates. // metatable on the stack for cache lookups/updates.
@ -584,10 +585,8 @@ static int lupb_symtab_getdefs(lua_State *L) {
lua_createtable(L, count, 0); lua_createtable(L, count, 0);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
upb_def *def = defs[i]; upb_def *def = defs[i];
lua_pushnumber(L, i + 1); // 1-based array.
lupb_def_getorcreate(L, def, true); lupb_def_getorcreate(L, def, true);
// Add it to our return table. lua_rawseti(L, -2, i + 1);
lua_settable(L, -3);
} }
free(defs); free(defs);
return 1; return 1;
@ -608,10 +607,16 @@ static const struct luaL_Reg lupb_symtab_mm[] = {
/* lupb_msg********************************************************************/ /* lupb_msg********************************************************************/
// Messages are userdata where we store primitive values (numbers and bools) // Messages are userdata. Primitive values (numbers and bools, and their
// right in the userdata. We also use integer entries in the environment table // hasbits) are stored right in the userdata. Other values are stored using
// like so: // integer entries in the environment table and no hasbits are used (since
// {msgdef, <string, submessage, or array fields>} // "nil" in the environment table can indicate "not present").
//
// The environment table looks like:
// {msgdef, <string, submessage, and array fields>}
// Must pass a upb_fielddef as the pointer.
static void lupb_array_pushnew(lua_State *L, void *f);
static void *lupb_msg_check(lua_State *L, int narg, upb_msgdef **md) { static void *lupb_msg_check(lua_State *L, int narg, upb_msgdef **md) {
void *msg = luaL_checkudata(L, narg, "upb.msg"); void *msg = luaL_checkudata(L, narg, "upb.msg");
@ -627,7 +632,7 @@ static void *lupb_msg_check(lua_State *L, int narg, upb_msgdef **md) {
return msg; return msg;
} }
static void lupb_msg_pushnew(lua_State *L, upb_msgdef *md) { static void lupb_msg_pushnew(lua_State *L, void *md) {
void *msg = lua_newuserdata(L, upb_msgdef_size(md)); void *msg = lua_newuserdata(L, upb_msgdef_size(md));
luaL_getmetatable(L, "upb.msg"); luaL_getmetatable(L, "upb.msg");
assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb. assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb.
@ -646,52 +651,52 @@ static int lupb_msg_new(lua_State *L) {
} }
static int lupb_msg_index(lua_State *L) { static int lupb_msg_index(lua_State *L) {
assert(lua_gettop(L) == 2); // __index should always be called with 2 args.
upb_msgdef *md; upb_msgdef *md;
void *m = lupb_msg_check(L, 1, &md); void *m = lupb_msg_check(L, 1, &md);
const char *name = luaL_checkstring(L, 2); upb_fielddef *f = upb_msgdef_ntof(md, luaL_checkstring(L, 2));
upb_fielddef *f = upb_msgdef_ntof(md, name); if (!f) luaL_argerror(L, 2, "not a field name");
if (!f) luaL_error(L, "%s is not a field name", name); if (upb_isprimitivetype(upb_fielddef_type(f))) {
if (upb_isseq(f)) luaL_error(L, "NYI: access of repeated fields"); upb_value v = upb_msg_has(m, f) ? upb_msg_get(m, f) : upb_fielddef_default(f);
upb_value val = lupb_pushvalue(L, v, f);
upb_msg_has(m, f) ? upb_msg_get(m, f) : upb_fielddef_default(f); } else {
lupb_pushvalue(L, val, f); lua_getfenv(L, 1);
lua_rawgeti(L, -1, f->offset);
if (lua_isnil(L, -1)) {
// Need to lazily create array, string, or submessage.
if (upb_isseq(f)) {
lupb_array_pushnew(L, f);
} else if (upb_isstring(f)) {
// TODO: (need to figure out default string ownership).
} else if (upb_issubmsg(f)) {
lupb_msg_pushnew(L, upb_downcast_msgdef(upb_fielddef_subdef(f)));
} else {
luaL_error(L, "internal error");
}
lua_rawseti(L, -2, f->offset);
}
}
return 1; return 1;
} }
static int lupb_msg_newindex(lua_State *L) { static int lupb_msg_newindex(lua_State *L) {
assert(lua_gettop(L) == 3); // __newindex should always be called with 3 args.
upb_msgdef *md; upb_msgdef *md;
void *m = lupb_msg_check(L, 1, &md); void *m = lupb_msg_check(L, 1, &md);
const char *name = luaL_checkstring(L, 2); upb_fielddef *f = upb_msgdef_ntof(md, luaL_checkstring(L, 2));
upb_fielddef *f = upb_msgdef_ntof(md, name); if (!f) luaL_error(L, "not a field name");
if (!f) luaL_error(L, "%s is not a field name", name); if (upb_isprimitivetype(upb_fielddef_type(f))) {
upb_msg_set(m, f, lupb_getvalue(L, 3, f, NULL)); if (lua_isnil(L, 3))
return 0; upb_msg_clearbit(m, f);
} else
upb_msg_set(m, f, lupb_getvalue(L, 3, f, NULL));
#if 0 } else {
static int lupb_msg_parse(lua_State *L) { if (!lua_isnil(L, 3)) lupb_typecheck(L, 3, f);
lupb_msg *m = lupb_msg_check(L, 1); lua_getfenv(L, 1);
size_t len; lua_pushvalue(L, 3);
const char *strbuf = luaL_checklstring(L, 2, &len); lua_rawseti(L, -1, f->offset);
upb_string str = UPB_STACK_STRING_LEN(strbuf, len); }
upb_status status = UPB_STATUS_INIT;
upb_strtomsg(&str, m->msg, m->msgdef, &status);
lupb_checkstatus(L, &status);
return 0; return 0;
} }
static int lupb_msg_totext(lua_State *L) {
lupb_msg *m = lupb_msg_check(L, 1);
upb_string *str = upb_string_new();
upb_msgtotext(str, m->msg, m->msgdef, false);
lupb_pushstring(L, str);
upb_string_unref(str);
return 1;
}
#endif
static const struct luaL_Reg lupb_msg_mm[] = { static const struct luaL_Reg lupb_msg_mm[] = {
{"__index", lupb_msg_index}, {"__index", lupb_msg_index},
{"__newindex", lupb_msg_newindex}, {"__newindex", lupb_msg_newindex},
@ -709,9 +714,8 @@ static int lupb_clear(lua_State *L) {
static int lupb_has(lua_State *L) { static int lupb_has(lua_State *L) {
upb_msgdef *md; upb_msgdef *md;
void *m = lupb_msg_check(L, 1, &md); void *m = lupb_msg_check(L, 1, &md);
const char *name = luaL_checkstring(L, 2); upb_fielddef *f = upb_msgdef_ntof(md, luaL_checkstring(L, 2));
upb_fielddef *f = upb_msgdef_ntof(md, name); if (!f) luaL_argerror(L, 2, "not a field name");
if (!f) luaL_error(L, "%s is not a field name", name);
lua_pushboolean(L, upb_msg_has(m, f)); lua_pushboolean(L, upb_msg_has(m, f));
return 1; return 1;
} }
@ -723,6 +727,222 @@ static int lupb_msgdef(lua_State *L) {
return 1; return 1;
} }
// Accessors for arrays, strings, and submessages need access to the current
// userdata's environment table, which can only be stored in Lua space.
// Options for storing it are:
//
// - put the env tables for all messages and arrays in the registry, keyed by
// userdata pointer (light userdata), or by a reference using luaL_ref().
// Then we can just let upb's parse stack track the stack of env tables.
// Easy but requires all messages and arraysto be in the registry, which
// seems too heavyweight.
//
// - store the stack of env tables in the Lua stack. Convenient, but requires
// special code to handle resumable decoders.
//
// There is also the question of how to obtain the lua_State* pointer.
// The main options for this are:
//
// - make our closure point to a struct:
// struct { void *msg; lua_State *L; }
// But then we can't use standard accessors, which expect the closure
// to point to the data itself. Using the standard accessors for
// primitive values is both a simplicity and a performance win.
//
// - store a lua_State* pointer inside each userdata. Convenient and
// efficient, but makes every message sizeof(void*) larger.
// Currently we take this route.
//
// - use thread-local storage. Convenient and efficient, but not portable.
typedef void createfunc_t(lua_State *L, void *param);
static upb_sflow_t lupb_msg_start(void *m, upb_fielddef *f, bool array,
createfunc_t *pushnew, void *param) {
lua_State *L = *(lua_State**)m;
int offset = array ? lua_rawlen(L, -1) : f->offset;
if (!lua_checkstack(L, 3)) luaL_error(L, "stack full");
lua_rawgeti(L, -1, offset);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
pushnew(L, param);
lua_pushvalue(L, -1);
lua_rawseti(L, -3, offset);
}
void *subval = lua_touserdata(L, -1);
lua_getfenv(L, -1);
lua_replace(L, -2); // Replace subval userdata with fenv.
return UPB_CONTINUE_WITH(subval);
}
static upb_flow_t lupb_msg_string(void *m, upb_value fval, upb_value val,
bool array) {
// Could add lazy materialization of strings here.
upb_fielddef *f = upb_value_getfielddef(fval);
lua_State *L = *(lua_State**)m;
int offset = array ? lua_rawlen(L, -1) : f->offset;
if (!lua_checkstack(L, 1)) luaL_error(L, "stack full");
lupb_pushstring(L, upb_value_getstrref(val));
lua_rawseti(L, -2, offset);
return UPB_CONTINUE;
}
static upb_sflow_t lupb_msg_startseq(void *m, upb_value fval) {
upb_fielddef *f = upb_value_getfielddef(fval);
return lupb_msg_start(m, f, false, lupb_array_pushnew, f);
}
static upb_sflow_t lupb_msg_startsubmsg(void *m, upb_value fval) {
upb_fielddef *f = upb_value_getfielddef(fval);
return lupb_msg_start(m, f, false, lupb_msg_pushnew, upb_fielddef_subdef(f));
}
static upb_sflow_t lupb_msg_startsubmsg_r(void *a, upb_value fval) {
upb_fielddef *f = upb_value_getfielddef(fval);
return lupb_msg_start(a, f, true, lupb_msg_pushnew, upb_fielddef_subdef(f));
}
static upb_flow_t lupb_msg_stringval(void *m, upb_value fval, upb_value val) {
return lupb_msg_string(m, fval, val, false);
}
static upb_flow_t lupb_msg_stringval_r(void *a, upb_value fval, upb_value val) {
return lupb_msg_string(a, fval, val, true);
}
#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
#define STDMSG(type, size) static upb_accessor_vtbl vtbl = { \
&lupb_msg_startsubmsg, \
&upb_stdmsg_set ## type, \
&lupb_msg_startseq, \
&lupb_msg_startsubmsg_r, \
&upb_stdmsg_set ## type ## _r, \
&upb_stdmsg_has, \
&upb_stdmsg_getptr, \
&upb_stdmsg_get ## type, \
&upb_stdmsg_seqbegin, \
&upb_stdmsg_ ## size ## byte_seqnext, \
&upb_stdmsg_seqget ## type};
#define RETURN_STDMSG(type, size) { STDMSG(type, size); return &vtbl; }
static upb_accessor_vtbl *lupb_accessor(upb_fielddef *f) {
switch (f->type) {
case UPB_TYPE(DOUBLE): RETURN_STDMSG(double, 8)
case UPB_TYPE(FLOAT): RETURN_STDMSG(float, 4)
case UPB_TYPE(UINT64):
case UPB_TYPE(FIXED64): RETURN_STDMSG(uint64, 8)
case UPB_TYPE(INT64):
case UPB_TYPE(SFIXED64):
case UPB_TYPE(SINT64): RETURN_STDMSG(int64, 8)
case UPB_TYPE(INT32):
case UPB_TYPE(SINT32):
case UPB_TYPE(ENUM):
case UPB_TYPE(SFIXED32): RETURN_STDMSG(int32, 4)
case UPB_TYPE(UINT32):
case UPB_TYPE(FIXED32): RETURN_STDMSG(uint32, 4)
case UPB_TYPE(BOOL): { STDMSG(bool, 1); return &vtbl; }
case UPB_TYPE(GROUP):
case UPB_TYPE(MESSAGE): RETURN_STDMSG(ptr, 8) // TODO: 32-bit
case UPB_TYPE(STRING):
case UPB_TYPE(BYTES): {
STDMSG(ptr, 8);
vtbl.set = &lupb_msg_stringval;
vtbl.append = &lupb_msg_stringval_r;
return &vtbl;
}
}
return NULL;
}
/* lupb_array ****************************************************************/
// Array: we store all elements in the environment table. Could optimize by
// storing primitive arrays in our own memory; this would be significantly more
// space efficient. Lua array elements are 16 bytes each; our own array would
// be 1/4 the space for 32-bit integers, or 1/16 the space for booleans.
//
// The first element of the environment table stores our type (which will be
// either an integer from upb.TYPE_* or a upb.msgdef), the remaining elements
// store the elements. We always keep all elements contiguous so we can use
// lua_objlen()/lua_rawlen() (for Lua 5.1/5.2 respectively) to report its len).
// narg is offset of environment table.
static size_t lupb_array_getlen(lua_State *L, int narg) {
return lua_rawlen(L, narg) - 1;
}
static void lupb_array_check(lua_State *L, int narg) {
if (!luaL_checkudata(L, narg, "upb.array"))
luaL_typerror(L, narg, "upb array");
}
static void lupb_array_pushnew(lua_State *L, void *f) {
(void)L;
(void)f;
}
static int lupb_array_new(lua_State *L) {
(void)L;
return 0;
}
static int lupb_array_len(lua_State *L) {
lupb_array_check(L, 1);
lua_getfenv(L, 1);
lua_pushnumber(L, lupb_array_getlen(L, -1));
return 1;
}
static int lupb_array_index(lua_State *L) {
assert(lua_gettop(L) == 2); // __index should always be called with 2 args.
lupb_array_check(L, 1);
lua_Number num = luaL_checknumber(L, 2);
if (!lupb_isint(num)) luaL_typerror(L, 2, "integer");
lua_getfenv(L, 1);
size_t len = lupb_array_getlen(L, -1);
if (num < 1 || num > len) luaL_error(L, "array bounds check failed");
lua_rawgeti(L, -1, num + 1);
return 1;
}
static int lupb_array_newindex(lua_State *L) {
assert(lua_gettop(L) == 3); // __newindex should always be called with 3 args.
lupb_array_check(L, 1);
lua_Number num = luaL_checknumber(L, 2);
if (rint(num) != num) luaL_typerror(L, 2, "integer");
lua_getfenv(L, 1);
size_t len = lupb_array_getlen(L, -1);
// We only allow extending the index one beyond the end.
if (num < 1 || num > len + 1) luaL_error(L, "array bounds check failed");
lua_pushvalue(L, 3);
lua_rawseti(L, -2, num);
return 0;
}
static const struct luaL_Reg lupb_array_mm[] = {
{"__len", lupb_array_len},
{"__index", lupb_array_index},
{"__newindex", lupb_array_newindex},
{NULL, NULL}
};
/* lupb toplevel **************************************************************/ /* lupb toplevel **************************************************************/
@ -732,7 +952,7 @@ static const struct luaL_Reg lupb_toplevel_m[] = {
{"FieldDef", lupb_fielddef_new}, {"FieldDef", lupb_fielddef_new},
{"Message", lupb_msg_new}, {"Message", lupb_msg_new},
//{"Array", lupb_array_new}, {"Array", lupb_array_new},
{"clear", lupb_clear}, {"clear", lupb_clear},
{"msgdef", lupb_msgdef}, {"msgdef", lupb_msgdef},

@ -30,7 +30,7 @@ void compare_arrays(const google::protobuf::Reflection *r,
{ {
ASSERT(upb_msg_has(upb_msg, upb_f)); ASSERT(upb_msg_has(upb_msg, upb_f));
ASSERT(upb_isseq(upb_f)); ASSERT(upb_isseq(upb_f));
void *arr = upb_value_getptr(upb_msg_get(upb_msg, upb_f)); void *arr = upb_value_getptr(upb_msg_getseq(upb_msg, upb_f));
void *iter = upb_seq_begin(arr, upb_f); void *iter = upb_seq_begin(arr, upb_f);
for(int i = 0; for(int i = 0;
i < r->FieldSize(proto2_msg, proto2_f); i < r->FieldSize(proto2_msg, proto2_f);

@ -59,7 +59,7 @@ static void test_upb_symtab() {
upb_msgdef *m = upb_downcast_msgdef(def); upb_msgdef *m = upb_downcast_msgdef(def);
upb_msg_iter i = upb_msg_begin(m); upb_msg_iter i = upb_msg_begin(m);
upb_fielddef *f = upb_msg_iter_field(i); upb_fielddef *f = upb_msg_iter_field(i);
ASSERT(upb_hasdef(f)); ASSERT(upb_hassubdef(f));
upb_def *def2 = f->def; upb_def *def2 = f->def;
i = upb_msg_next(m, i); i = upb_msg_next(m, i);

@ -278,58 +278,40 @@ NEXTFUNC(8)
NEXTFUNC(4) NEXTFUNC(4)
NEXTFUNC(1) NEXTFUNC(1)
#define STDMSG(type) { static upb_accessor_vtbl vtbl = {NULL, &upb_stdmsg_startsubmsg, \ #define STDMSG(type, size) { static upb_accessor_vtbl vtbl = { \
&upb_stdmsg_set ## type, &upb_stdmsg_has, &upb_stdmsg_get ## type, \ &upb_stdmsg_startsubmsg, \
NULL, NULL, NULL}; return &vtbl; } &upb_stdmsg_set ## type, \
#define STDMSG_R(type, size) { static upb_accessor_vtbl vtbl = { \ &upb_stdmsg_startseq, \
&upb_stdmsg_startseq, &upb_stdmsg_startsubmsg_r, &upb_stdmsg_set ## type ## _r, \ &upb_stdmsg_startsubmsg_r, \
&upb_stdmsg_has, &upb_stdmsg_getptr, &upb_stdmsg_seqbegin, \ &upb_stdmsg_set ## type ## _r, \
&upb_stdmsg_ ## size ## byte_seqnext, &upb_stdmsg_seqget ## type}; \ &upb_stdmsg_has, \
&upb_stdmsg_getptr, \
&upb_stdmsg_get ## type, \
&upb_stdmsg_seqbegin, \
&upb_stdmsg_ ## size ## byte_seqnext, \
&upb_stdmsg_seqget ## type}; \
return &vtbl; } return &vtbl; }
upb_accessor_vtbl *upb_stdmsg_accessor(upb_fielddef *f) { upb_accessor_vtbl *upb_stdmsg_accessor(upb_fielddef *f) {
if (upb_isseq(f)) { switch (f->type) {
switch (f->type) { case UPB_TYPE(DOUBLE): STDMSG(double, 8)
case UPB_TYPE(DOUBLE): STDMSG_R(double, 8) case UPB_TYPE(FLOAT): STDMSG(float, 4)
case UPB_TYPE(FLOAT): STDMSG_R(float, 4) case UPB_TYPE(UINT64):
case UPB_TYPE(UINT64): case UPB_TYPE(FIXED64): STDMSG(uint64, 8)
case UPB_TYPE(FIXED64): STDMSG_R(uint64, 8) case UPB_TYPE(INT64):
case UPB_TYPE(INT64): case UPB_TYPE(SFIXED64):
case UPB_TYPE(SFIXED64): case UPB_TYPE(SINT64): STDMSG(int64, 8)
case UPB_TYPE(SINT64): STDMSG_R(int64, 8) case UPB_TYPE(INT32):
case UPB_TYPE(INT32): case UPB_TYPE(SINT32):
case UPB_TYPE(SINT32): case UPB_TYPE(ENUM):
case UPB_TYPE(ENUM): case UPB_TYPE(SFIXED32): STDMSG(int32, 4)
case UPB_TYPE(SFIXED32): STDMSG_R(int32, 4) case UPB_TYPE(UINT32):
case UPB_TYPE(UINT32): case UPB_TYPE(FIXED32): STDMSG(uint32, 4)
case UPB_TYPE(FIXED32): STDMSG_R(uint32, 4) case UPB_TYPE(BOOL): STDMSG(bool, 1)
case UPB_TYPE(BOOL): STDMSG_R(bool, 1) case UPB_TYPE(STRING):
case UPB_TYPE(STRING): case UPB_TYPE(BYTES):
case UPB_TYPE(BYTES): case UPB_TYPE(GROUP):
case UPB_TYPE(GROUP): case UPB_TYPE(MESSAGE): STDMSG(str, 8) // TODO: 32-bit
case UPB_TYPE(MESSAGE): STDMSG_R(str, 8) // TODO: 32-bit
}
} else {
switch (f->type) {
case UPB_TYPE(DOUBLE): STDMSG(double)
case UPB_TYPE(FLOAT): STDMSG(float)
case UPB_TYPE(UINT64):
case UPB_TYPE(FIXED64): STDMSG(uint64)
case UPB_TYPE(INT64):
case UPB_TYPE(SFIXED64):
case UPB_TYPE(SINT64): STDMSG(int64)
case UPB_TYPE(INT32):
case UPB_TYPE(SINT32):
case UPB_TYPE(ENUM):
case UPB_TYPE(SFIXED32): STDMSG(int32)
case UPB_TYPE(UINT32):
case UPB_TYPE(FIXED32): STDMSG(uint32)
case UPB_TYPE(BOOL): STDMSG(bool)
case UPB_TYPE(STRING):
case UPB_TYPE(BYTES):
case UPB_TYPE(GROUP):
case UPB_TYPE(MESSAGE): STDMSG(str)
}
} }
return NULL; return NULL;
} }
@ -337,10 +319,15 @@ upb_accessor_vtbl *upb_stdmsg_accessor(upb_fielddef *f) {
static void upb_accessors_onfreg(void *c, upb_fhandlers *fh, upb_fielddef *f) { static void upb_accessors_onfreg(void *c, upb_fhandlers *fh, upb_fielddef *f) {
(void)c; (void)c;
if (f->accessor) { if (f->accessor) {
upb_fhandlers_setstartseq(fh, f->accessor->appendseq);
upb_fhandlers_setvalue(fh, f->accessor->set);
upb_fhandlers_setstartsubmsg(fh, f->accessor->appendsubmsg);
upb_fhandlers_setfval(fh, f->fval); upb_fhandlers_setfval(fh, f->fval);
if (upb_isseq(f)) {
upb_fhandlers_setstartseq(fh, f->accessor->startseq);
upb_fhandlers_setvalue(fh, f->accessor->append);
upb_fhandlers_setstartsubmsg(fh, f->accessor->appendsubmsg);
} else {
upb_fhandlers_setvalue(fh, f->accessor->set);
upb_fhandlers_setstartsubmsg(fh, f->accessor->startsubmsg);
}
} }
} }

@ -51,12 +51,17 @@ INLINE bool upb_seq_done(void *iter) { return iter == NULL; }
typedef struct _upb_accessor_vtbl { typedef struct _upb_accessor_vtbl {
// Writers. These take an fval as a parameter because the callbacks are used // Writers. These take an fval as a parameter because the callbacks are used
// as upb_handlers, but the fval is always the fielddef for that field. // as upb_handlers, but the fval is always the fielddef for that field.
upb_startfield_handler *appendseq; // Repeated fields only. upb_startfield_handler *startsubmsg; // Non-repeated submsg fields.
upb_startfield_handler *appendsubmsg; // Submsg fields (repeated or no). upb_value_handler *set; // Non-repeated scalar fields.
upb_value_handler *set; // Scalar fields (repeated or no). upb_startfield_handler *startseq; // Repeated fields only.
upb_startfield_handler *appendsubmsg; // Repeated submsg fields.
upb_value_handler *append; // Repeated scalar fields.
// TODO: expect to also need endsubmsg and endseq.
// Readers. // Readers.
upb_has_reader *has; upb_has_reader *has;
upb_value_reader *getseq;
upb_value_reader *get; upb_value_reader *get;
upb_seqbegin_handler *seqbegin; upb_seqbegin_handler *seqbegin;
upb_seqnext_handler *seqnext; upb_seqnext_handler *seqnext;
@ -82,6 +87,10 @@ upb_accessor_vtbl *upb_stdmsg_accessor(upb_fielddef *f);
// defaults (but not strings, submessages, or arrays). // defaults (but not strings, submessages, or arrays).
void upb_msg_clear(void *msg, upb_msgdef *md); void upb_msg_clear(void *msg, upb_msgdef *md);
INLINE void upb_msg_clearbit(void *msg, upb_fielddef *f) {
((char*)msg)[f->hasbit / 8] &= ~(1 << (f->hasbit % 8));
}
// Could add a method that recursively clears submessages, strings, and // Could add a method that recursively clears submessages, strings, and
// arrays if desired. This could be a win if you wanted to merge without // arrays if desired. This could be a win if you wanted to merge without
// needing hasbits, because during parsing you would never clear submessages // needing hasbits, because during parsing you would never clear submessages
@ -94,10 +103,16 @@ INLINE bool upb_msg_has(void *m, upb_fielddef *f) {
// May only be called for fields that have accessors. // May only be called for fields that have accessors.
INLINE upb_value upb_msg_get(void *m, upb_fielddef *f) { INLINE upb_value upb_msg_get(void *m, upb_fielddef *f) {
assert(f->accessor); assert(f->accessor && !upb_isseq(f));
return f->accessor->get(m, f->fval); return f->accessor->get(m, f->fval);
} }
// May only be called for fields that have accessors.
INLINE upb_value upb_msg_getseq(void *m, upb_fielddef *f) {
assert(f->accessor && upb_isseq(f));
return f->accessor->getseq(m, f->fval);
}
INLINE void upb_msg_set(void *m, upb_fielddef *f, upb_value val) { INLINE void upb_msg_set(void *m, upb_fielddef *f, upb_value val) {
assert(f->accessor); assert(f->accessor);
f->accessor->set(m, f->fval, val); f->accessor->set(m, f->fval, val);
@ -182,6 +197,7 @@ upb_flow_t upb_stdmsg_setuint32(void *c, upb_value fval, upb_value val);
upb_flow_t upb_stdmsg_setdouble(void *c, upb_value fval, upb_value val); upb_flow_t upb_stdmsg_setdouble(void *c, upb_value fval, upb_value val);
upb_flow_t upb_stdmsg_setfloat(void *c, upb_value fval, upb_value val); upb_flow_t upb_stdmsg_setfloat(void *c, upb_value fval, upb_value val);
upb_flow_t upb_stdmsg_setbool(void *c, upb_value fval, upb_value val); upb_flow_t upb_stdmsg_setbool(void *c, upb_value fval, upb_value val);
upb_flow_t upb_stdmsg_setptr(void *c, upb_value fval, upb_value val);
// Value writers for repeated fields: the closure points to a standard array // Value writers for repeated fields: the closure points to a standard array
// struct, appends the value to the end of the array, resizing with realloc() // struct, appends the value to the end of the array, resizing with realloc()
@ -199,6 +215,7 @@ upb_flow_t upb_stdmsg_setuint32_r(void *c, upb_value fval, upb_value val);
upb_flow_t upb_stdmsg_setdouble_r(void *c, upb_value fval, upb_value val); upb_flow_t upb_stdmsg_setdouble_r(void *c, upb_value fval, upb_value val);
upb_flow_t upb_stdmsg_setfloat_r(void *c, upb_value fval, upb_value val); upb_flow_t upb_stdmsg_setfloat_r(void *c, upb_value fval, upb_value val);
upb_flow_t upb_stdmsg_setbool_r(void *c, upb_value fval, upb_value val); upb_flow_t upb_stdmsg_setbool_r(void *c, upb_value fval, upb_value val);
upb_flow_t upb_stdmsg_setptr_r(void *c, upb_value fval, upb_value val);
// Writers for C strings (NULL-terminated): we can find a char* at a known // Writers for C strings (NULL-terminated): we can find a char* at a known
// offset from the closure "c". Calls realloc() on the pointer to allocate // offset from the closure "c". Calls realloc() on the pointer to allocate

@ -89,6 +89,8 @@ void upb_read_descriptor(upb_symtab *symtab, const char *str, size_t len,
if (upb_ok(status)) upb_symtab_add(symtab, defs, n, status); if (upb_ok(status)) upb_symtab_add(symtab, defs, n, status);
for(int i = 0; i < n; i++) upb_def_unref(defs[i]);
upb_descreader_uninit(&r); upb_descreader_uninit(&r);
upb_stringsrc_uninit(&strsrc); upb_stringsrc_uninit(&strsrc);
upb_decoder_uninit(&d); upb_decoder_uninit(&d);

Loading…
Cancel
Save