summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lang_ext/lua/upb.c368
-rw-r--r--tests/test_vs_proto2.cc2
-rw-r--r--tests/tests.c2
-rw-r--r--upb/msg.c91
-rw-r--r--upb/msg.h25
-rw-r--r--upb/pb/glue.c2
6 files changed, 358 insertions, 132 deletions
diff --git a/lang_ext/lua/upb.c b/lang_ext/lua/upb.c
index 0cc6806..75d1585 100644
--- a/lang_ext/lua/upb.c
+++ b/lang_ext/lua/upb.c
@@ -15,8 +15,14 @@
#include "upb/msg.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 lupb_isint(double n) { return (double)(int)n == n; }
+
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)
@@ -31,6 +37,17 @@ static uint32_t lupb_touint32(lua_State *L, int narg, const char *name) {
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) {
switch (f->type) {
case UPB_TYPE(INT32):
@@ -121,10 +138,15 @@ static upb_value lupb_getvalue(lua_State *L, int narg, upb_fielddef *f,
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_fielddef_getorcreate(lua_State *L, upb_fielddef *f);
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) {
if (!upb_ok(s)) {
@@ -200,7 +222,7 @@ typedef struct {
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");
+ if (!ldef) luaL_typerror(L, narg, "upb def");
return ldef;
}
@@ -232,29 +254,10 @@ typedef struct {
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");
+ if (!f) luaL_typerror(L, narg, "upb fielddef");
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) {
lupb_fielddef *f = lupb_fielddef_check(L, 1);
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) {
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 (created) upb_fielddef_ref(f);
}
static int lupb_fielddef_newindex(lua_State *L) {
@@ -495,6 +494,8 @@ typedef struct {
upb_symtab *symtab;
} lupb_symtab;
+static upb_accessor_vtbl *lupb_accessor(upb_fielddef *f);
+
// Inherits a ref on the symtab.
// Checks that narg is a proper lupb_symtab object. If it is, leaves its
// 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);
for (int i = 0; i < count; i++) {
upb_def *def = defs[i];
- lua_pushnumber(L, i + 1); // 1-based array.
lupb_def_getorcreate(L, def, true);
- // Add it to our return table.
- lua_settable(L, -3);
+ lua_rawseti(L, -2, i + 1);
}
free(defs);
return 1;
@@ -608,10 +607,16 @@ static const struct luaL_Reg lupb_symtab_mm[] = {
/* lupb_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>}
+// Messages are userdata. Primitive values (numbers and bools, and their
+// hasbits) are stored right in the userdata. Other values are stored using
+// integer entries in the environment table and no hasbits are used (since
+// "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) {
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;
}
-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));
luaL_getmetatable(L, "upb.msg");
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) {
- assert(lua_gettop(L) == 2); // __index should always be called with 2 args.
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);
+ upb_fielddef *f = upb_msgdef_ntof(md, luaL_checkstring(L, 2));
+ if (!f) luaL_argerror(L, 2, "not a field name");
+ if (upb_isprimitivetype(upb_fielddef_type(f))) {
+ upb_value v = upb_msg_has(m, f) ? upb_msg_get(m, f) : upb_fielddef_default(f);
+ lupb_pushvalue(L, v, f);
+ } else {
+ 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;
}
static int lupb_msg_newindex(lua_State *L) {
- assert(lua_gettop(L) == 3); // __newindex should always be called with 3 args.
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_parse(lua_State *L) {
- lupb_msg *m = lupb_msg_check(L, 1);
- size_t len;
- const char *strbuf = luaL_checklstring(L, 2, &len);
- 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);
+ upb_fielddef *f = upb_msgdef_ntof(md, luaL_checkstring(L, 2));
+ if (!f) luaL_error(L, "not a field name");
+ if (upb_isprimitivetype(upb_fielddef_type(f))) {
+ if (lua_isnil(L, 3))
+ upb_msg_clearbit(m, f);
+ else
+ upb_msg_set(m, f, lupb_getvalue(L, 3, f, NULL));
+ } else {
+ if (!lua_isnil(L, 3)) lupb_typecheck(L, 3, f);
+ lua_getfenv(L, 1);
+ lua_pushvalue(L, 3);
+ lua_rawseti(L, -1, f->offset);
+ }
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[] = {
{"__index", lupb_msg_index},
{"__newindex", lupb_msg_newindex},
@@ -709,9 +714,8 @@ static int lupb_clear(lua_State *L) {
static int lupb_has(lua_State *L) {
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_fielddef *f = upb_msgdef_ntof(md, luaL_checkstring(L, 2));
+ if (!f) luaL_argerror(L, 2, "not a field name");
lua_pushboolean(L, upb_msg_has(m, f));
return 1;
}
@@ -723,6 +727,222 @@ static int lupb_msgdef(lua_State *L) {
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 **************************************************************/
@@ -732,7 +952,7 @@ static const struct luaL_Reg lupb_toplevel_m[] = {
{"FieldDef", lupb_fielddef_new},
{"Message", lupb_msg_new},
- //{"Array", lupb_array_new},
+ {"Array", lupb_array_new},
{"clear", lupb_clear},
{"msgdef", lupb_msgdef},
diff --git a/tests/test_vs_proto2.cc b/tests/test_vs_proto2.cc
index 0444d40..b22c620 100644
--- a/tests/test_vs_proto2.cc
+++ b/tests/test_vs_proto2.cc
@@ -30,7 +30,7 @@ void compare_arrays(const google::protobuf::Reflection *r,
{
ASSERT(upb_msg_has(upb_msg, 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);
for(int i = 0;
i < r->FieldSize(proto2_msg, proto2_f);
diff --git a/tests/tests.c b/tests/tests.c
index 1f64718..fc8e11d 100644
--- a/tests/tests.c
+++ b/tests/tests.c
@@ -59,7 +59,7 @@ static void test_upb_symtab() {
upb_msgdef *m = upb_downcast_msgdef(def);
upb_msg_iter i = upb_msg_begin(m);
upb_fielddef *f = upb_msg_iter_field(i);
- ASSERT(upb_hasdef(f));
+ ASSERT(upb_hassubdef(f));
upb_def *def2 = f->def;
i = upb_msg_next(m, i);
diff --git a/upb/msg.c b/upb/msg.c
index a2b2cf7..0a9948a 100644
--- a/upb/msg.c
+++ b/upb/msg.c
@@ -278,58 +278,40 @@ NEXTFUNC(8)
NEXTFUNC(4)
NEXTFUNC(1)
-#define STDMSG(type) { static upb_accessor_vtbl vtbl = {NULL, &upb_stdmsg_startsubmsg, \
- &upb_stdmsg_set ## type, &upb_stdmsg_has, &upb_stdmsg_get ## type, \
- NULL, NULL, NULL}; return &vtbl; }
-#define STDMSG_R(type, size) { static upb_accessor_vtbl vtbl = { \
- &upb_stdmsg_startseq, &upb_stdmsg_startsubmsg_r, &upb_stdmsg_set ## type ## _r, \
- &upb_stdmsg_has, &upb_stdmsg_getptr, &upb_stdmsg_seqbegin, \
- &upb_stdmsg_ ## size ## byte_seqnext, &upb_stdmsg_seqget ## type}; \
+#define STDMSG(type, size) { static upb_accessor_vtbl vtbl = { \
+ &upb_stdmsg_startsubmsg, \
+ &upb_stdmsg_set ## type, \
+ &upb_stdmsg_startseq, \
+ &upb_stdmsg_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}; \
return &vtbl; }
upb_accessor_vtbl *upb_stdmsg_accessor(upb_fielddef *f) {
- if (upb_isseq(f)) {
- switch (f->type) {
- case UPB_TYPE(DOUBLE): STDMSG_R(double, 8)
- case UPB_TYPE(FLOAT): STDMSG_R(float, 4)
- case UPB_TYPE(UINT64):
- case UPB_TYPE(FIXED64): STDMSG_R(uint64, 8)
- case UPB_TYPE(INT64):
- case UPB_TYPE(SFIXED64):
- case UPB_TYPE(SINT64): STDMSG_R(int64, 8)
- case UPB_TYPE(INT32):
- case UPB_TYPE(SINT32):
- case UPB_TYPE(ENUM):
- case UPB_TYPE(SFIXED32): STDMSG_R(int32, 4)
- case UPB_TYPE(UINT32):
- case UPB_TYPE(FIXED32): STDMSG_R(uint32, 4)
- case UPB_TYPE(BOOL): STDMSG_R(bool, 1)
- case UPB_TYPE(STRING):
- case UPB_TYPE(BYTES):
- case UPB_TYPE(GROUP):
- 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)
- }
+ switch (f->type) {
+ case UPB_TYPE(DOUBLE): STDMSG(double, 8)
+ case UPB_TYPE(FLOAT): STDMSG(float, 4)
+ case UPB_TYPE(UINT64):
+ case UPB_TYPE(FIXED64): STDMSG(uint64, 8)
+ case UPB_TYPE(INT64):
+ case UPB_TYPE(SFIXED64):
+ case UPB_TYPE(SINT64): STDMSG(int64, 8)
+ case UPB_TYPE(INT32):
+ case UPB_TYPE(SINT32):
+ case UPB_TYPE(ENUM):
+ case UPB_TYPE(SFIXED32): STDMSG(int32, 4)
+ case UPB_TYPE(UINT32):
+ case UPB_TYPE(FIXED32): STDMSG(uint32, 4)
+ case UPB_TYPE(BOOL): STDMSG(bool, 1)
+ case UPB_TYPE(STRING):
+ case UPB_TYPE(BYTES):
+ case UPB_TYPE(GROUP):
+ case UPB_TYPE(MESSAGE): STDMSG(str, 8) // TODO: 32-bit
}
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) {
(void)c;
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);
+ 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);
+ }
}
}
diff --git a/upb/msg.h b/upb/msg.h
index ac9e877..20a5cfe 100644
--- a/upb/msg.h
+++ b/upb/msg.h
@@ -51,12 +51,17 @@ INLINE bool upb_seq_done(void *iter) { return iter == NULL; }
typedef struct _upb_accessor_vtbl {
// 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.
- 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).
+ upb_startfield_handler *startsubmsg; // Non-repeated submsg fields.
+ upb_value_handler *set; // Non-repeated scalar fields.
+ 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.
upb_has_reader *has;
+ upb_value_reader *getseq;
upb_value_reader *get;
upb_seqbegin_handler *seqbegin;
upb_seqnext_handler *seqnext;
@@ -82,6 +87,10 @@ upb_accessor_vtbl *upb_stdmsg_accessor(upb_fielddef *f);
// defaults (but not strings, submessages, or arrays).
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
// arrays if desired. This could be a win if you wanted to merge without
// 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.
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);
}
+// 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) {
assert(f->accessor);
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_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_setptr(void *c, upb_value fval, upb_value val);
// 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()
@@ -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_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_setptr_r(void *c, upb_value fval, upb_value val);
// 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
diff --git a/upb/pb/glue.c b/upb/pb/glue.c
index dfd9e88..6b52435 100644
--- a/upb/pb/glue.c
+++ b/upb/pb/glue.c
@@ -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);
+ for(int i = 0; i < n; i++) upb_def_unref(defs[i]);
+
upb_descreader_uninit(&r);
upb_stringsrc_uninit(&strsrc);
upb_decoder_uninit(&d);
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback