New upb_msg code and Lua bindings around it.

There are still some things that are unfinished,
but we are at parity with what Lua had before.
pull/13171/head
Josh Haberman 9 years ago
parent 77c97fd3f2
commit 4b0c4ca7fb
  1. 10
      Makefile
  2. 68
      tests/bindings/lua/test_upb.lua
  3. 22
      tests/bindings/lua/test_upb.pb.lua
  4. 1346
      upb/bindings/lua/def.c
  5. 1073
      upb/bindings/lua/msg.c
  6. 2011
      upb/bindings/lua/upb.c
  7. 64
      upb/bindings/lua/upb.h
  8. 892
      upb/bindings/lua/upb/msg.c
  9. 94
      upb/bindings/lua/upb/pb.c
  10. 15
      upb/def.c
  11. 40
      upb/def.h
  12. BIN
      upb/descriptor/descriptor.pb
  13. 22
      upb/descriptor/reader.c
  14. 1
      upb/json/parser.rl
  15. 1205
      upb/msg.c
  16. 340
      upb/msg.h
  17. 84
      upb/shim/shim.c
  18. 69
      upb/shim/shim.h
  19. 3
      upb/structdefs.int.h
  20. 34
      upb/table.int.h
  21. 4
      upb/upb.c
  22. 16
      upb/upb.h

@ -33,7 +33,7 @@ all: lib tests tools/upbc lua python
testall: test pythontest
# Set this to have user-specific flags (especially things like -O0 and -g).
USER_CPPFLAGS?=
USER_CPPFLAGS?=-O0 -g -ffunction-sections -fdata-sections -I/usr/include/lua5.2 -UNDEBUG
# Build with "make WITH_JIT=yes" (or anything besides "no") to enable the JIT.
WITH_JIT=no
@ -150,8 +150,8 @@ make_objs_cc = $$(patsubst upb/$$(pc).cc,obj/upb/$$(pc).$(1),$$($$(call to_srcs,
upb_SRCS = \
upb/def.c \
upb/handlers.c \
upb/msg.c \
upb/refcounted.c \
upb/shim/shim.c \
upb/symtab.c \
upb/table.c \
upb/upb.c \
@ -479,9 +479,9 @@ LUA_LIB_DEPS = \
lib/libupb.descriptor_pic.a \
lib/libupb_pic.a \
upb/bindings/lua/upb_c.so: upb/bindings/lua/upb.c $(LUA_LIB_DEPS)
$(E) CC upb/bindings/lua/upb.c
$(Q) $(CC) $(OPT) $(CSTD) $(WARNFLAGS) $(CPPFLAGS) $(CFLAGS) -fpic -shared -o $@ $< $(LUA_LDFLAGS) $(LUA_LIB_DEPS)
upb/bindings/lua/upb_c.so: upb/bindings/lua/upb.c upb/bindings/lua/def.c upb/bindings/lua/msg.c $(LUA_LIB_DEPS)
$(E) 'CC upb/bindings/lua/{upb,def,msg}.c'
$(Q) $(CC) $(OPT) $(CSTD) $(WARNFLAGS) $(CPPFLAGS) $(CFLAGS) -fpic -shared -o $@ $^ $(LUA_LDFLAGS)
upb/bindings/lua/upb/table_c.so: upb/bindings/lua/upb/table.c lib/libupb_pic.a
$(E) CC upb/bindings/lua/upb/table.c

@ -463,6 +463,7 @@ function test_numeric_array()
array[1] = val
assert_equal(val, array[1])
assert_equal(1, #array)
assert_equal(val, array[1])
-- Past the end of the array.
assert_error_match("array index", function() return array[2] end)
@ -513,7 +514,7 @@ function test_numeric_array()
-- values as int32s.
test_for_numeric_type(upb.TYPE_ENUM, 2^31 - 1, 2^31, -2^31 - 1, 5.1)
test_for_numeric_type(upb.TYPE_INT64, 2^62, 2^63, -2^64, bad64)
test_for_numeric_type(upb.TYPE_FLOAT, 10^38)
test_for_numeric_type(upb.TYPE_FLOAT, 340282306073709652508363335590014353408)
test_for_numeric_type(upb.TYPE_DOUBLE, 10^101)
end
@ -567,18 +568,19 @@ end
function test_msg_primitives()
local function test_for_numeric_type(upb_type, val, too_big, too_small, bad3)
msg = upb.Message(
upb.build_defs{
upb.MessageDef{full_name = "TestMessage", fields = {
upb.FieldDef{name = "f", number = 1, type = upb_type},
}
local symtab = upb.SymbolTable{
upb.MessageDef{full_name = "TestMessage", fields = {
upb.FieldDef{name = "f", number = 1, type = upb_type},
}
}
)
}
factory = upb.MessageFactory(symtab)
TestMessage = factory:get_message_class(symtab:lookup("TestMessage"))
msg = TestMessage()
-- Defaults to nil
assert_nil(msg.f)
assert_equal(0, msg.f)
msg.f = 0
assert_equal(0, msg.f)
@ -608,7 +610,7 @@ function test_msg_primitives()
assert_error_match(errmsg, function() msg.f = array end)
end
local msgdef = upb.build_defs{
local symtab = upb.SymbolTable{
upb.MessageDef{full_name = "TestMessage", fields = {
upb.FieldDef{name = "i32", number = 1, type = upb.TYPE_INT32},
upb.FieldDef{name = "u32", number = 2, type = upb.TYPE_UINT32},
@ -621,17 +623,18 @@ function test_msg_primitives()
}
}
msg = upb.Message(msgdef)
factory = upb.MessageFactory(symtab)
TestMessage = factory:get_message_class(symtab:lookup("TestMessage"))
msg = TestMessage()
-- Unset member returns nil. This is unlike C++/Java, but is more
-- Lua-like behavior.
assert_equal(nil, msg.i32)
assert_equal(nil, msg.u32)
assert_equal(nil, msg.i64)
assert_equal(nil, msg.u64)
assert_equal(nil, msg.dbl)
assert_equal(nil, msg.flt)
assert_equal(nil, msg.bool)
-- Unset member returns default value.
assert_equal(0, msg.i32)
assert_equal(0, msg.u32)
assert_equal(0, msg.i64)
assert_equal(0, msg.u64)
assert_equal(0, msg.dbl)
assert_equal(0, msg.flt)
assert_equal(false, msg.bool)
-- Attempts to access non-existent fields fail.
assert_error_match("no such field", function() msg.no_such = 1 end)
@ -661,7 +664,7 @@ function test_msg_primitives()
end
function test_msg_array()
local msgdef = upb.build_defs{
local symtab = upb.SymbolTable{
upb.MessageDef{full_name = "TestMessage", fields = {
upb.FieldDef{name = "i32_array", number = 1, type = upb.TYPE_INT32,
label = upb.LABEL_REPEATED},
@ -669,7 +672,9 @@ function test_msg_array()
}
}
msg = upb.Message(msgdef)
factory = upb.MessageFactory(symtab)
TestMessage = factory:get_message_class(symtab:lookup("TestMessage"))
msg = TestMessage()
assert_nil(msg.i32_array)
@ -680,7 +685,7 @@ function test_msg_array()
local function assign_int64()
msg.i32_array = upb.Array(upb.TYPE_INT64)
end
assert_error_match("Array type mismatch", assign_int64)
assert_error_match("Array had incorrect type", assign_int64)
local arr = upb.Array(upb.TYPE_INT32)
msg.i32_array = arr
@ -696,7 +701,7 @@ function test_msg_array()
end
function test_msg_submsg()
local test_msgdef, submsg_msgdef = upb.build_defs{
local symtab = upb.SymbolTable{
upb.MessageDef{full_name = "TestMessage", fields = {
upb.FieldDef{name = "submsg", number = 1, type = upb.TYPE_MESSAGE,
subdef_name = ".SubMessage"},
@ -705,17 +710,20 @@ function test_msg_submsg()
upb.MessageDef{full_name = "SubMessage"}
}
msg = upb.Message(test_msgdef)
factory = upb.MessageFactory(symtab)
TestMessage = factory:get_message_class(symtab:lookup("TestMessage"))
SubMessage = factory:get_message_class(symtab:lookup("SubMessage"))
msg = TestMessage()
assert_nil(msg.submsg)
-- Can't assign message of the wrong type.
local function assign_int64()
msg.submsg = upb.Message(test_msgdef)
msg.submsg = TestMessage()
end
assert_error_match("Message type mismatch", assign_int64)
assert_error_match("Message had incorrect type", assign_int64)
local sub = upb.Message(submsg_msgdef)
local sub = SubMessage()
msg.submsg = sub
assert_equal(sub, msg.submsg)
@ -760,8 +768,8 @@ function test_finalizer()
assert_error_match("called into dead object", function()
t[3]:number()
end)
assert_error_match("called into dead object",
function() t[4]:lookup()
assert_error_match("called into dead object", function()
t[4]:lookup()
end)
end)
t = {

@ -11,7 +11,7 @@ else
module("testupb_pb", lunit.testcase, package.seeall)
end
local primitive_types_msg = upb.build_defs{
local symtab = upb.SymbolTable{
upb.MessageDef{full_name = "TestMessage", fields = {
upb.FieldDef{name = "i32", number = 1, type = upb.TYPE_INT32},
upb.FieldDef{name = "u32", number = 2, type = upb.TYPE_UINT32},
@ -24,13 +24,16 @@ local primitive_types_msg = upb.build_defs{
}
}
local factory = upb.MessageFactory(symtab);
local TestMessage = factory:get_message_class(symtab:lookup("TestMessage"))
function test_decodermethod()
local dm = pb.DecoderMethod(primitive_types_msg)
local decoder = pb.MakeStringToMessageDecoder(TestMessage)
assert_error(
function()
-- Needs at least one argument to construct.
pb.DecoderMethod()
pb.MakeStringToMessageDecoder()
end)
end
@ -39,8 +42,8 @@ function test_parse_primitive()
"\008\128\128\128\128\002\016\128\128\128\128\004\024\128\128"
.. "\128\128\128\128\128\002\032\128\128\128\128\128\128\128\001\041\000"
.. "\000\000\000\000\000\248\063\053\000\000\096\064\056\001"
local dm = pb.DecoderMethod(primitive_types_msg)
msg = dm:parse(binary_pb)
local decoder = pb.MakeStringToMessageDecoder(TestMessage)
msg = decoder(binary_pb)
assert_equal(536870912, msg.i32)
assert_equal(1073741824, msg.u32)
assert_equal(1125899906842624, msg.i64)
@ -51,16 +54,19 @@ function test_parse_primitive()
end
function test_parse_string()
local msgdef = upb.build_defs{
local symtab = upb.SymbolTable{
upb.MessageDef{full_name = "TestMessage", fields = {
upb.FieldDef{name = "str", number = 1, type = upb.TYPE_STRING},
}
}
}
local factory = upb.MessageFactory(symtab);
local TestMessage = factory:get_message_class(symtab:lookup("TestMessage"))
local binary_pb = "\010\005Hello"
local dm = pb.DecoderMethod(msgdef)
msg = dm:parse(binary_pb)
local decoder = pb.MakeStringToMessageDecoder(TestMessage)
msg = decoder(binary_pb)
assert_equal("Hello", msg.str)
end

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -8,6 +8,7 @@
#include "lauxlib.h"
#include "upb/def.h"
#include "upb/handlers.h"
#include "upb/msg.h"
#include "upb/symtab.h"
/* Lua 5.1/5.2 compatibility code. */
@ -23,10 +24,14 @@
void *luaL_testudata(lua_State *L, int ud, const char *tname);
#define lupb_setfuncs(L, l) luaL_register(L, NULL, l)
#elif LUA_VERSION_NUM == 502
int luaL_typerror(lua_State *L, int narg, const char *tname);
#define lupb_setfuncs(L, l) luaL_setfuncs(L, l, 0)
#else
#error Only Lua 5.1 and 5.2 are supported
#endif
@ -69,6 +74,7 @@ uint32_t lupb_checkuint32(lua_State *L, int narg);
double lupb_checkdouble(lua_State *L, int narg);
float lupb_checkfloat(lua_State *L, int narg);
bool lupb_checkbool(lua_State *L, int narg);
const char *lupb_checkstring(lua_State *L, int narg, size_t *len);
const char *lupb_checkname(lua_State *L, int narg);
void lupb_pushint64(lua_State *L, int64_t val);
@ -77,10 +83,30 @@ void lupb_pushuint64(lua_State *L, uint64_t val);
void lupb_pushuint32(lua_State *L, uint32_t val);
void lupb_pushdouble(lua_State *L, double val);
void lupb_pushfloat(lua_State *L, float val);
void lupb_pushbool(lua_State *L, bool val);
/* Functions for getting/pushing wrappers to various types defined in the
* core library. */
/* Builds and returns a handlers object for populating a lupb_msg described by
* the MessageDef at "narg".
*
* TODO(haberman): factor this so it doesn't have to take a lua_State. We
* should be able to generate message handlers for a upb_msgdef that can be used
* across many Lua states, so we can shared JIT code across lua_States. */
const upb_handlers *lupb_msg_newwritehandlers(lua_State *L, int narg,
const void *owner);
/* Registers a type with the given name, methods, and metamethods.
* If "refcount_gc" is true, adds a __gc metamethod that does an unref.
* Refcounted types must be allocated with lupb_refcounted_push[new]wrapper. */
void lupb_register_type(lua_State *L, const char *name, const luaL_Reg *m,
const luaL_Reg *mm);
/* Checks the given upb_status and throws a Lua error if it is not ok. */
void lupb_checkstatus(lua_State *L, upb_status *s);
/** From def.c. ***************************************************************/
upb_fieldtype_t lupb_checkfieldtype(lua_State *L, int narg);
void *lupb_refcounted_check(lua_State *L, int narg, const char *type);
const upb_msgdef *lupb_msg_checkdef(lua_State *L, int narg);
const upb_msgdef *lupb_msgdef_check(lua_State *L, int narg);
@ -101,26 +127,22 @@ void lupb_symtab_pushwrapper(lua_State *L, const upb_symtab *s,
void lupb_symtab_pushnewrapper(lua_State *L, const upb_symtab *s,
const void *ref_donor);
/* For constructing a new message. narg is the Lua value for the MessageDef
* object. */
void lupb_msg_pushnew(lua_State *L, int narg);
void lupb_def_registertypes(lua_State *L);
/* Builds and returns a handlers object for populating a lupb_msg described by
* the MessageDef at "narg".
*
* TODO(haberman): factor this so it doesn't have to take a lua_State. We
* should be able to generate message handlers for a upb_msgdef that can be used
* across many Lua states, so we can shared JIT code across lua_States. */
const upb_handlers *lupb_msg_newwritehandlers(lua_State *L, int narg,
const void *owner);
int lupb_refcounted_gc(lua_State *L);
/* Registers a type with the given name, methods, and metamethods.
* If "refcount_gc" is true, adds a __gc metamethod that does an unref.
* Refcounted types must be allocated with lupb_refcounted_push[new]wrapper. */
void lupb_register_type(lua_State *L, const char *name, const luaL_Reg *m,
const luaL_Reg *mm, bool refcount_gc);
/* Checks the given upb_status and throws a Lua error if it is not ok. */
void lupb_checkstatus(lua_State *L, upb_status *s);
/** From msg.c. ***************************************************************/
struct lupb_msgclass;
typedef struct lupb_msgclass lupb_msgclass;
upb_arena *lupb_arena_check(lua_State *L, int narg);
int lupb_arena_new(lua_State *L);
int lupb_msg_pushref(lua_State *L, int msgclass, void *msg);
const upb_msglayout *lupb_msgclass_getlayout(lua_State *L, int narg);
const upb_handlers *lupb_msgclass_getmergehandlers(lua_State *L, int narg);
void lupb_msg_registertypes(lua_State *L);
#endif /* UPB_LUA_UPB_H_ */

@ -0,0 +1,892 @@
/* lupb_msgfactory **************************************************************/
/* Userval contains a map of:
* [1] = SymbolTable (to keep GC-reachable)
* const upb_msgdef* -> lupb_msgclass
*/
#define LUPB_MSGFACTORY_SYMTAB 1
typedef struct lupb_msgfactory {
upb_msgfactory *factory;
} lupb_msgfactory;
static int lupb_msgclass_pushnew(lua_State *L, int factory, const upb_msglayout *l);
static lupb_msgfactory *lupb_msgfactory_check(lua_State *L, int narg) {
return luaL_checkudata(L, narg, LUPB_MSGFACTORY);
}
static int lupb_msgfactory_new(lua_State *L) {
const upb_symtab *symtab = lupb_symtab_check(L, 1);
lupb_msgfactory *lmsgfactory =
lupb_newuserdata(L, sizeof(lupb_msgfactory), LUPB_MSGFACTORY);
lmsgfactory->factory = upb_msgfactory_new(symtab);
lupb_uservalseti(L, -1, LUPB_MSGFACTORY_SYMTAB, 1);
return 1;
}
static int lupb_msgfactory_gc(lua_State *L) {
lupb_msgfactory *lfactory = lupb_msgfactory_check(L, 1);
if (lfactory->factory) {
upb_msgfactory_free(lfactory->factory);
lfactory->factory = NULL;
}
return 0;
}
static void lupb_msgfactory_pushmsgclass(lua_State *L, int narg,
const upb_msgdef *md) {
const lupb_msgfactory *lfactory = lupb_msgfactory_check(L, narg);
lua_getuservalue(L, narg);
lua_pushlightuserdata(L, (void*)md);
lua_rawget(L, -2);
if (lua_isnil(L, -1)) {
/* TODO: verify md is in symtab? */
lupb_msgclass_pushnew(L, narg,
upb_msgfactory_getlayout(lfactory->factory, md));
/* Set in userval. */
lua_pushlightuserdata(L, (void*)md);
lua_pushvalue(L, -2);
lua_rawset(L, -4);
}
}
static int lupb_msgfactory_getmsgclass(lua_State *L) {
lupb_msgfactory_pushmsgclass(L, 1, lupb_msgdef_check(L, 2));
return 1;
}
static const struct luaL_Reg lupb_msgfactory_m[] = {
{"get_message_class", lupb_msgfactory_getmsgclass},
{NULL, NULL}
};
static const struct luaL_Reg lupb_msgfactory_mm[] = {
{"__gc", lupb_msgfactory_gc},
{NULL, NULL}
};
/* lupb_msgclass **************************************************************/
#define LUPB_MSGCLASS_FACTORY 1
#define LUPB_MSGCLASS_MSGDEF 2
typedef struct lupb_msgclass {
const upb_msglayout *layout;
const lupb_msgfactory *lfactory;
} lupb_msgclass;
/* Checks that the given object is a lupb_msg with the given lmsgclass. */
static upb_msgval lupb_msg_typecheck(lua_State *L, int narg,
const lupb_msgclass *lmsgclass);
/* Type-checks for assigning to a message field. */
static upb_msgval lupb_array_typecheck(lua_State *L, int narg, int msg,
const upb_fielddef *f);
static upb_msgval lupb_map_typecheck(lua_State *L, int narg, int msg,
const upb_fielddef *f);
static const lupb_msgclass *lupb_msg_getsubmsgclass(lua_State *L, int narg,
const upb_fielddef *f);
static const lupb_msgclass *lupb_msg_msgclassfor(lua_State *L, int narg,
const upb_msgdef *md);
static lupb_msgclass *lupb_msgclass_check(lua_State *L, int narg) {
return luaL_checkudata(L, narg, LUPB_MSGCLASS);
}
static void lupb_msgclass_typecheck(lua_State *L, const lupb_msgclass *expected,
const lupb_msgclass *actual) {
if (expected != actual) {
const upb_msgdef *msgdef = upb_msglayout_msgdef(expected->layout);
/* TODO: better error message. */
luaL_typerror(L, 3, upb_msgdef_fullname(msgdef));
}
}
static const lupb_msgclass *lupb_msgclass_msgclassfor(lua_State *L, int narg,
const upb_msgdef *md) {
lupb_uservalgeti(L, narg, LUPB_MSGCLASS_FACTORY);
lupb_msgfactory_pushmsgclass(L, -1, md);
return lupb_msgclass_check(L, -1);
}
static const lupb_msgclass *lupb_msgclass_getsubmsgclass(lua_State *L, int narg,
const upb_fielddef *f) {
/* If we wanted we could try to optimize this by caching these pointers in our
* msgclass, in an array indexed by field index. We would still need to fall
* back to calling msgclassfor(), unless we wanted to eagerly create
* message classes for all submessages. But for big schemas that might be a
* lot of things to build, and we might end up not using most of them. */
return lupb_msgclass_msgclassfor(L, narg, upb_fielddef_msgsubdef(f));
}
static int lupb_msgclass_pushnew(lua_State *L, int factory, const upb_msglayout *l) {
const lupb_msgfactory *lfactory = lupb_msgfactory_check(L, factory);
lupb_msgclass *lmc = lupb_newuserdata(L, sizeof(*lmc), LUPB_MSGCLASS);
lupb_uservalseti(L, -1, LUPB_MSGCLASS_FACTORY, factory);
lmc->layout = l;
lmc->lfactory = lfactory;
return 1;
}
static int lupb_msgclass_call(lua_State *L) {
lupb_msg_pushnew(L, 1);
return 1;
}
static const struct luaL_Reg lupb_msgclass_mm[] = {
{"__call", lupb_msgclass_call},
{NULL, NULL}
};
/* lupb_string ****************************************************************/
/* A wrapper around a Lua string.
*
* This type is NOT exposed to users. Users deal with plain Lua strings.
*
* This type exists for two reasons:
*
* 1. To provide storage for a upb_string, which is required for interoperating
* with upb_msg. It allows upb to visit string data structures without
* calling into Lua.
* 2. To cache a string's UTF-8 validity. We want to validate that a string is
* valid UTF-8 before allowing it to be assigned to a string field. However
* if a string is assigned from one message to another, or assigned to
* multiple message fields, we don't want to force the UTF-8 check again. We
* cache inside this object if the UTF-8 check has been performed.
*
* TODO(haberman): is this slightly too clever? If we just exposed this object
* directly to Lua we could get rid of the cache. But then the object we expose
* to users wouldn't be a true string, so expressions like this would fail:
*
* if msg.string_field == "abc" then
* -- ...
* end
*
* Instead users would have to say this, which seems like a drag:
*
* if tostring(msg.string_field) == "abc" then
* -- ...
* end
*/
typedef struct {
enum ValidUtf8 {
UTF8_UNCHECKED = 0,
UTF8_VALID = 1,
UTF8_INVALID = 2
} utf8_validity; /* Possibly move this into upb_string at some point. */
/* upb_string follows. */
} lupb_string;
#define LUPB_STRING_INDEX 1 /* The index where we reference the Lua string. */
static upb_string *lupb_string_upbstr(lupb_string *lstring) {
return lupb_structafter(&lstring[1]);
}
static size_t lupb_string_sizeof() {
return lupb_sizewithstruct(sizeof(lupb_string), upb_string_sizeof());
}
/* The cache maps char* (lightuserdata) -> lupb_string userdata. The char* is
* the string data from a Lua string object. In practice Lua string objects
* have a stable char* for the actual string data, so we can safely key by this.
* See: http://lua-users.org/lists/lua-l/2011-06/msg00401.html
*
* The cache's values are weak, so cache entries can be collected if this string
* is no longer a member of any message, array, or map. Keeping real Lua
* strings as weak keys is not possible, because Lua does make strings subject
* to weak collection, so this would prevent these strings from ever being
* collected. */
static void lupb_string_pushcache(lua_State *L) {
static char key;
lua_pushlightuserdata(L, &key);
lua_rawget(L, LUA_REGISTRYINDEX);
/* Lazily create. */
if (lua_isnil(L, -1)) {
lua_pop(L, 1); /* nil. */
lua_newtable(L);
lua_createtable(L, 0, 1); /* Cache metatable. */
lua_pushstring(L, "v"); /* Values are weak. */
lua_setfield(L, -2, "__mode");
lua_setmetatable(L, -2);
lua_pushlightuserdata(L, &key);
lua_pushvalue(L, -2); /* Cache. */
lua_rawset(L, LUA_REGISTRYINDEX);
}
}
static lupb_string *lupb_string_pushwrapper(lua_State *L, int narg) {
const char *str;
size_t len;
lupb_string *lstring;
lupb_checkstring(L, narg);
str = lua_tolstring(L, narg, &len);
lupb_string_pushcache(L);
lua_pushlightuserdata(L, (void*)str);
lua_rawget(L, -2);
if (lua_isnil(L, -1)) {
/* String wasn't in cache, need to create it. */
lua_pop(L, 1); /* nil. */
lstring = lupb_newuserdata(L, lupb_string_sizeof(), LUPB_STRING);
lstring->utf8_validity = UTF8_UNCHECKED;
upb_string_set(lupb_string_upbstr(lstring), str, len);
lua_pushlightuserdata(L, (void*)str);
lua_pushvalue(L, -2);
/* Stack is [cache, lupb_string, str, lupb_string]. */
lua_rawset(L, -4);
/* Need to create a reference to the underlying string object, so
* lupb_string keeps it alive. */
lupb_uservalseti(L, -1, LUPB_STRING_INDEX, narg);
} else {
lstring = lua_touserdata(L, -1);
}
lua_remove(L, -2); /* cache. */
return lstring;
}
/* The value at narg should be a Lua string object. This will push a wrapper
* object (which may be from the cache). Returns a upb_string* that is valid
* for as long as the pushed object is alive.
*
* This object should only be used internally, and not exposed to users! */
static upb_msgval lupb_string_pushbyteswrapper(lua_State *L, int narg) {
lupb_string *lstring = lupb_string_pushwrapper(L, narg);
return upb_msgval_str(lupb_string_upbstr(lstring));
}
/* Like lupb_string_pushbyteswrapper(), except it also validates that the string
* is valid UTF-8 (if we haven't already) and throws an error if not. */
static upb_msgval lupb_string_pushstringwrapper(lua_State *L, int narg) {
lupb_string *lstring = lupb_string_pushwrapper(L, narg);
if (lstring->utf8_validity == UTF8_UNCHECKED) {
if (true /* TODO: check UTF-8 */) {
lstring->utf8_validity = UTF8_VALID;
} else {
lstring->utf8_validity = UTF8_INVALID;
}
}
if (lstring->utf8_validity != UTF8_VALID) {
luaL_error(L, "String is not valid UTF-8");
}
return upb_msgval_str(lupb_string_upbstr(lstring));
}
/* Given a previously pushed wrapper object, unwraps it and pushes the plain
* string object underneath. This is the only object we should expose to users.
*/
static void lupb_string_unwrap(lua_State *L, int arg) {
lupb_uservalgeti(L, arg, LUPB_STRING_INDEX);
}
/* upb <-> Lua type conversion ************************************************/
static bool lupb_isstring(upb_fieldtype_t type) {
return type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES;
}
static bool lupb_istypewrapped(upb_fieldtype_t type) {
return type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES ||
type == UPB_TYPE_MESSAGE;
}
static upb_msgval lupb_tomsgval(lua_State *L, upb_fieldtype_t type, int narg,
const lupb_msgclass *lmsgclass,
bool *pushed_luaobj) {
switch (type) {
case UPB_TYPE_INT32:
case UPB_TYPE_ENUM:
return upb_msgval_int32(lupb_checkint32(L, narg));
case UPB_TYPE_INT64:
return upb_msgval_int64(lupb_checkint64(L, narg));
case UPB_TYPE_UINT32:
return upb_msgval_uint32(lupb_checkuint32(L, narg));
case UPB_TYPE_UINT64:
return upb_msgval_uint64(lupb_checkuint64(L, narg));
case UPB_TYPE_DOUBLE:
return upb_msgval_double(lupb_checkdouble(L, narg));
case UPB_TYPE_FLOAT:
return upb_msgval_float(lupb_checkfloat(L, narg));
case UPB_TYPE_BOOL:
return upb_msgval_bool(lupb_checkbool(L, narg));
case UPB_TYPE_STRING:
/* For map lookup by key, we might want a lighter-weight way of creating a
* temporary string. */
*pushed_luaobj = true;
return lupb_string_pushstringwrapper(L, narg);
case UPB_TYPE_BYTES:
*pushed_luaobj = true;
return lupb_string_pushbyteswrapper(L, narg);
case UPB_TYPE_MESSAGE:
UPB_ASSERT(lmsgclass);
*pushed_luaobj = true;
lua_pushvalue(L, narg);
return lupb_msg_typecheck(L, narg, lmsgclass);
}
}
static void lupb_pushmsgval(lua_State *L, upb_fieldtype_t type,
upb_msgval val) {
switch (type) {
case UPB_TYPE_INT32:
case UPB_TYPE_ENUM:
lupb_pushint32(L, upb_msgval_getint32(val));
break;
case UPB_TYPE_INT64:
lupb_pushint64(L, upb_msgval_getint64(val));
break;
case UPB_TYPE_UINT32:
lupb_pushuint32(L, upb_msgval_getuint32(val));
break;
case UPB_TYPE_UINT64:
lupb_pushuint64(L, upb_msgval_getuint64(val));
break;
case UPB_TYPE_DOUBLE:
lupb_pushdouble(L, upb_msgval_getdouble(val));
break;
case UPB_TYPE_FLOAT:
lupb_pushfloat(L, upb_msgval_getdouble(val));
break;
case UPB_TYPE_BOOL:
lupb_pushbool(L, upb_msgval_getbool(val));
break;
case UPB_TYPE_STRING:
case UPB_TYPE_BYTES:
case UPB_TYPE_MESSAGE:
lupb_assert(L, false);
}
}
/* lupb_array *****************************************************************/
/* A strongly typed array. Implemented by wrapping upb_array.
*
* - we only allow integer indices.
* - all entries must have the correct type.
* - we do not allow "holes" in the array; you can only assign to an existing
* index or one past the end (which will grow the array by one).
*/
typedef struct {
/* Only needed for array of message. This wastes space in the non-message
* case but simplifies the code. Could optimize away if desired. */
lupb_msgclass *lmsgclass;
/* upb_array follows. */
} lupb_array;
static size_t lupb_array_sizeof(upb_fieldtype_t type) {
return lupb_sizewithstruct(sizeof(lupb_array), upb_array_sizeof(type));
}
static upb_array *lupb_array_upbarr(lupb_array *arr) {
return lupb_structafter(&arr[1]);
}
static lupb_array *lupb_array_check(lua_State *L, int narg) {
return luaL_checkudata(L, narg, LUPB_ARRAY);
}
static upb_array *lupb_array_check2(lua_State *L, int narg) {
return lupb_array_upbarr(lupb_array_check(L, narg));
}
static upb_msgval lupb_array_typecheck(lua_State *L, int narg, int msg,
const upb_fielddef *f) {
lupb_array *larray = lupb_array_check(L, narg);
upb_array *array = lupb_array_upbarr(larray);
if (upb_array_type(array) != upb_fielddef_type(f) ||
lupb_msg_getsubmsgclass(L, msg, f) != larray->lmsgclass) {
luaL_error(L, "Array had incorrect type (expected: %s, got: %s)",
upb_fielddef_type(f), upb_array_type(array));
}
if (upb_array_type(array) == UPB_TYPE_MESSAGE) {
lupb_msgclass_typecheck(L, lupb_msg_getsubmsgclass(L, msg, f),
larray->lmsgclass);
}
return upb_msgval_arr(array);
}
/* We use "int" because of lua_rawseti/lua_rawgeti -- can re-evaluate if we want
* arrays bigger than 2^31. */
static int lupb_array_checkindex(lua_State *L, int narg, uint32_t max) {
uint32_t n = lupb_checkuint32(L, narg);
if (n == 0 || n > max || n > INT_MAX) { /* Lua uses 1-based indexing. :( */
luaL_error(L, "Invalid array index.");
}
return n;
}
static int lupb_array_new(lua_State *L) {
lupb_array *larray;
upb_fieldtype_t type;
lupb_msgclass *lmsgclass = NULL;
if (lua_type(L, 1) == LUA_TNUMBER) {
type = lupb_checkfieldtype(L, 1);
} else {
type = UPB_TYPE_MESSAGE;
lmsgclass = lupb_msgclass_check(L, 1);
lupb_uservalseti(L, -1, MSGCLASS_INDEX, 1); /* GC-root lmsgclass. */
}
larray = lupb_newuserdata(L, lupb_array_sizeof(type), LUPB_ARRAY);
larray->lmsgclass = lmsgclass;
upb_array_init(lupb_array_upbarr(larray), type);
return 1;
}
static int lupb_array_gc(lua_State *L) {
upb_array *array = lupb_array_check2(L, 1);
WITH_ALLOC(upb_array_uninit(array, alloc));
return 0;
}
static int lupb_array_newindex(lua_State *L) {
lupb_array *larray = lupb_array_check(L, 1);
upb_array *array = lupb_array_upbarr(larray);
upb_fieldtype_t type = upb_array_type(array);
bool hasuserval = false;
uint32_t n = lupb_array_checkindex(L, 2, upb_array_size(array) + 1);
upb_msgval msgval = lupb_tomsgval(L, type, 3, larray->lmsgclass, &hasuserval);
WITH_ALLOC(upb_array_set(array, n, msgval, alloc));
if (hasuserval) {
lupb_uservalseti(L, 1, n, -1);
}
return 0; /* 1 for chained assignments? */
}
static int lupb_array_index(lua_State *L) {
lupb_array *larray = lupb_array_check(L, 1);
upb_array *array = lupb_array_upbarr(larray);
uint32_t n = lupb_array_checkindex(L, 2, upb_array_size(array));
upb_fieldtype_t type = upb_array_type(array);
if (lupb_istypewrapped(type)) {
lupb_uservalgeti(L, 1, n);
if (lupb_isstring(type)) {
lupb_string_unwrap(L, -1);
}
} else {
lupb_pushmsgval(L, upb_array_type(array), upb_array_get(array, n));
}
return 1;
}
static int lupb_array_len(lua_State *L) {
upb_array *array = lupb_array_check2(L, 1);
lua_pushnumber(L, upb_array_size(array));
return 1;
}
static const struct luaL_Reg lupb_array_mm[] = {
{"__gc", lupb_array_gc},
{"__index", lupb_array_index},
{"__len", lupb_array_len},
{"__newindex", lupb_array_newindex},
{NULL, NULL}
};
/* lupb_map *******************************************************************/
/* A map object. Implemented by wrapping upb_map.
*
* When the value type is string/bytes/message, the userval consists of:
*
* [Lua number/string] -> [lupb_string/lupb_msg userdata]
*
* We always keep this synced to the underlying upb_map. For other value types
* we don't use the userdata, and we just read/write the underlying upb_map.
*
*
*/
typedef struct {
const lupb_msgclass *value_lmsgclass;
/* upb_map follows */
} lupb_map;
/* lupb_map internal functions */
static size_t lupb_map_sizeof(upb_fieldtype_t ktype, upb_fieldtype_t vtype) {
return lupb_sizewithstruct(sizeof(lupb_map), upb_map_sizeof(ktype, vtype));
}
static upb_map *lupb_map_upbmap(lupb_map *lmap) {
return lupb_structafter(&lmap[1]);
}
static lupb_map *lupb_map_check(lua_State *L, int narg) {
return luaL_checkudata(L, narg, LUPB_ARRAY);
}
static upb_map *lupb_map_check2(lua_State *L, int narg) {
return lupb_map_upbmap(lupb_map_check(L, narg));
}
static upb_msgval lupb_map_typecheck(lua_State *L, int narg, int msg,
const upb_fielddef *f) {
lupb_map *lmap = lupb_map_check(L, narg);
upb_map *map = lupb_map_upbmap(lmap);
const upb_msgdef *entry = upb_fielddef_msgsubdef(f);
const upb_fielddef *key_field = upb_msgdef_itof(entry, UPB_MAPENTRY_KEY);
const upb_fielddef *value_field = upb_msgdef_itof(entry, UPB_MAPENTRY_VALUE);
UPB_ASSERT(entry && key_field && value_field);
if (upb_map_keytype(map) != upb_fielddef_type(key_field)) {
luaL_error(L, "Map key type invalid");
}
if (upb_map_valuetype(map) != upb_fielddef_type(value_field)) {
luaL_error(L, "Map had incorrect value type (expected: %s, got: %s)",
upb_fielddef_type(value_field), upb_map_valuetype(map));
}
if (upb_map_valuetype(map) == UPB_TYPE_MESSAGE) {
lupb_msgclass_typecheck(
L, lupb_msg_msgclassfor(L, msg, upb_fielddef_msgsubdef(value_field)),
lmap->value_lmsgclass);
}
return upb_msgval_map(map);
}
static void lupb_map_lazy
static int lupb_map_gc(lua_State *L) {
upb_map *map = lupb_map_check2(L, 1);
WITH_ALLOC(upb_map_uninit(map, alloc));
return 0;
}
/* lupb_map Public API */
static int lupb_map_new(lua_State *L) {
lupb_map *lmap;
upb_map *map;
upb_fieldtype_t key_type = lupb_checkfieldtype(L, 1);
upb_fieldtype_t value_type;
lupb_msgclass *value_lmsgclass = NULL;
if (lua_type(L, 2) == LUA_TNUMBER) {
value_type = lupb_checkfieldtype(L, 2);
} else {
value_type = UPB_TYPE_MESSAGE;
}
lmap = lupb_newuserdata(L, lupb_map_sizeof(key_type, value_type), LUPB_MAP);
map = lupb_map_upbmap(lmap);
if (value_type == UPB_TYPE_MESSAGE) {
value_lmsgclass = lupb_msgclass_check(L, 2);
lupb_uservalseti(L, -1, MSGCLASS_INDEX, 2); /* GC-root lmsgclass. */
}
lmap->value_lmsgclass = value_lmsgclass;
WITH_ALLOC(upb_map_init(map, key_type, value_type, alloc));
return 1;
}
static int lupb_map_index(lua_State *L) {
lupb_map *lmap = lupb_map_check(L, 1);
upb_map *map = lupb_map_upbmap(lmap);
upb_fieldtype_t valtype = upb_map_valuetype(map);
bool pushedobj;
/* We don't always use "key", but this call checks the key type. */
upb_msgval key = lupb_map_tokeymsgval(L, upb_map_keytype(map), 2);
if (lupb_istypewrapped(valtype)) {
/* Userval contains the full map, lookup there by key. */
lupb_getuservalue(L, 1);
lua_pushvalue(L, 2);
lua_rawget(L, -2);
} else {
/* Lookup in upb_map. */
upb_msgval val;
if (upb_map_get(map, key, &val)) {
lupb_map_pushmsgval(L, upb_map_valuetype(map), val);
} else {
lua_pushnil(L);
}
}
return 1;
}
static int lupb_map_len(lua_State *L) {
upb_map *map = lupb_map_check2(L, 1);
lua_pushnumber(L, upb_map_size(map));
return 1;
}
static int lupb_map_newindex(lua_State *L) {
lupb_map *lmap = lupb_map_check(L, 1);
upb_map *map = lupb_map_upbmap(lmap);
bool keyobj = false;
upb_msgval key = lupb_tomsgval(L, upb_map_keytype(map), 2, NULL, &keyobj);
if (lua_isnil(L, 3)) {
/* Delete from map. */
WITH_ALLOC(upb_map_del(map, key, alloc));
if (lupb_istypewrapped(upb_map_valuetype(map))) {
/* Delete in userval. */
lupb_getuservalue(L, 1);
lua_pushvalue(L, 2);
lua_pushnil(L);
lua_rawset(L, -3);
lua_pop(L, 1);
}
} else {
/* Set in map. */
bool valobj = false;
upb_msgval val = lupb_tomsgval(L, upb_map_valuetype(map), 3,
lmap->value_lmsgclass, &valobj);
WITH_ALLOC(upb_map_set(map, key, val, NULL, alloc));
if (valobj) {
/* Set in userval. */
lupb_getuservalue(L, 1);
lua_pushvalue(L, 2);
lua_pushvalue(L, -3);
lua_rawset(L, -3);
lua_pop(L, 1);
}
}
return 0;
}
/* upb_mapiter [[[ */
static int lupb_mapiter_next(lua_State *L) {
upb_mapiter *i = lua_touserdata(L, lua_upvalueindex(1));
lupb_map *lmap = lupb_map_check(L, 1);
upb_map *map = lupb_map_upbmap(lmap);
upb_string *str = malloc(upb_string_sizeof());
if (upb_mapiter_done(i)) {
return 0;
}
lupb_map_pushmsgval(L, upb_map_keytype(map), upb_mapiter_key(i));
lupb_map_pushmsgval(L, upb_map_valuetype(map), upb_mapiter_value(i));
upb_mapiter_next(i);
free(str);
return 2;
}
static int lupb_map_pairs(lua_State *L) {
lupb_map *lmap = lupb_map_check(L, 1);
upb_map *map = lupb_map_upbmap(lmap);
upb_mapiter *i = lua_newuserdata(L, upb_mapiter_sizeof());
upb_mapiter_begin(i, map);
lua_pushvalue(L, 1);
/* Upvalues are [upb_mapiter, lupb_map]. */
lua_pushcclosure(L, &lupb_mapiter_next, 2);
return 1;
}
/* upb_mapiter ]]] */
static const struct luaL_Reg lupb_map_mm[] = {
{"__gc", lupb_map_gc},
{"__index", lupb_map_index},
{"__len", lupb_map_len},
{"__newindex", lupb_map_newindex},
{"__pairs", lupb_map_pairs},
{NULL, NULL}
};
/* lupb_msg *******************************************************************/
/* A message object. Implemented by wrapping upb_msg.
*
* Our userval contains:
*
* - [0] = our message class
* - [upb_fielddef_index(f)] = any submessage/string/map/repeated obj.
*/
#define LUPB_MSG_MSGCLASSINDEX 0
typedef struct {
const lupb_msgclass *lmsgclass;
/* Data follows, in a flat buffer. */
} lupb_msg;
/* lupb_msg helpers */
static bool in_userval(const upb_fielddef *f) {
return upb_fielddef_isseq(f) || upb_fielddef_issubmsg(f) ||
upb_fielddef_isstring(f) || upb_fielddef_ismap(f);
}
lupb_msg *lupb_msg_check(lua_State *L, int narg) {
lupb_msg *msg = luaL_checkudata(L, narg, LUPB_MSG);
if (!msg->lmsgclass) luaL_error(L, "called into dead msg");
return msg;
}
void *lupb_msg_upbmsg(lupb_msg *lmsg) {
return lupb_structafter(&lmsg[1]);
}
static upb_msgval lupb_msg_typecheck(lua_State *L, int narg,
const lupb_msgclass *lmsgclass) {
lupb_msg *msg = lupb_msg_check(L, narg);
lupb_msgclass_typecheck(L, msg->lmsgclass, lmsgclass);
return upb_msgval_msg(msg);
}
const upb_msgdef *lupb_msg_checkdef(lua_State *L, int narg) {
return upb_msglayout_msgdef(lupb_msg_check(L, narg)->lmsgclass->layout);
}
static const upb_fielddef *lupb_msg_checkfield(lua_State *L,
const lupb_msg *msg,
int fieldarg) {
size_t len;
const char *fieldname = luaL_checklstring(L, fieldarg, &len);
const upb_msgdef *msgdef = upb_msglayout_msgdef(msg->lmsgclass->layout);
const upb_fielddef *f = upb_msgdef_ntof(msgdef, fieldname, len);
if (!f) {
const char *msg = lua_pushfstring(L, "no such field: %s", fieldname);
luaL_argerror(L, fieldarg, msg);
return NULL; /* Never reached. */
}
return f;
}
static int lupb_msg_pushnew(lua_State *L, int narg) {
lupb_msgclass *lmsgclass = lupb_msgclass_check(L, narg);
size_t size = upb_msg_sizeof(lmsgclass->layout);
lupb_msg *msg = lupb_newuserdata(L, size, LUPB_MSG);
msg->lmsgclass = lmsgclass;
lupb_uservalseti(L, -1, LUPB_MSG_MSGCLASSINDEX, narg);
return 1;
}
static const lupb_msgclass *lupb_msg_msgclassfor(lua_State *L, int narg,
const upb_msgdef *md) {
lupb_uservalgeti(L, narg, LUPB_MSG_MSGCLASSINDEX);
return lupb_msgclass_msgclassfor(L, -1, md);
}
static const lupb_msgclass *lupb_msg_getsubmsgclass(lua_State *L, int narg,
const upb_fielddef *f) {
lupb_uservalgeti(L, narg, LUPB_MSG_MSGCLASSINDEX);
return lupb_msgclass_getsubmsgclass(L, -1, f);
}
/* lupb_msg Public API */
static int lupb_msg_index(lua_State *L) {
lupb_msg *msg = lupb_msg_check(L, 1);
const upb_fielddef *f = lupb_msg_checkfield(L, msg, 2);
if (in_userval(f)) {
lupb_uservalgeti(L, 1, upb_fielddef_index(f));
if (upb_fielddef_isseq(f) && lua_isnil(L, -1)) {
/* TODO(haberman): default-construct empty array. */
}
} else {
lupb_pushmsgval(L, upb_fielddef_type(f),
upb_msg_get(msg, f, msg->lmsgclass->layout));
}
return 1;
}
static int lupb_msg_newindex(lua_State *L) {
lupb_msg *lmsg = lupb_msg_check(L, 1);
const upb_fielddef *f = lupb_msg_checkfield(L, lmsg, 2);
bool luaobj = false;
upb_msgval msgval;
/* Typecheck and get msgval. */
if (upb_fielddef_isseq(f)) {
msgval = lupb_array_typecheck(L, 3, 1, f);
luaobj = true;
} else if (upb_fielddef_ismap(f)) {
msgval = lupb_map_typecheck(L, 3, 1, f);
luaobj = true;
} else {
const lupb_msgclass *lmsgclass = NULL;
upb_fieldtype_t type = upb_fielddef_type(f);
if (type == UPB_TYPE_MESSAGE) {
lmsgclass = lupb_msg_getsubmsgclass(L, 1, f);
}
msgval = lupb_tomsgval(L, upb_fielddef_type(f), 3, lmsgclass, &luaobj);
}
/* Set in upb_msg and userval (if necessary). */
WITH_ALLOC(upb_msg_set(lmsg, f, msgval, lmsg->lmsgclass->layout, alloc));
if (luaobj) {
lupb_uservalseti(L, 1, upb_fielddef_index(f), -1);
}
return 0; /* 1 for chained assignments? */
}
static const struct luaL_Reg lupb_msg_mm[] = {
{"__index", lupb_msg_index},
{"__newindex", lupb_msg_newindex},
{NULL, NULL}
};

@ -10,59 +10,24 @@
#define LUPB_PBDECODERMETHOD "lupb.pb.decodermethod"
#define MSGDEF_INDEX 1
static upb_pbdecodermethod *lupb_pbdecodermethod_check(lua_State *L, int narg) {
return lupb_refcounted_check(L, narg, LUPB_PBDECODERMETHOD);
}
static int lupb_pbdecodermethod_new(lua_State *L) {
const upb_handlers *handlers = lupb_msg_newwritehandlers(L, 1, &handlers);
const upb_pbdecodermethod *m;
upb_pbdecodermethodopts opts;
upb_pbdecodermethodopts_init(&opts, handlers);
m = upb_pbdecodermethod_new(&opts, &m);
upb_handlers_unref(handlers, &handlers);
lupb_refcounted_pushnewrapper(
L, upb_pbdecodermethod_upcast(m), LUPB_PBDECODERMETHOD, &m);
/* We need to keep a pointer to the MessageDef (in Lua space) so we can
* construct new messages in parse(). */
lua_newtable(L);
lua_pushvalue(L, 1);
lua_rawseti(L, -2, MSGDEF_INDEX);
lua_setuservalue(L, -2);
return 1; /* The DecoderMethod wrapper. */
}
/* Unlike most of our exposed Lua functions, this does not correspond to an
* actual method on the underlying DecoderMethod. But it's convenient, and
* important to implement in C because we can do stack allocation and
* initialization of our runtime structures like the Decoder and Sink. */
static int lupb_pbdecodermethod_parse(lua_State *L) {
static int lupb_pb_strtomessage(lua_State *L) {
size_t len;
const upb_pbdecodermethod *method = lupb_pbdecodermethod_check(L, 1);
const char *pb = lua_tolstring(L, 2, &len);
void *msg;
upb_status status = UPB_STATUS_INIT;
const char *pb = lua_tolstring(L, 1, &len);
const upb_msglayout *layout = lua_touserdata(L, lua_upvalueindex(1));
const upb_pbdecodermethod *method = lua_touserdata(L, lua_upvalueindex(2));
const upb_handlers *handlers = upb_pbdecodermethod_desthandlers(method);
upb_arena *msg_arena;
upb_env env;
upb_sink sink;
upb_pbdecoder *decoder;
void *msg;
const upb_handlers *handlers = upb_pbdecodermethod_desthandlers(method);
lua_getuservalue(L, 1);
lua_rawgeti(L, -1, MSGDEF_INDEX);
lupb_assert(L, !lua_isnil(L, -1));
lupb_msg_pushnew(L, -1); /* Push new message. */
msg = lua_touserdata(L, -1);
/* Handlers need this. */
lua_getuservalue(L, -1);
lupb_arena_new(L);
msg_arena = lupb_arena_check(L, -1);
msg = upb_msg_new(layout, upb_arena_alloc(msg_arena));
upb_env_init(&env);
upb_env_reporterrorsto(&env, &status);
upb_sink_reset(&sink, handlers, msg);
@ -76,18 +41,42 @@ static int lupb_pbdecodermethod_parse(lua_State *L) {
lupb_checkstatus(L, &status);
lua_pop(L, 1); /* Uservalue. */
/* References the arena at the top of the stack. */
lupb_msg_pushref(L, lua_upvalueindex(3), msg);
return 1;
}
static const struct luaL_Reg lupb_pbdecodermethod_m[] = {
{"parse", lupb_pbdecodermethod_parse},
static int lupb_pb_makestrtomsgdecoder(lua_State *L) {
const upb_msglayout *layout = lupb_msgclass_getlayout(L, 1);
const upb_handlers *handlers = lupb_msgclass_getmergehandlers(L, 1);
const upb_pbdecodermethod *m;
upb_pbdecodermethodopts opts;
upb_pbdecodermethodopts_init(&opts, handlers);
m = upb_pbdecodermethod_new(&opts, &m);
/* Push upvalues for the closure. */
lua_pushlightuserdata(L, (void*)layout);
lua_pushlightuserdata(L, (void*)m);
lua_pushvalue(L, 1);
/* Upvalue for the closure, only to keep the decodermethod alive. */
lupb_refcounted_pushnewrapper(
L, upb_pbdecodermethod_upcast(m), LUPB_PBDECODERMETHOD, &m);
lua_pushcclosure(L, &lupb_pb_strtomessage, 4);
return 1; /* The decoder closure. */
}
static const struct luaL_Reg decodermethod_mm[] = {
{"__gc", lupb_refcounted_gc},
{NULL, NULL}
};
static const struct luaL_Reg toplevel_m[] = {
{"DecoderMethod", lupb_pbdecodermethod_new},
{"MakeStringToMessageDecoder", lupb_pb_makestrtomsgdecoder},
{NULL, NULL}
};
@ -97,8 +86,7 @@ int luaopen_upb_pb_c(lua_State *L) {
return 1;
}
lupb_register_type(L, LUPB_PBDECODERMETHOD, lupb_pbdecodermethod_m, NULL,
true);
lupb_register_type(L, LUPB_PBDECODERMETHOD, NULL, decodermethod_mm);
return 1;
}

@ -133,7 +133,8 @@ upb_def *upb_def_dup(const upb_def *def, const void *o) {
case UPB_DEF_ENUM:
return upb_enumdef_upcast_mutable(
upb_enumdef_dup(upb_downcast_enumdef(def), o));
default: UPB_ASSERT(false); return NULL;
default:
UPB_UNREACHABLE();
}
}
@ -283,6 +284,7 @@ static bool assign_msg_indices(upb_msgdef *m, upb_status *s) {
/* Sort fields. upb internally relies on UPB_TYPE_MESSAGE fields having the
* lowest indexes, but we do not publicly guarantee this. */
upb_msg_field_iter j;
upb_msg_oneof_iter k;
int i;
uint32_t selector;
int n = upb_msgdef_numfields(m);
@ -367,6 +369,13 @@ static bool assign_msg_indices(upb_msgdef *m, upb_status *s) {
#undef TRY
#endif
for(upb_msg_oneof_begin(&k, m), i = 0;
!upb_msg_oneof_done(&k);
upb_msg_oneof_next(&k), i++) {
upb_oneofdef *o = upb_msg_iter_oneof(&k);
o->index = i;
}
upb_gfree(fields);
return true;
}
@ -1833,6 +1842,10 @@ int upb_oneofdef_numfields(const upb_oneofdef *o) {
return upb_strtable_count(&o->ntof);
}
uint32_t upb_oneofdef_index(const upb_oneofdef *o) {
return o->index;
}
bool upb_oneofdef_addfield(upb_oneofdef *o, upb_fielddef *f,
const void *ref_donor,
upb_status *s) {

@ -222,15 +222,19 @@ UPB_DECLARE_DEF_TYPE(upb::EnumDef, enumdef, ENUM)
* types defined in descriptor.proto, which gives INT32 and SINT32 separate
* types (we distinguish the two with the "integer encoding" enum below). */
typedef enum {
UPB_TYPE_FLOAT = 1,
UPB_TYPE_DOUBLE = 2,
UPB_TYPE_BOOL = 3,
UPB_TYPE_STRING = 4,
UPB_TYPE_BYTES = 5,
UPB_TYPE_MESSAGE = 6,
UPB_TYPE_ENUM = 7, /* Enum values are int32. */
UPB_TYPE_INT32 = 8,
UPB_TYPE_UINT32 = 9,
/* Types stored in 1 byte. */
UPB_TYPE_BOOL = 1,
/* Types stored in 4 bytes. */
UPB_TYPE_FLOAT = 2,
UPB_TYPE_INT32 = 3,
UPB_TYPE_UINT32 = 4,
UPB_TYPE_ENUM = 5, /* Enum values are int32. */
/* Types stored as pointers (probably 4 or 8 bytes). */
UPB_TYPE_STRING = 6,
UPB_TYPE_BYTES = 7,
UPB_TYPE_MESSAGE = 8,
/* Types stored as 8 bytes. */
UPB_TYPE_DOUBLE = 9,
UPB_TYPE_INT64 = 10,
UPB_TYPE_UINT64 = 11
} upb_fieldtype_t;
@ -404,16 +408,10 @@ class upb::FieldDef {
bool IsPrimitive() const;
bool IsMap() const;
/* Whether this field must be able to explicitly represent presence:
/* Returns whether this field explicitly represents presence.
*
* * This is always false for repeated fields (an empty repeated field is
* equivalent to a repeated field with zero entries).
*
* * This is always true for submessages.
*
* * For other fields, it depends on the message (see
* MessageDef::SetPrimitivesHavePresence())
*/
* For proto2 messages: Returns true for any scalar (non-repeated) field.
* For proto3 messages: Returns true for scalar submessage or oneof fields. */
bool HasPresence() const;
/* How integers are encoded. Only meaningful for integer types.
@ -1151,6 +1149,7 @@ int32_t upb_enum_iter_number(upb_enum_iter *iter);
UPB_END_EXTERN_C
/* upb::OneofDef **************************************************************/
typedef upb_inttable_iter upb_oneof_iter;
@ -1270,10 +1269,11 @@ upb_oneofdef *upb_oneofdef_dup(const upb_oneofdef *o, const void *owner);
UPB_REFCOUNTED_CMETHODS(upb_oneofdef, upb_oneofdef_upcast)
const char *upb_oneofdef_name(const upb_oneofdef *o);
bool upb_oneofdef_setname(upb_oneofdef *o, const char *name, upb_status *s);
const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o);
int upb_oneofdef_numfields(const upb_oneofdef *o);
uint32_t upb_oneofdef_index(const upb_oneofdef *o);
bool upb_oneofdef_setname(upb_oneofdef *o, const char *name, upb_status *s);
bool upb_oneofdef_addfield(upb_oneofdef *o, upb_fielddef *f,
const void *ref_donor,
upb_status *s);

Binary file not shown.

@ -63,7 +63,7 @@ struct upb_descreader {
upb_fielddef *f;
};
static char *upb_strndup(const char *buf, size_t n) {
static char *upb_gstrndup(const char *buf, size_t n) {
char *ret = upb_gmalloc(n + 1);
if (!ret) return NULL;
memcpy(ret, buf, n);
@ -213,7 +213,7 @@ static size_t file_onname(void *closure, const void *hd, const char *buf,
UPB_UNUSED(hd);
UPB_UNUSED(handle);
name = upb_strndup(buf, n);
name = upb_gstrndup(buf, n);
/* XXX: see comment at the top of the file. */
ok = upb_filedef_setname(r->file, name, NULL);
upb_gfree(name);
@ -229,7 +229,7 @@ static size_t file_onpackage(void *closure, const void *hd, const char *buf,
UPB_UNUSED(hd);
UPB_UNUSED(handle);
package = upb_strndup(buf, n);
package = upb_gstrndup(buf, n);
/* XXX: see comment at the top of the file. */
upb_descreader_setscopename(r, package);
ok = upb_filedef_setpackage(r->file, package, NULL);
@ -301,7 +301,7 @@ static size_t enumval_onname(void *closure, const void *hd, const char *buf,
UPB_UNUSED(handle);
/* XXX: see comment at the top of the file. */
upb_gfree(r->name);
r->name = upb_strndup(buf, n);
r->name = upb_gstrndup(buf, n);
r->saw_name = true;
return n;
}
@ -352,7 +352,7 @@ static bool enum_endmsg(void *closure, const void *hd, upb_status *status) {
static size_t enum_onname(void *closure, const void *hd, const char *buf,
size_t n, const upb_bufhandle *handle) {
upb_descreader *r = closure;
char *fullname = upb_strndup(buf, n);
char *fullname = upb_gstrndup(buf, n);
UPB_UNUSED(hd);
UPB_UNUSED(handle);
/* XXX: see comment at the top of the file. */
@ -520,7 +520,7 @@ static bool field_onnumber(void *closure, const void *hd, int32_t val) {
static size_t field_onname(void *closure, const void *hd, const char *buf,
size_t n, const upb_bufhandle *handle) {
upb_descreader *r = closure;
char *name = upb_strndup(buf, n);
char *name = upb_gstrndup(buf, n);
UPB_UNUSED(hd);
UPB_UNUSED(handle);
@ -533,7 +533,7 @@ static size_t field_onname(void *closure, const void *hd, const char *buf,
static size_t field_ontypename(void *closure, const void *hd, const char *buf,
size_t n, const upb_bufhandle *handle) {
upb_descreader *r = closure;
char *name = upb_strndup(buf, n);
char *name = upb_gstrndup(buf, n);
UPB_UNUSED(hd);
UPB_UNUSED(handle);
@ -546,7 +546,7 @@ static size_t field_ontypename(void *closure, const void *hd, const char *buf,
static size_t field_onextendee(void *closure, const void *hd, const char *buf,
size_t n, const upb_bufhandle *handle) {
upb_descreader *r = closure;
char *name = upb_strndup(buf, n);
char *name = upb_gstrndup(buf, n);
UPB_UNUSED(hd);
UPB_UNUSED(handle);
@ -566,7 +566,7 @@ static size_t field_ondefaultval(void *closure, const void *hd, const char *buf,
* type yet, so we save it as a string until the end of the field.
* XXX: see comment at the top of the file. */
upb_gfree(r->default_string);
r->default_string = upb_strndup(buf, n);
r->default_string = upb_gstrndup(buf, n);
return n;
}
@ -587,7 +587,7 @@ static size_t oneof_name(void *closure, const void *hd, const char *buf,
upb_descreader *r = closure;
upb_descreader_frame *f = &r->stack[r->stack_len-1];
upb_oneofdef *o = upb_descreader_getoneof(r, f->oneof_index++);
char *name_null_terminated = upb_strndup(buf, n);
char *name_null_terminated = upb_gstrndup(buf, n);
bool ok = upb_oneofdef_setname(o, name_null_terminated, NULL);
UPB_UNUSED(hd);
UPB_UNUSED(handle);
@ -624,7 +624,7 @@ static size_t msg_name(void *closure, const void *hd, const char *buf,
upb_descreader *r = closure;
upb_msgdef *m = upb_descreader_top(r);
/* XXX: see comment at the top of the file. */
char *name = upb_strndup(buf, n);
char *name = upb_gstrndup(buf, n);
UPB_UNUSED(hd);
UPB_UNUSED(handle);

@ -19,7 +19,6 @@
** - handling of keys/escape-sequences/etc that span input buffers.
*/
#include <assert.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,340 @@
/*
** upb::Message is a representation for protobuf messages.
**
** However it differs from other common representations like
** google::protobuf::Message in one key way: it does not prescribe any
** ownership semantics, and it does not perform any memory management.
**
** A client can access a upb::Message without knowing anything about
** ownership semantics, but to create or mutate a message a user needs
** to implement the memory management themselves.
**
** Currently all messages, arrays, and maps store a upb_alloc* internally.
** Mutating operations use this when they require dynamically-allocated
** memory. We could potentially eliminate this size overhead later by
** letting the user flip a bit on the factory that prevents this from
** being stored. The user would then need to use separate functions where
** the upb_alloc* is passed explicitly. However for handlers to populate
** such structures, they would need a place to store this upb_alloc* during
** parsing; upb_handlers don't currently have a good way to accommodate this.
**
** TODO: UTF-8 checking?
**/
#ifndef UPB_MSG_H_
#define UPB_MSG_H_
#include "upb/def.h"
#include "upb/handlers.h"
#include "upb/sink.h"
#include "upb/symtab.h"
#ifdef __cplusplus
namespace upb {
class MessageLayout;
class MessageFactory;
}
#endif
UPB_DECLARE_TYPE(upb::MessageFactory, upb_msgfactory)
UPB_DECLARE_TYPE(upb::MessageLayout, upb_msglayout)
UPB_DECLARE_TYPE(upb::Array, upb_array)
UPB_DECLARE_TYPE(upb::Map, upb_map)
UPB_DECLARE_TYPE(upb::MapIterator, upb_mapiter)
UPB_DECLARE_TYPE(upb::Visitor, upb_visitor)
UPB_DECLARE_TYPE(upb::VisitorPlan, upb_visitorplan)
/* TODO(haberman): C++ accessors */
UPB_BEGIN_EXTERN_C
/** upb_msglayout *************************************************************/
/* Please note that map_entry messages (upb_msgdef_mapentry(m) == true) cannot
* have layouts. They can only be represented as upb_map, not as a message. */
/* Requires that upb_fielddef_issubmsg(upb_msglayout_msgdef(l)) == true.
*
* Since map entry messages don't have layouts, if upb_fielddef_ismap(f) == true
* then this function will return the layout for the map's value. It requires
* that the value type of the map field is a submessage. */
const upb_msglayout *upb_msglayout_sublayout(const upb_msglayout *l,
const upb_fielddef *f);
const upb_msgdef *upb_msglayout_msgdef(const upb_msglayout *l);
/** upb_msgfactory ************************************************************/
upb_msgfactory *upb_msgfactory_new(const upb_symtab *symtab);
void upb_msgfactory_free(upb_msgfactory *f);
/* Requires:
* - m is in upb_msgfactory_symtab(f)
* - upb_msgdef_mapentry(m) == false (since map messages can't have layouts).
*
* The returned layout will live for as long as the msgfactory does.
*/
const upb_msglayout *upb_msgfactory_getlayout(const upb_msgfactory *f,
const upb_msgdef *m);
/* Returns handlers for populating a message with the given msgdef. */
const upb_handlers *upb_msgfactory_getmergehandlers(const upb_msgfactory *f,
const upb_msgdef *m);
/* Returns a plan for visiting the data and submessages of the given msgdef. */
const upb_visitorplan *upb_visitorplan_new(const upb_msgfactory *f,
const upb_msgdef *m);
/* For actually visiting a message and its submessages. */
upb_visitor *upb_visitor_create(upb_env *e, const upb_visitorplan *vp,
upb_sink *output);
bool upb_visitor_visitmsg(upb_visitor *v, const void *msg);
/** upb_msgval ****************************************************************/
/* A union representing all possible protobuf values. Used for generic get/set
* operations. */
typedef void upb_msg;
typedef union {
bool b;
float flt;
double dbl;
int32_t i32;
int64_t i64;
uint32_t u32;
uint64_t u64;
const void* ptr;
struct {
const char *ptr;
size_t len;
} str;
} upb_msgval;
#define ACCESSORS(name, membername, ctype) \
UPB_INLINE ctype upb_msgval_get ## name(upb_msgval v) { \
return v.membername; \
} \
UPB_INLINE void upb_msgval_set ## name(upb_msgval *v, ctype cval) { \
v->membername = cval; \
} \
UPB_INLINE upb_msgval upb_msgval_ ## name(ctype v) { \
upb_msgval ret; \
ret.membername = v; \
return ret; \
}
ACCESSORS(bool, b, bool)
ACCESSORS(float, flt, float)
ACCESSORS(double, dbl, double)
ACCESSORS(int32, i32, int32_t)
ACCESSORS(int64, i64, int64_t)
ACCESSORS(uint32, u32, uint32_t)
ACCESSORS(uint64, u64, uint64_t)
ACCESSORS(map, ptr, const upb_map*)
ACCESSORS(msg, ptr, const upb_msg*)
ACCESSORS(ptr, ptr, const void*)
ACCESSORS(arr, ptr, const upb_array*)
#undef ACCESSORS
UPB_INLINE upb_msgval upb_msgval_str(const char *ptr, size_t len) {
upb_msgval ret;
ret.str.ptr = ptr;
ret.str.len = len;
return ret;
}
/** upb_msg *******************************************************************/
size_t upb_msg_sizeof(const upb_msglayout *l);
void upb_msg_init(upb_msg *msg, const upb_msglayout *l, upb_alloc *a);
void upb_msg_uninit(upb_msg *msg, const upb_msglayout *l);
upb_msg *upb_msg_new(const upb_msglayout *l, upb_alloc *a);
void upb_msg_free(upb_msg *msg, const upb_msglayout *l);
upb_alloc *upb_msg_alloc(const upb_msg *msg, const upb_msglayout *l);
/* Packs the tree of messages rooted at "msg" into a single hunk of memory,
* allocated from the given allocator. */
void *upb_msg_pack(const upb_msg *msg, const upb_msglayout *l,
void *p, size_t *ofs, size_t size);
/* Read-only message API. Can be safely called by anyone. */
/* Returns the value associated with this field:
* - for scalar fields (including strings), the value directly.
* - return upb_msg*, or upb_map* for msg/map.
* If the field is unset for these field types, returns NULL.
*
* TODO(haberman): should we let users store cached array/map/msg
* pointers here for fields that are unset? Could be useful for the
* strongly-owned submessage model (ie. generated C API that doesn't use
* arenas).
*/
upb_msgval upb_msg_get(const upb_msg *msg,
const upb_fielddef *f,
const upb_msglayout *l);
/* May only be called for fields where upb_fielddef_haspresence(f) == true. */
bool upb_msg_has(const upb_msg *msg,
const upb_fielddef *f,
const upb_msglayout *l);
/* Returns NULL if no field in the oneof is set. */
const upb_fielddef *upb_msg_getoneofcase(const upb_msg *msg,
const upb_oneofdef *o,
const upb_msglayout *l);
/* Returns true if any field in the oneof is set. */
bool upb_msg_hasoneof(const upb_msg *msg,
const upb_oneofdef *o,
const upb_msglayout *l);
/* Mutable message API. May only be called by the owner of the message who
* knows its ownership scheme and how to keep it consistent. */
/* Sets the given field to the given value. Does not perform any memory
* management: if you overwrite a pointer to a msg/array/map/string without
* cleaning it up (or using an arena) it will leak.
*/
bool upb_msg_set(upb_msg *msg,
const upb_fielddef *f,
upb_msgval val,
const upb_msglayout *l);
/* For a primitive field, set it back to its default. For repeated, string, and
* submessage fields set it back to NULL. This could involve releasing some
* internal memory (for example, from an extension dictionary), but it is not
* recursive in any way and will not recover any memory that may be used by
* arrays/maps/strings/msgs that this field may have pointed to.
*/
bool upb_msg_clearfield(upb_msg *msg,
const upb_fielddef *f,
const upb_msglayout *l);
/* Clears all fields in the oneof such that none of them are set. */
bool upb_msg_clearoneof(upb_msg *msg,
const upb_oneofdef *o,
const upb_msglayout *l);
/* TODO(haberman): copyfrom()/mergefrom()? */
/** upb_array *****************************************************************/
size_t upb_array_sizeof(upb_fieldtype_t type);
void upb_array_init(upb_array *arr, upb_fieldtype_t type, upb_alloc *a);
void upb_array_uninit(upb_array *arr);
upb_array *upb_array_new(upb_fieldtype_t type, upb_alloc *a);
void upb_array_free(upb_array *arr);
/* Read-only interface. Safe for anyone to call. */
size_t upb_array_size(const upb_array *arr);
upb_fieldtype_t upb_array_type(const upb_array *arr);
upb_msgval upb_array_get(const upb_array *arr, size_t i);
/* Write interface. May only be called by the message's owner who can enforce
* its memory management invariants. */
bool upb_array_set(upb_array *arr, size_t i, upb_msgval val);
/** upb_map *******************************************************************/
/* Stores data for a map field. The map will internally allocate (and free, if
* desired) all the internal storage used for the hash table or tree, using the
* given allocator. It will also copy and internally store the data for string
* keys, but *not* for string or message *values*. So the caller must ensure
* that any string or message values outlive the map. */
size_t upb_map_sizeof(upb_fieldtype_t ktype, upb_fieldtype_t vtype);
bool upb_map_init(upb_map *map, upb_fieldtype_t ktype, upb_fieldtype_t vtype,
upb_alloc *a);
void upb_map_uninit(upb_map *map);
upb_map *upb_map_new(upb_fieldtype_t ktype, upb_fieldtype_t vtype, upb_alloc *a);
void upb_map_free(upb_map *map);
/* Read-only interface. Safe for anyone to call. */
size_t upb_map_size(const upb_map *map);
upb_fieldtype_t upb_map_keytype(const upb_map *map);
upb_fieldtype_t upb_map_valuetype(const upb_map *map);
bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val);
/* Write interface. May only be called by the message's owner who can enforce
* its memory management invariants. */
/* Sets or overwrites an entry in the map. Return value indicates whether
* the operation succeeded or failed with OOM, and also whether an existing
* key was replaced or not. */
bool upb_map_set(upb_map *map,
upb_msgval key, upb_msgval val,
upb_msgval *valremoved);
/* Deletes an entry in the map. Returns true if the key was present. */
bool upb_map_del(upb_map *map, upb_msgval key);
/** upb_mapiter ***************************************************************/
/* For iterating over a map. Map iterators are invalidated by mutations to the
* map, but an invalidated iterator will never return junk or crash the process.
* An invalidated iterator may return entries that were already returned though,
* and if you keep invalidating the iterator during iteration, the program may
* enter an infinite loop. */
size_t upb_mapiter_sizeof();
void upb_mapiter_begin(upb_mapiter *i, const upb_map *t);
upb_mapiter *upb_mapiter_new(const upb_map *t, upb_alloc *a);
void upb_mapiter_free(upb_mapiter *i, upb_alloc *a);
void upb_mapiter_next(upb_mapiter *i);
bool upb_mapiter_done(const upb_mapiter *i);
/* For string keys, the value will be in upb_msgval_strkey(), *not*
* upb_msgval_str(). */
upb_msgval upb_mapiter_key(const upb_mapiter *i);
upb_msgval upb_mapiter_value(const upb_mapiter *i);
void upb_mapiter_setdone(upb_mapiter *i);
bool upb_mapiter_isequal(const upb_mapiter *i1, const upb_mapiter *i2);
/** Handlers ******************************************************************/
/* These are the handlers used internally by upb_msgfactory_getmergehandlers().
* They write scalar data to a known offset from the message pointer.
*
* These would be trivial for anyone to implement themselves, but it's better
* to use these because some JITs will recognize and specialize these instead
* of actually calling the function. */
/* Sets a handler for the given primitive field that will write the data at the
* given offset. If hasbit > 0, also sets a hasbit at the given bit offset
* (addressing each byte low to high). */
bool upb_msg_setscalarhandler(upb_handlers *h,
const upb_fielddef *f,
size_t offset,
int32_t hasbit);
/* If the given handler is a msghandlers_primitive field, returns true and sets
* *type, *offset and *hasbit. Otherwise returns false. */
bool upb_msg_getscalarhandlerdata(const upb_handlers *h,
upb_selector_t s,
upb_fieldtype_t *type,
size_t *offset,
int32_t *hasbit);
UPB_END_EXTERN_C
#endif /* UPB_MSG_H_ */

@ -1,84 +0,0 @@
#include "upb/shim/shim.h"
/* Fallback implementation if the shim is not specialized by the JIT. */
#define SHIM_WRITER(type, ctype) \
bool upb_shim_set ## type (void *c, const void *hd, ctype val) { \
uint8_t *m = c; \
const upb_shim_data *d = hd; \
if (d->hasbit > 0) \
*(uint8_t*)&m[d->hasbit / 8] |= 1 << (d->hasbit % 8); \
*(ctype*)&m[d->offset] = val; \
return true; \
} \
SHIM_WRITER(double, double)
SHIM_WRITER(float, float)
SHIM_WRITER(int32, int32_t)
SHIM_WRITER(int64, int64_t)
SHIM_WRITER(uint32, uint32_t)
SHIM_WRITER(uint64, uint64_t)
SHIM_WRITER(bool, bool)
#undef SHIM_WRITER
bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset,
int32_t hasbit) {
upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
bool ok;
upb_shim_data *d = upb_gmalloc(sizeof(*d));
if (!d) return false;
d->offset = offset;
d->hasbit = hasbit;
upb_handlerattr_sethandlerdata(&attr, d);
upb_handlerattr_setalwaysok(&attr, true);
upb_handlers_addcleanup(h, d, upb_gfree);
#define TYPE(u, l) \
case UPB_TYPE_##u: \
ok = upb_handlers_set##l(h, f, upb_shim_set##l, &attr); break;
ok = false;
switch (upb_fielddef_type(f)) {
TYPE(INT64, int64);
TYPE(INT32, int32);
TYPE(ENUM, int32);
TYPE(UINT64, uint64);
TYPE(UINT32, uint32);
TYPE(DOUBLE, double);
TYPE(FLOAT, float);
TYPE(BOOL, bool);
default: UPB_ASSERT(false); break;
}
#undef TYPE
upb_handlerattr_uninit(&attr);
return ok;
}
const upb_shim_data *upb_shim_getdata(const upb_handlers *h, upb_selector_t s,
upb_fieldtype_t *type) {
upb_func *f = upb_handlers_gethandler(h, s);
if ((upb_int64_handlerfunc*)f == upb_shim_setint64) {
*type = UPB_TYPE_INT64;
} else if ((upb_int32_handlerfunc*)f == upb_shim_setint32) {
*type = UPB_TYPE_INT32;
} else if ((upb_uint64_handlerfunc*)f == upb_shim_setuint64) {
*type = UPB_TYPE_UINT64;
} else if ((upb_uint32_handlerfunc*)f == upb_shim_setuint32) {
*type = UPB_TYPE_UINT32;
} else if ((upb_double_handlerfunc*)f == upb_shim_setdouble) {
*type = UPB_TYPE_DOUBLE;
} else if ((upb_float_handlerfunc*)f == upb_shim_setfloat) {
*type = UPB_TYPE_FLOAT;
} else if ((upb_bool_handlerfunc*)f == upb_shim_setbool) {
*type = UPB_TYPE_BOOL;
} else {
return NULL;
}
return (const upb_shim_data*)upb_handlers_gethandlerdata(h, s);
}

@ -1,69 +0,0 @@
/*
** For handlers that do very tiny, very simple operations, the function call
** overhead of calling a handler can be significant. This file allows the
** user to define handlers that do something very simple like store the value
** to memory and/or set a hasbit. JIT compilers can then special-case these
** handlers and emit specialized code for them instead of actually calling the
** handler.
**
** The functionality is very simple/limited right now but may expand to be able
** to call another function.
*/
#ifndef UPB_SHIM_H
#define UPB_SHIM_H
#include "upb/handlers.h"
typedef struct {
size_t offset;
int32_t hasbit;
} upb_shim_data;
#ifdef __cplusplus
namespace upb {
struct Shim {
typedef upb_shim_data Data;
/* Sets a handler for the given field that writes the value to the given
* offset and, if hasbit >= 0, sets a bit at the given bit offset. Returns
* true if the handler was set successfully. */
static bool Set(Handlers *h, const FieldDef *f, size_t ofs, int32_t hasbit);
/* If this handler is a shim, returns the corresponding upb::Shim::Data and
* stores the type in "type". Otherwise returns NULL. */
static const Data* GetData(const Handlers* h, Handlers::Selector s,
FieldDef::Type* type);
};
} /* namespace upb */
#endif
UPB_BEGIN_EXTERN_C
/* C API. */
bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset,
int32_t hasbit);
const upb_shim_data *upb_shim_getdata(const upb_handlers *h, upb_selector_t s,
upb_fieldtype_t *type);
UPB_END_EXTERN_C
#ifdef __cplusplus
/* C++ Wrappers. */
namespace upb {
inline bool Shim::Set(Handlers* h, const FieldDef* f, size_t ofs,
int32_t hasbit) {
return upb_shim_set(h, f, ofs, hasbit);
}
inline const Shim::Data* Shim::GetData(const Handlers* h, Handlers::Selector s,
FieldDef::Type* type) {
return upb_shim_getdata(h, s, type);
}
} /* namespace upb */
#endif
#endif /* UPB_SHIM_H */

@ -152,6 +152,7 @@ extern const struct upb_refcounted_vtbl upb_enumdef_vtbl;
struct upb_oneofdef {
upb_refcounted base;
uint32_t index; /* Index within oneofs. */
const char *name;
upb_strtable ntof;
upb_inttable itof;
@ -161,7 +162,7 @@ struct upb_oneofdef {
extern const struct upb_refcounted_vtbl upb_oneofdef_vtbl;
#define UPB_ONEOFDEF_INIT(name, ntof, itof, refs, ref2s) \
{ UPB_REFCOUNT_INIT(&upb_oneofdef_vtbl, refs, ref2s), name, ntof, itof }
{ UPB_REFCOUNT_INIT(&upb_oneofdef_vtbl, refs, ref2s), 0, name, ntof, itof }
/* upb_symtab *****************************************************************/

@ -43,7 +43,9 @@ typedef enum {
UPB_CTYPE_CSTR = 6,
UPB_CTYPE_PTR = 7,
UPB_CTYPE_CONSTPTR = 8,
UPB_CTYPE_FPTR = 9
UPB_CTYPE_FPTR = 9,
UPB_CTYPE_FLOAT = 10,
UPB_CTYPE_DOUBLE = 11
} upb_ctype_t;
typedef struct {
@ -117,6 +119,29 @@ FUNCS(constptr, constptr, const void*, uintptr_t, UPB_CTYPE_CONSTPTR)
FUNCS(fptr, fptr, upb_func*, uintptr_t, UPB_CTYPE_FPTR)
#undef FUNCS
UPB_INLINE void upb_value_setfloat(upb_value *val, float cval) {
memcpy(&val->val, &cval, sizeof(cval));
SET_TYPE(val->ctype, UPB_CTYPE_FLOAT);
}
UPB_INLINE void upb_value_setdouble(upb_value *val, double cval) {
memcpy(&val->val, &cval, sizeof(cval));
SET_TYPE(val->ctype, UPB_CTYPE_DOUBLE);
}
UPB_INLINE upb_value upb_value_float(float cval) {
upb_value ret;
upb_value_setfloat(&ret, cval);
return ret;
}
UPB_INLINE upb_value upb_value_double(double cval) {
upb_value ret;
upb_value_setdouble(&ret, cval);
return ret;
}
#undef SET_TYPE
@ -359,6 +384,13 @@ UPB_INLINE size_t upb_strtable_count(const upb_strtable *t) {
return t->t.count;
}
void upb_inttable_packedsize(const upb_inttable *t, size_t *size);
void upb_strtable_packedsize(const upb_strtable *t, size_t *size);
upb_inttable *upb_inttable_pack(const upb_inttable *t, void *p, size_t *ofs,
size_t size);
upb_strtable *upb_strtable_pack(const upb_strtable *t, void *p, size_t *ofs,
size_t size);
/* Inserts the given key into the hashtable with the given value. The key must
* not already exist in the hash table. For string tables, the key must be
* NULL-terminated, and the table will make an internal copy of the key.

@ -231,6 +231,10 @@ void upb_arena_uninit(upb_arena *a) {
block = next;
}
/* Protect against multiple-uninit. */
a->cleanup_head = NULL;
a->block_head = NULL;
}
bool upb_arena_addcleanup(upb_arena *a, upb_cleanup_func *func, void *ud) {

@ -208,6 +208,12 @@ template <int N> class InlinedEnvironment;
* exist in debug mode. This turns into regular assert. */
#define UPB_ASSERT_DEBUGVAR(expr) assert(expr)
#ifdef __GNUC__
#define UPB_UNREACHABLE() do { assert(0); __builtin_unreachable(); } while(0)
#else
#define UPB_UNREACHABLE() do { assert(0); } while(0)
#endif
/* Generic function type. */
typedef void upb_func();
@ -441,17 +447,18 @@ struct upb_alloc {
};
UPB_INLINE void *upb_malloc(upb_alloc *alloc, size_t size) {
UPB_ASSERT(size > 0);
UPB_ASSERT(alloc);
return alloc->func(alloc, NULL, 0, size);
}
UPB_INLINE void *upb_realloc(upb_alloc *alloc, void *ptr, size_t oldsize,
size_t size) {
UPB_ASSERT(size > 0);
UPB_ASSERT(alloc);
return alloc->func(alloc, ptr, oldsize, size);
}
UPB_INLINE void upb_free(upb_alloc *alloc, void *ptr) {
assert(alloc);
alloc->func(alloc, ptr, 0, 0);
}
@ -500,7 +507,6 @@ UPB_BEGIN_EXTERN_C
void upb_arena_init(upb_arena *a);
void upb_arena_init2(upb_arena *a, void *mem, size_t n, upb_alloc *alloc);
void upb_arena_uninit(upb_arena *a);
upb_alloc *upb_arena_alloc(upb_arena *a);
bool upb_arena_addcleanup(upb_arena *a, upb_cleanup_func *func, void *ud);
size_t upb_arena_bytesallocated(const upb_arena *a);
void upb_arena_setnextblocksize(upb_arena *a, size_t size);
@ -585,6 +591,10 @@ struct upb_arena {
void *future2;
};
UPB_BEGIN_EXTERN_C
UPB_INLINE upb_alloc *upb_arena_alloc(upb_arena *a) { return &a->alloc; }
UPB_END_EXTERN_C
/* upb::Environment ***********************************************************/

Loading…
Cancel
Save