pull/13171/head
Joshua Haberman 5 years ago
parent 9a360ad43d
commit 27b95c969a
  1. 24
      BUILD
  2. 31
      bazel/build_defs.bzl
  3. 406
      upb/bindings/lua/def.c
  4. 573
      upb/bindings/lua/msg.c
  5. 73
      upb/bindings/lua/upb.c
  6. 87
      upb/bindings/lua/upb.h
  7. 56
      upb/bindings/lua/upb/pb.c
  8. 3
      upb/bindings/lua/upb/pb.lua
  9. 19
      upb/reflection.h

24
BUILD

@ -579,7 +579,6 @@ lua_cclibrary(
deps = [
"reflection",
"upb",
"upb_pb",
],
)
@ -590,23 +589,6 @@ lua_library(
strip_prefix = "upb/bindings/lua",
)
lua_cclibrary(
name = "lua/upb/pb_c",
srcs = ["upb/bindings/lua/upb/pb.c"],
luadeps = ["lua/upb_c"],
deps = ["upb_pb"],
)
lua_library(
name = "lua/upb/pb",
srcs = ["upb/bindings/lua/upb/pb.lua"],
luadeps = [
"lua/upb",
"lua/upb/pb_c",
],
strip_prefix = "upb/bindings/lua",
)
# Lua tests. ###################################################################
lua_test(
@ -615,12 +597,6 @@ lua_test(
luamain = "tests/bindings/lua/test_upb.lua",
)
lua_test(
name = "lua/test_upb_pb",
luadeps = ["lua/upb/pb"],
luamain = "tests/bindings/lua/test_upb.pb.lua",
)
# Test the CMake build #########################################################
filegroup(

@ -5,6 +5,19 @@ load(":upb_proto_library.bzl", "GeneratedSrcsInfo")
def _librule(name):
return name + "_lib"
runfiles_init = """\
# --- begin runfiles.bash initialization v2 ---
# Copy-pasted from the Bazel Bash runfiles library v2.
set -uo pipefail; f=bazel_tools/tools/bash/runfiles/runfiles.bash
source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
source "$0.runfiles/$f" 2>/dev/null || \
source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
{ echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e
# --- end runfiles.bash initialization v2 ---
"""
def _get_real_short_path(file):
# For some reason, files from other archives have short paths that look like:
# ../com_google_protobuf/google/protobuf/descriptor.proto
@ -26,7 +39,7 @@ def _get_real_roots(files):
roots[real_root] = True
return roots.keys()
def lua_cclibrary(name, srcs, hdrs = [], deps = [], luadeps = []):
def lua_cclibrary(name, srcs, hdrs = [], deps = []):
lib_rule = name + "_lib"
so_rule = "lib" + name + ".so"
so_file = _remove_prefix(name, "lua/") + ".so"
@ -35,7 +48,7 @@ def lua_cclibrary(name, srcs, hdrs = [], deps = [], luadeps = []):
name = _librule(name),
hdrs = hdrs,
srcs = srcs,
deps = deps + [_librule(dep) for dep in luadeps] + ["@lua//:liblua_headers"],
deps = deps + ["@lua//:liblua_headers"],
)
native.cc_binary(
@ -87,7 +100,7 @@ def lua_library(name, srcs, strip_prefix, luadeps = []):
)
def make_shell_script(name, contents, out):
contents = contents.replace("$", "$$")
contents = (runfiles_init + contents).replace("$", "$$")
native.genrule(
name = "gen_" + name,
outs = [out],
@ -104,14 +117,20 @@ def _lua_binary_or_test(name, luamain, luadeps, rule):
BASE=$(dirname $(rlocation upb/upb_c.so))
export LUA_CPATH="$BASE/?.so"
export LUA_PATH="$BASE/?.lua"
$(rlocation lua/lua) $(rlocation upb/tools/upbc.lua) "$@"
""",
LUA=$(rlocation lua/lua)
MAIN=$(rlocation upb/%s)
$LUA $MAIN
""" % luamain,
)
rule(
name = name,
srcs = [script],
data = ["@lua//:lua", luamain] + luadeps,
data = [
"@lua//:lua",
luamain
] + luadeps,
deps = ["@bazel_tools//tools/bash/runfiles"],
)
def lua_binary(name, luamain, luadeps = []):

@ -15,97 +15,68 @@
#define LUPB_SYMTAB "lupb.symtab"
#define LUPB_OBJCACHE "lupb.objcache"
#define CHK(pred) \
do { \
upb_status status; \
upb_status_clear(&status); \
pred; \
lupb_checkstatus(L, &status); \
} while (0)
static void lupb_symtab_pushwrapper(lua_State *L, int narg, const void *def,
const char *type);
/* lupb_wrapper ***************************************************************/
/* Wrappers around upb objects. */
/* Wrappers around upb def objects. The userval contains a reference to the
* symtab. */
/* Checks type; if it matches, pulls the pointer out of the wrapper. */
void *lupb_checkwrapper(lua_State *L, int narg, const char *type) {
void *ud = lua_touserdata(L, narg);
void *ret;
typedef struct {
const void* def; /* upb_msgdef, upb_enumdef, upb_oneofdef, etc. */
} lupb_wrapper;
static const void *lupb_wrapper_check(lua_State *L, int narg,
const char *type) {
lupb_wrapper *w = lua_touserdata(L, narg);
if (!ud) {
if (!w) {
luaL_typerror(L, narg, "upb wrapper");
}
memcpy(&ret, ud, sizeof(ret));
if (!ret) {
if (!w->def) {
luaL_error(L, "called into dead object");
}
luaL_checkudata(L, narg, type);
return ret;
return w->def;
}
void lupb_pushwrapper(lua_State *L, const void *obj, const char *type) {
void *ud;
if (obj == NULL) {
lua_pushnil(L);
return;
}
/* Lookup our cache in the registry (we don't put our objects in the registry
* directly because we need our cache to be a weak table). */
lua_getfield(L, LUA_REGISTRYINDEX, LUPB_OBJCACHE);
UPB_ASSERT(!lua_isnil(L, -1)); /* Should have been created by luaopen_upb. */
lua_pushlightuserdata(L, (void*)obj);
lua_rawget(L, -2);
/* Stack is now: objcache, cached value. */
if (lua_isnil(L, -1)) {
/* Remove bad cached value and push new value. */
lua_pop(L, 1);
ud = lua_newuserdata(L, sizeof(*ud));
memcpy(ud, &obj, sizeof(*ud));
luaL_getmetatable(L, type);
/* Should have been created by luaopen_upb. */
lupb_assert(L, !lua_isnil(L, -1));
lua_setmetatable(L, -2);
/* Set it in the cache. */
lua_pushlightuserdata(L, (void*)obj);
lua_pushvalue(L, -2);
lua_rawset(L, -4);
}
lua_insert(L, -2);
lua_pop(L, 1);
static void lupb_wrapper_pushsymtab(lua_State *L, int narg) {
lua_getuserval(L, narg);
lua_rawgeti(L, -1, 1);
lua_replace(L, -2);
}
void lupb_msgdef_pushwrapper(lua_State *L, const upb_msgdef *m);
void lupb_oneofdef_pushwrapper(lua_State *L, const upb_oneofdef *o);
static void lupb_enumdef_pushwrapper(lua_State *L, const upb_enumdef *e);
/* lupb_wrapper_pushwrapper()
*
* For a given def wrapper at index |narg|, pushes a wrapper for the given |def|
* and the given |type|. The new wrapper will be part of the same symtab. */
static void lupb_wrapper_pushwrapper(lua_State *L, int narg, const void *def,
const char *type) {
lupb_wrapper_pushsymtab(L, narg);
lupb_symtab_pushwrapper(L, -1, def, type);
lua_replace(L, -2); /* Remove symtab from stack. */
}
/* lupb_fielddef **************************************************************/
void lupb_fielddef_pushwrapper(lua_State *L, const upb_fielddef *f) {
lupb_pushwrapper(L, f, LUPB_FIELDDEF);
}
const upb_fielddef *lupb_fielddef_check(lua_State *L, int narg) {
return lupb_checkwrapper(L, narg, LUPB_FIELDDEF);
return lupb_wrapper_check(L, narg, LUPB_FIELDDEF);
}
static int lupb_fielddef_containingoneof(lua_State *L) {
const upb_fielddef *f = lupb_fielddef_check(L, 1);
lupb_oneofdef_pushwrapper(L, upb_fielddef_containingoneof(f));
const upb_oneof *o = upb_fielddef_containingoneof(f);
lupb_wrapper_pushwrapper(L, 1, o, LUPB_ONEOFDEF);
return 1;
}
static int lupb_fielddef_containingtype(lua_State *L) {
const upb_fielddef *f = lupb_fielddef_check(L, 1);
lupb_msgdef_pushwrapper(L, upb_fielddef_containingtype(f));
const upb_msgdef *m = upb_fielddef_containingtype(f);
lupb_wrapper_pushwrapper(L, 1, m, LUPB_MSGDEF);
return 1;
}
@ -146,17 +117,6 @@ static int lupb_fielddef_descriptortype(lua_State *L) {
return 1;
}
static int lupb_fielddef_getsel(lua_State *L) {
const upb_fielddef *f = lupb_fielddef_check(L, 1);
upb_selector_t sel;
if (upb_handlers_getselector(f, luaL_checknumber(L, 2), &sel)) {
lua_pushinteger(L, sel);
return 1;
} else {
return 0;
}
}
static int lupb_fielddef_hassubdef(lua_State *L) {
const upb_fielddef *f = lupb_fielddef_check(L, 1);
lua_pushboolean(L, upb_fielddef_hassubdef(f));
@ -211,22 +171,21 @@ static int lupb_fielddef_packed(lua_State *L) {
static int lupb_fielddef_msgsubdef(lua_State *L) {
const upb_fielddef *f = lupb_fielddef_check(L, 1);
lupb_msgdef_pushwrapper(L, upb_fielddef_msgsubdef(f));
const upb_msgdef *m = upb_fielddef_msgsubdef(f);
lupb_wrapper_pushwrapper(L, 1, m, LUPB_MSGDEF);
return 1;
}
static int lupb_fielddef_enumsubdef(lua_State *L) {
const upb_fielddef *f = lupb_fielddef_check(L, 1);
lupb_enumdef_pushwrapper(L, upb_fielddef_enumsubdef(f));
const upb_enumdef *e = upb_fielddef_enumsubdef(f);
lupb_wrapper_pushwrapper(L, 1, e, LUPB_ENUMDEF);
return 1;
}
static int lupb_fielddef_type(lua_State *L) {
const upb_fielddef *f = lupb_fielddef_check(L, 1);
if (upb_fielddef_typeisset(f))
lua_pushinteger(L, upb_fielddef_type(f));
else
lua_pushnil(L);
lua_pushinteger(L, upb_fielddef_type(f));
return 1;
}
@ -235,7 +194,6 @@ static const struct luaL_Reg lupb_fielddef_m[] = {
{"containing_type", lupb_fielddef_containingtype},
{"default", lupb_fielddef_default},
{"descriptor_type", lupb_fielddef_descriptortype},
{"getsel", lupb_fielddef_getsel},
{"has_subdef", lupb_fielddef_hassubdef},
{"index", lupb_fielddef_index},
{"is_extension", lupb_fielddef_isextension},
@ -250,55 +208,64 @@ static const struct luaL_Reg lupb_fielddef_m[] = {
{NULL, NULL}
};
/* lupb_oneofdef **************************************************************/
void lupb_oneofdef_pushwrapper(lua_State *L, const upb_oneofdef *o) {
lupb_pushwrapper(L, o, LUPB_ONEOFDEF);
}
const upb_oneofdef *lupb_oneofdef_check(lua_State *L, int narg) {
return lupb_checkwrapper(L, narg, LUPB_ONEOFDEF);
return lupb_wrapper_check(L, narg, LUPB_ONEOFDEF);
}
static int lupb_oneofdef_containingtype(lua_State *L) {
const upb_oneofdef *o = lupb_oneofdef_check(L, 1);
lupb_msgdef_pushwrapper(L, upb_oneofdef_containingtype(o));
const upb_msgdef *m = upb_oneofdef_containingtype(o);
lupb_wrapper_pushwrapper(L, 1, m, LUPB_MSGDEF);
return 1;
}
/* lupb_oneofdef_field()
*
* Handles:
* oneof.field(field_number)
* oneof.field(field_name)
*/
static int lupb_oneofdef_field(lua_State *L) {
const upb_oneofdef *o = lupb_oneofdef_check(L, 1);
int type = lua_type(L, 2);
const upb_oneofdef *o = lupb_oneofdef_check(L, narg);
const upb_fielddef *f;
if (type == LUA_TNUMBER) {
f = upb_oneofdef_itof(o, lua_tointeger(L, 2));
} else if (type == LUA_TSTRING) {
f = upb_oneofdef_ntofz(o, lua_tostring(L, 2));
} else {
const char *msg = lua_pushfstring(L, "number or string expected, got %s",
luaL_typename(L, 2));
return luaL_argerror(L, 2, msg);
switch (lua_type(L, 2)) {
case LUA_TNUMBER:
f = upb_oneofdef_itof(o, lua_tointeger(L, 2));
break;
case LUA_TSTRING:
f = upb_oneofdef_ntofz(o, lua_tostring(L, 2));
break;
default: {
const char *msg = lua_pushfstring(L, "number or string expected, got %s",
luaL_typename(L, 2));
return luaL_argerror(L, 2, msg);
}
}
lupb_fielddef_pushwrapper(L, f);
lupb_wrapper_pushwrapper(L, 1, f, LUPB_FIELDDEF);
return 1;
}
static int lupb_oneofiter_next(lua_State *L) {
upb_oneof_iter *i = lua_touserdata(L, lua_upvalueindex(1));
const upb_fielddef *f;
if (upb_oneof_done(i)) return 0;
lupb_fielddef_pushwrapper(L, upb_oneof_iter_field(i));
f = upb_oneof_iter_field(i);
upb_oneof_next(i);
lupb_symtab_pushwrapper(L, lua_upvalueindex(2), f, LUPB_FIELDDEF);
return 1;
}
static int lupb_oneofdef_fields(lua_State *L) {
const upb_oneofdef *o = lupb_oneofdef_check(L, 1);
upb_oneof_iter *i = lua_newuserdata(L, sizeof(upb_oneof_iter));
upb_oneof_begin(i, o);
/* Need to guarantee that the msgdef outlives the iter. */
lua_pushvalue(L, 1);
const upb_oneofdef *o = lupb_oneof_check(L, 1);
lupb_oneofiter *i = lua_newuserdata(L, sizeof(lupb_oneofiter));
lupb_wrapper_pushsymtab(L, 1);
upb_oneof_begin(&i->iter, o);
/* Closure upvalues are: iter, symtab. */
lua_pushcclosure(L, &lupb_oneofiter_next, 2);
return 1;
}
@ -335,12 +302,8 @@ typedef struct {
const upb_msgdef *md;
} lupb_msgdef;
void lupb_msgdef_pushwrapper(lua_State *L, const upb_msgdef *m) {
lupb_pushwrapper(L, m, LUPB_MSGDEF);
}
const upb_msgdef *lupb_msgdef_check(lua_State *L, int narg) {
return lupb_checkwrapper(L, narg, LUPB_MSGDEF);
return lupb_wrapper_check(L, narg, LUPB_MSGDEF);
}
static int lupb_msgdef_len(lua_State *L) {
@ -349,42 +312,62 @@ static int lupb_msgdef_len(lua_State *L) {
return 1;
}
/* lupb_msgdef_field()
*
* Handles:
* msg.field(field_number) -> fielddef
* msg.field(field_name) -> fielddef
*/
static int lupb_msgdef_field(lua_State *L) {
const upb_msgdef *m = lupb_msgdef_check(L, 1);
int type = lua_type(L, 2);
const upb_fielddef *f;
if (type == LUA_TNUMBER) {
f = upb_msgdef_itof(m, lua_tointeger(L, 2));
} else if (type == LUA_TSTRING) {
f = upb_msgdef_ntofz(m, lua_tostring(L, 2));
} else {
const char *msg = lua_pushfstring(L, "number or string expected, got %s",
luaL_typename(L, 2));
return luaL_argerror(L, 2, msg);
switch (lua_type(L, 2)) {
case LUA_TNUMBER:
f = upb_msgdef_itof(m, lua_tointeger(L, 2));
break;
case LUA_TSTRING:
f = upb_msgdef_ntofz(m, lua_tostring(L, 2));
break;
default: {
const char *msg = lua_pushfstring(L, "number or string expected, got %s",
luaL_typename(L, 2));
return luaL_argerror(L, 2, msg);
}
}
lupb_fielddef_pushwrapper(L, f);
lupb_wrapper_pushwrapper(L, 1, f, LUPB_FIELDDEF);
return 1;
}
/* lupb_msgdef_lookupname()
*
* Handles:
* msg.lookup_name(name) -> fielddef or oneofdef
*/
static int lupb_msgdef_lookupname(lua_State *L) {
const upb_msgdef *m = lupb_msgdef_check(L, 1);
const upb_fielddef *f;
const upb_oneofdef *o;
if (!upb_msgdef_lookupnamez(m, lua_tostring(L, 2), &f, &o)) {
lua_pushnil(L);
} else if (o) {
lupb_oneofdef_pushwrapper(L, o);
lupb_wrapper_pushwrapper(L, 1, o, LUPB_ONEOFDEF);
} else {
lupb_fielddef_pushwrapper(L, f);
lupb_wrapper_pushwrapper(L, 1, f, LUPB_FIELDDEF);
}
return 1;
}
static int lupb_msgfielditer_next(lua_State *L) {
upb_msg_field_iter *i = lua_touserdata(L, lua_upvalueindex(1));
const upb_fielddef *f;
if (upb_msg_field_done(i)) return 0;
lupb_fielddef_pushwrapper(L, upb_msg_iter_field(i));
f = upb_msg_iter_field(i);
lupb_symtab_pushwrapper(L, lua_upvalueindex(2), f);
upb_msg_field_next(i);
return 1;
}
@ -392,27 +375,31 @@ static int lupb_msgfielditer_next(lua_State *L) {
static int lupb_msgdef_fields(lua_State *L) {
const upb_msgdef *m = lupb_msgdef_check(L, 1);
upb_msg_field_iter *i = lua_newuserdata(L, sizeof(upb_msg_field_iter));
lupb_wrapper_pushsymtab(L, 1);
upb_msg_field_begin(i, m);
/* Need to guarantee that the msgdef outlives the iter. */
lua_pushvalue(L, 1);
/* Closure upvalues are: iter, symtab. */
lua_pushcclosure(L, &lupb_msgfielditer_next, 2);
return 1;
}
static int lupb_msgoneofiter_next(lua_State *L) {
upb_msg_oneof_iter *i = lua_touserdata(L, lua_upvalueindex(1));
const upb_oneofdef *o;
if (upb_msg_oneof_done(i)) return 0;
lupb_oneofdef_pushwrapper(L, upb_msg_iter_oneof(i));
o = upb_msg_iter_oneof(i);
upb_msg_oneof_next(i);
lupb_symtab_pushwrapper(L, lua_upvalueindex(2), o);
return 1;
}
static int lupb_msgdef_oneofs(lua_State *L) {
const upb_msgdef *m = lupb_msgdef_check(L, 1);
upb_msg_oneof_iter *i = lua_newuserdata(L, sizeof(upb_msg_oneof_iter));
lupb_wrapper_pushsymtab(L, 1);
upb_msg_oneof_begin(i, m);
/* Need to guarantee that the msgdef outlives the iter. */
lua_pushvalue(L, 1);
/* Closure upvalues are: iter, symtab. */
lua_pushcclosure(L, &lupb_msgoneofiter_next, 2);
return 1;
}
@ -448,11 +435,7 @@ static const struct luaL_Reg lupb_msgdef_m[] = {
/* lupb_enumdef ***************************************************************/
const upb_enumdef *lupb_enumdef_check(lua_State *L, int narg) {
return lupb_checkwrapper(L, narg, LUPB_ENUMDEF);
}
static void lupb_enumdef_pushwrapper(lua_State *L, const upb_enumdef *e) {
lupb_pushwrapper(L, e, LUPB_ENUMDEF);
return lupb_wrapper_check(L, narg, LUPB_ENUMDEF);
}
static int lupb_enumdef_len(lua_State *L) {
@ -461,26 +444,39 @@ static int lupb_enumdef_len(lua_State *L) {
return 1;
}
/* lupb_enumdef_value()
*
* Handles:
* enum.value(number) -> name
* enum.value(name) -> number
*/
static int lupb_enumdef_value(lua_State *L) {
const upb_enumdef *e = lupb_enumdef_check(L, 1);
int type = lua_type(L, 2);
if (type == LUA_TNUMBER) {
/* Pushes "nil" for a NULL pointer. */
int32_t key = lupb_checkint32(L, 2);
lua_pushstring(L, upb_enumdef_iton(e, key));
} else if (type == LUA_TSTRING) {
const char *key = lua_tostring(L, 2);
int32_t num;
if (upb_enumdef_ntoiz(e, key, &num)) {
lua_pushinteger(L, num);
} else {
lua_pushnil(L);
switch (lua_type(L, 2)) {
case LUA_TNUMBER: {
int32_t key = lupb_checkint32(L, 2);
/* Pushes "nil" for a NULL pointer. */
lua_pushstring(L, upb_enumdef_iton(e, key));
break;
}
case LUA_TSTRING: {
const char *key = lua_tostring(L, 2);
int32_t num;
if (upb_enumdef_ntoiz(e, key, &num)) {
lua_pushinteger(L, num);
} else {
lua_pushnil(L);
}
break;
}
default: {
const char *msg = lua_pushfstring(L, "number or string expected, got %s",
luaL_typename(L, 2));
return luaL_argerror(L, 2, msg);
}
} else {
const char *msg = lua_pushfstring(L, "number or string expected, got %s",
luaL_typename(L, 2));
return luaL_argerror(L, 2, msg);
}
return 1;
}
@ -496,9 +492,10 @@ static int lupb_enumiter_next(lua_State *L) {
static int lupb_enumdef_values(lua_State *L) {
const upb_enumdef *e = lupb_enumdef_check(L, 1);
upb_enum_iter *i = lua_newuserdata(L, sizeof(upb_enum_iter));
lupb_wrapper_pushsymtab(L, 1);
upb_enum_begin(i, e);
/* Need to guarantee that the enumdef outlives the iter. */
lua_pushvalue(L, 1);
/* Closure upvalues are: iter, symtab. */
lua_pushcclosure(L, &lupb_enumiter_next, 2);
return 1;
}
@ -517,18 +514,15 @@ static const struct luaL_Reg lupb_enumdef_m[] = {
/* lupb_filedef ***************************************************************/
void lupb_filedef_pushwrapper(lua_State *L, const upb_filedef *f) {
lupb_pushwrapper(L, f, LUPB_FILEDEF);
}
const upb_filedef *lupb_filedef_check(lua_State *L, int narg) {
return lupb_checkwrapper(L, narg, LUPB_FILEDEF);
return lupb_wrapper_check(L, narg, LUPB_FILEDEF);
}
static int lupb_filedef_dep(lua_State *L) {
const upb_filedef *f = lupb_filedef_check(L, 1);
int index = luaL_checkint(L, 2);
lupb_filedef_pushwrapper(L, upb_filedef_dep(f, index));
const upb_filedef *dep = upb_filedef_dep(f, index);
lupb_wrapper_pushwrapper(L, 1, dep, LUPB_FILEDEF);
return 1;
}
@ -541,7 +535,8 @@ static int lupb_filedef_depcount(lua_State *L) {
static int lupb_filedef_enum(lua_State *L) {
const upb_filedef *f = lupb_filedef_check(L, 1);
int index = luaL_checkint(L, 2);
lupb_enumdef_pushwrapper(L, upb_filedef_enum(f, index));
const upb_enumdef *e = upb_filedef_enum(f, index);
lupb_wrapper_pushwrapper(L, 1, e, LUPB_ENUMDEF);
return 1;
}
@ -554,7 +549,8 @@ static int lupb_filedef_enumcount(lua_State *L) {
static int lupb_filedef_msg(lua_State *L) {
const upb_filedef *f = lupb_filedef_check(L, 1);
int index = luaL_checkint(L, 2);
lupb_msgdef_pushwrapper(L, upb_filedef_msg(f, index));
const upb_msgdef *m = upb_filedef_msg(f, index);
lupb_wrapper_pushwrapper(L, 1, m, LUPB_MSGDEF);
return 1;
}
@ -598,6 +594,11 @@ static const struct luaL_Reg lupb_filedef_m[] = {
/* lupb_symtab ****************************************************************/
/* The symtab owns all defs. Thus GC-rooting the symtab ensures that all
* underlying defs stay alive.
*
* The symtab's userval is a cache of def* -> object. */
typedef struct {
upb_symtab *symtab;
} lupb_symtab;
@ -610,11 +611,63 @@ upb_symtab *lupb_symtab_check(lua_State *L, int narg) {
return lsymtab->symtab;
}
void lupb_symtab_pushwrapper(lua_State *L, int narg, const void *def,
const char *type) {
if (def == NULL) {
lua_pushnil(L);
return;
}
lua_getuserval(L, narg); /* Get cache. */
/* Index by "def" pointer. */
lua_pushlightuserdata(L, (void*)def);
lua_rawget(L, -2)
/* Stack is now: cache, cached value. */
if (lua_isnil(L, -1)) {
/* Create new wrapper. */
lupb_wrapper *w = lua_newuserdata(L, sizeof(*w));
w->def = def;
lua_replace(L, -2); /* Replace nil */
/* Set metatable of wrapper. */
luaL_getmetatable(L, type);
lua_setmetatable(L, -2);
/* Add wrapper to the the cache. */
lua_pushlightuserdata(L, (void*)def);
lua_pushvalue(L, -2);
lua_rawset(L, -4);
}
lua_replace(L, -2); /* Remove cache, leaving only the wrapper. */
}
/* upb_symtab_new()
*
* Handles:
* upb.SymbolTable() -> <new instance>
*/
static int lupb_symtab_new(lua_State *L) {
lupb_symtab *lsymtab = lua_newuserdata(L, sizeof(*lsymtab));
lsymtab->symtab = upb_symtab_new();
luaL_getmetatable(L, LUPB_SYMTAB);
lua_setmetatable(L, -2);
/* Create our object cache. */
lua_newtable(L);
/* Cache metatable: specifies that values are weak. */
lua_createtable(L, 0, 1);
lua_pushstring(L, "v");
lua_setfield(L, -2, "__mode");
lua_setmetatable(L, -2);
/* Set the cache as our userval. */
lua_setuservalue(L, -2);
return 1;
}
@ -625,9 +678,6 @@ static int lupb_symtab_gc(lua_State *L) {
return 0;
}
/* TODO(haberman): perhaps this should take a message object instead of a
* serialized string once we have a good story for vending compiled-in
* messages. */
static int lupb_symtab_add(lua_State *L) {
upb_arena *arena;
size_t i, n, len;
@ -635,8 +685,10 @@ static int lupb_symtab_add(lua_State *L) {
google_protobuf_FileDescriptorSet *set;
upb_symtab *s = lupb_symtab_check(L, 1);
const char *str = luaL_checklstring(L, 2, &len);
upb_status status;
lupb_arena_new(L);
upb_status_clear(&status);
arena = lupb_arena_check(L, -1);
set = google_protobuf_FileDescriptorSet_parse(str, len, arena);
@ -647,7 +699,8 @@ static int lupb_symtab_add(lua_State *L) {
files = google_protobuf_FileDescriptorSet_file(set, &n);
for (i = 0; i < n; i++) {
CHK(upb_symtab_addfile(s, files[i], &status));
upb_symtab_addfile(s, files[i], &status);
lupb_checkstatus(L, &status);
}
return 0;
@ -656,14 +709,14 @@ static int lupb_symtab_add(lua_State *L) {
static int lupb_symtab_lookupmsg(lua_State *L) {
const upb_symtab *s = lupb_symtab_check(L, 1);
const upb_msgdef *m = upb_symtab_lookupmsg(s, luaL_checkstring(L, 2));
lupb_msgdef_pushwrapper(L, m);
lupb_symtab_pushwrapper(L, 1, m, LUPB_MSGDEF);
return 1;
}
static int lupb_symtab_lookupenum(lua_State *L) {
const upb_symtab *s = lupb_symtab_check(L, 1);
const upb_enumdef *e = upb_symtab_lookupenum(s, luaL_checkstring(L, 2));
lupb_enumdef_pushwrapper(L, e);
lupb_symtab_pushwrapper(L, 1, e, LUPB_ENUMDEF);
return 1;
}
@ -694,7 +747,7 @@ static const struct luaL_Reg lupbdef_toplevel_m[] = {
void lupb_def_registertypes(lua_State *L) {
lupb_setfuncs(L, lupbdef_toplevel_m);
/* Refcounted types. */
/* Register types. */
lupb_register_type(L, LUPB_ENUMDEF, lupb_enumdef_m, lupb_enumdef_mm);
lupb_register_type(L, LUPB_FIELDDEF, lupb_fielddef_m, NULL);
lupb_register_type(L, LUPB_FILEDEF, lupb_filedef_m, NULL);
@ -702,14 +755,6 @@ void lupb_def_registertypes(lua_State *L) {
lupb_register_type(L, LUPB_ONEOFDEF, lupb_oneofdef_m, lupb_oneofdef_mm);
lupb_register_type(L, LUPB_SYMTAB, lupb_symtab_m, lupb_symtab_mm);
/* Create our object cache. */
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_setfield(L, LUA_REGISTRYINDEX, LUPB_OBJCACHE);
/* Register constants. */
lupb_setfieldi(L, "LABEL_OPTIONAL", UPB_LABEL_OPTIONAL);
lupb_setfieldi(L, "LABEL_REQUIRED", UPB_LABEL_REQUIRED);
@ -746,21 +791,6 @@ void lupb_def_registertypes(lua_State *L) {
lupb_setfieldi(L, "DESCRIPTOR_TYPE_SINT32", UPB_DESCRIPTOR_TYPE_SINT32);
lupb_setfieldi(L, "DESCRIPTOR_TYPE_SINT64", UPB_DESCRIPTOR_TYPE_SINT64);
lupb_setfieldi(L, "HANDLER_INT32", UPB_HANDLER_INT32);
lupb_setfieldi(L, "HANDLER_INT64", UPB_HANDLER_INT64);
lupb_setfieldi(L, "HANDLER_UINT32", UPB_HANDLER_UINT32);
lupb_setfieldi(L, "HANDLER_UINT64", UPB_HANDLER_UINT64);
lupb_setfieldi(L, "HANDLER_FLOAT", UPB_HANDLER_FLOAT);
lupb_setfieldi(L, "HANDLER_DOUBLE", UPB_HANDLER_DOUBLE);
lupb_setfieldi(L, "HANDLER_BOOL", UPB_HANDLER_BOOL);
lupb_setfieldi(L, "HANDLER_STARTSTR", UPB_HANDLER_STARTSTR);
lupb_setfieldi(L, "HANDLER_STRING", UPB_HANDLER_STRING);
lupb_setfieldi(L, "HANDLER_ENDSTR", UPB_HANDLER_ENDSTR);
lupb_setfieldi(L, "HANDLER_STARTSUBMSG", UPB_HANDLER_STARTSUBMSG);
lupb_setfieldi(L, "HANDLER_ENDSUBMSG", UPB_HANDLER_ENDSUBMSG);
lupb_setfieldi(L, "HANDLER_STARTSEQ", UPB_HANDLER_STARTSEQ);
lupb_setfieldi(L, "HANDLER_ENDSEQ", UPB_HANDLER_ENDSEQ);
lupb_setfieldi(L, "SYNTAX_PROTO2", UPB_SYNTAX_PROTO2);
lupb_setfieldi(L, "SYNTAX_PROTO3", UPB_SYNTAX_PROTO3);
}

@ -12,97 +12,109 @@
#include "lauxlib.h"
#include "upb/bindings/lua/upb.h"
#include "upb/handlers.h"
#include "upb/port_def.inc"
#include "upb/reflection.h"
#include "upb/port_def.inc"
/*
* Message/Array/Map objects can be constructed in one of two ways:
*
* 1. To point to existing msg/array/map data inside an arena.
* 2. To create and uniquely own some brand new data.
*
* Case (1) is for when we've parsed some data into an arena (which is faster
* than parsing directly into Lua objects) or when we're pointing at some
* read-only data (like custom options in a def).
*
* Case (2) is for when a user creates the object directly in Lua.
*
* We use the userval of container objects (Message/Array/Map) to store
* references to sub-objects (Strings/Messages/Arrays/Maps). But we need to
* keep the userval in sync with the underlying upb_msg/upb_array/upb_map.
* We populate the userval lazily from the underlying data.
*
* This means that no one may remove/replace any String/Message/Array/Map
* field/entry in the underlying upb_{msg,array,map} behind our back. It's ok
* for entries to be added or for primitives to be modified, but *replacing*
* sub-containers is not.
*
* Luckily parse/merge follow this rule. However clear does not, so it's not
* safe to clear behind our back.
* Message/Map/Array objects. These objects form a directed graph: a message
* can contain submessages, arrays, and maps, which can then point to other
* messages. This graph can technically be cyclic, though this is an error and
* a cyclic graph cannot be serialized. So it's better to think of this as a
* tree of objects.
*
* The actual data exists at the upb level (upb_msg, upb_map, upb_array),
* independently of Lua. The upb objects contain all the canonical data and
* edges between objects. Lua wrapper objects expose the upb objects to Lua,
* but ultimately they are just wrappers. They pass through all reads and
* writes to the underlying upb objects.
*
* Each upb object lives in a upb arena. We have a Lua object to wrap the upb
* arena, but arenas are never exposed to the user. The Lua arena object just
* serves to own the upb arena and free it at the proper time, once the Lua GC
* has determined that there are no more references to anything that lives in
* that arena. All wrapper objects strongly reference the arena to which they
* belong.
*
* A global object cache stores a mapping of C pointer (upb_msg*, upb_array*,
* upb_map*) to a corresponding Lua wrapper. These references are weak so that
* the wrappers can be collected if they are no longer needed. A new wrapper
* object can always be recreated later.
*
* arena
* +->group
* |
* V +-----+
* lupb_arena |cache|-weak-+
* | ^ +-----+ |
* | | V
* Lua level | +------------lupb_msg
* ----------------|-----------------|-------------------------------------------
* upb level | |
* | +----V------------------------------+
* +->upb_arena | upb_msg ...(empty arena storage) |
* +-----------------------------------+
*
* If the user creates a reference between two objects that have different
* arenas, we need to merge the arenas into a single, bigger arena group. The
* arena group will reference both arenas, and will inherit the longest lifetime
* of anything in the arena.
*
* arena
* +--------------------------->group<-----------------+
* | |
* V +-----+ V
* lupb_arena +-weak-|cache|-weak-+ lupb_arena
* | ^ | +-----+ | ^ |
* | | V V | |
* Lua level | +------------lupb_msg lupb_msg----+ |
* ----------------|-----------------|-------------------------|---------|-------
* upb level | | | |
* | +----V----+ +----V----+ V
* +->upb_arena | upb_msg | | upb_msg | upb_arena
* +------|--+ +--^------+
* +---------------------+
* Key invariants:
* 1. every wrapper references the arena that contains it.
* 2. every arena group references all arenas that own upb objects reachable
* from that arena. In other words, when a wrapper references an arena,
* this is sufficient to ensure that any upb object reachable from that
* wrapper will stay alive.
*
* Additionally, every message object contains a strong reference to the
* corresponding Descriptor object. Likewise, array/map objects reference a
* Descriptor object if they are typed to store message values.
*
* (The object cache could be per-arena-group. This would keep individual cache
* tables smaller, and when an arena group is freed the entire cache table could
* be collected in one fell swoop. However this makes merging another arena
* into the group an O(n) operation, since all entries would need to be copied
* from the existing cache table.)
*/
#define LUPB_ARENA "lupb.arena"
#define LUPB_MSGCLASS "lupb.msgclass"
#define LUPB_MSGFACTORY "lupb.msgfactory"
#define LUPB_ARRAY "lupb.array"
#define LUPB_MAP "lupb.map"
#define LUPB_MSG "lupb.msg"
#define LUPB_STRING "lupb.string"
static int lupb_msg_pushnew(lua_State *L, int narg);
/* Lazily creates the uservalue if it doesn't exist. */
static void lupb_getuservalue(lua_State *L, int index) {
lua_getuservalue(L, index);
if (lua_isnil(L, -1)) {
/* Lazily create and set userval. */
lua_pop(L, 1); /* nil. */
lua_pushvalue(L, index); /* userdata copy. */
lua_newtable(L);
lua_setuservalue(L, -2);
lua_pop(L, 1); /* userdata copy. */
lua_getuservalue(L, index);
static void lupb_msg_typecheck(lua_State *L, const upb_msgdef *expected,
const upb_msgdef *actual) {
if (expected != actual) {
luaL_error(L, "Message had incorrect type, expected '%s', got '%s'",
upb_msgdef_fullname(expected), upb_msgdef_fullname(actual));
}
assert(!lua_isnil(L, -1));
}
static void lupb_uservalseti(lua_State *L, int userdata, int index, int val) {
lupb_getuservalue(L, userdata);
lua_pushvalue(L, val);
lua_rawseti(L, -2, index);
lua_pop(L, 1); /* Uservalue. */
}
static void lupb_uservalgeti(lua_State *L, int userdata, int index) {
lupb_getuservalue(L, userdata);
lua_rawgeti(L, -1, index);
lua_insert(L, -2);
lua_pop(L, 1); /* Uservalue. */
}
/* Pushes a new userdata with the given metatable. */
static void *lupb_newuserdata(lua_State *L, size_t size, const char *type) {
void *ret = lua_newuserdata(L, size);
/* Set metatable. */
luaL_getmetatable(L, type);
UPB_ASSERT(!lua_isnil(L, -1)); /* Should have been created by luaopen_upb. */
lua_setmetatable(L, -2);
/* We don't set a uservalue here -- we lazily create it later if necessary. */
return ret;
}
/* lupb_arena *****************************************************************/
/* lupb_arena only exists to wrap a upb_arena. It is never exposed to users;
* it is an internal memory management detail. Other objects refer to this
* object from their userdata to keep the arena-owned data alive. */
/* lupb_arena only exists to wrap a upb_arena. It is never exposed to users; it
* is an internal memory management detail. Other wrapper objects refer to this
* object from their userdata to keep the arena-owned data alive.
*
* The arena contains a table that caches wrapper objects. */
typedef struct {
upb_arena *arena;
@ -135,7 +147,7 @@ upb_arena *lupb_arena_get(lua_State *L) {
lua_pushlightuserdata(L, &lupb_arena_cache_key);
lua_gettable(L, LUA_REGISTRYINDEX);
arena = lua_touserdata(L, -1);
UPB_ASSERT(arena);
assert(arena);
lua_pop(L, 1);
return arena;
@ -159,223 +171,6 @@ static const struct luaL_Reg lupb_arena_mm[] = {
};
/* lupb_msgfactory ************************************************************/
/* Userval contains a map of:
* [1] -> SymbolTable (to keep GC-reachable)
* [const upb_msgdef*] -> [lupb_msgclass userdata]
*/
#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_msgdef *md);
/* lupb_msgfactory helpers. */
static lupb_msgfactory *lupb_msgfactory_check(lua_State *L, int narg) {
return luaL_checkudata(L, narg, LUPB_MSGFACTORY);
}
static void lupb_msgfactory_pushmsgclass(lua_State *L, int narg,
const upb_msgdef *md) {
lupb_getuservalue(L, narg);
lua_pushlightuserdata(L, (void*)md);
lua_rawget(L, -2);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
/* TODO: verify md is in symtab? */
lupb_msgclass_pushnew(L, narg, md);
/* Set in userval. */
lua_pushlightuserdata(L, (void*)md);
lua_pushvalue(L, -2);
lua_rawset(L, -4);
}
}
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;
}
/* lupb_msgfactory Public API. */
/**
* lupb_msgfactory_new()
*
* Handles:
* msgfactory = upb.MessageFactory(symtab)
*
* Creates a new, empty MessageFactory for the given SymbolTable.
* Message classes will be created on demand when the user calls
* msgfactory.get_message_class().
*/
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;
}
/**
* lupb_msgfactory_getmsgclass()
*
* Handles:
* MessageClass = factory.get_message_class(message_name)
*/
static int lupb_msgfactory_getmsgclass(lua_State *L) {
lupb_msgfactory *lfactory = lupb_msgfactory_check(L, 1);
const upb_symtab *symtab = upb_msgfactory_symtab(lfactory->factory);
const upb_msgdef *m = upb_symtab_lookupmsg(symtab, luaL_checkstring(L, 2));
if (!m) {
luaL_error(L, "No such message type: %s\n", lua_tostring(L, 2));
}
lupb_msgfactory_pushmsgclass(L, 1, m);
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 **************************************************************/
/* Userval contains a map of:
* [1] -> MessageFactory (to keep GC-reachable)
* [const upb_msgdef*] -> [lupb_msgclass userdata]
*/
#define LUPB_MSGCLASS_FACTORY 1
struct lupb_msgclass {
const upb_msglayout *layout;
const upb_msgdef *msgdef;
};
/* 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);
const lupb_msgclass *lupb_msgclass_check(lua_State *L, int narg) {
return luaL_checkudata(L, narg, LUPB_MSGCLASS);
}
const upb_msglayout *lupb_msgclass_getlayout(lua_State *L, int narg) {
return lupb_msgclass_check(L, narg)->layout;
}
const upb_msgdef *lupb_msgclass_getmsgdef(const lupb_msgclass *lmsgclass) {
return lmsgclass->msgdef;
}
/**
* lupb_msgclass_typecheck()
*
* Verifies that the expected msgclass matches the actual. If not, raises a Lua
* error.
*/
static void lupb_msgclass_typecheck(lua_State *L, const lupb_msgclass *expected,
const lupb_msgclass *actual) {
if (expected != actual) {
luaL_error(L, "Message had incorrect type, expected '%s', got '%s'",
upb_msgdef_fullname(expected->msgdef),
upb_msgdef_fullname(actual->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);
}
/**
* lupb_msgclass_getsubmsgclass()
*
* Given a MessageClass at index |narg| and the submessage field |f|, returns
* the message class for this field.
*
* Currently we do a hash table lookup for this. 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. */
static const lupb_msgclass *lupb_msgclass_getsubmsgclass(lua_State *L, int narg,
const upb_fielddef *f) {
if (upb_fielddef_type(f) != UPB_TYPE_MESSAGE) {
return NULL;
}
return lupb_msgclass_msgclassfor(L, narg, upb_fielddef_msgsubdef(f));
}
static int lupb_msgclass_pushnew(lua_State *L, int factory,
const upb_msgdef *md) {
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 = upb_msgfactory_getlayout(lfactory->factory, md);
lmc->msgdef = md;
return 1;
}
/* MessageClass Public API. */
/**
* lupb_msgclass_call()
*
* Handles:
* msg = MessageClass()
*
* Creates a new message from the given MessageClass.
*/
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}
};
/* upb <-> Lua type conversion ************************************************/
static bool lupb_istypewrapped(upb_fieldtype_t type) {
@ -384,7 +179,7 @@ static bool lupb_istypewrapped(upb_fieldtype_t type) {
}
static upb_msgval lupb_tomsgval(lua_State *L, upb_fieldtype_t type, int narg,
const lupb_msgclass *lmsgclass) {
const upb_msgdef *msgdef) {
upb_msgval ret;
switch (type) {
case UPB_TYPE_INT32:
@ -417,8 +212,8 @@ static upb_msgval lupb_tomsgval(lua_State *L, upb_fieldtype_t type, int narg,
break;
}
case UPB_TYPE_MESSAGE:
UPB_ASSERT(lmsgclass);
ret.msg_val = lupb_msg_checkmsg(L, narg, lmsgclass);
assert(msgdef);
ret.msg_val = lupb_msg_checkmsg(L, narg, msgdef);
break;
}
return ret;
@ -454,7 +249,7 @@ static void lupb_pushmsgval(lua_State *L, upb_fieldtype_t type,
case UPB_TYPE_MESSAGE:
break; /* Shouldn't call this function. */
}
UPB_UNREACHABLE();
LUPB_UNREACHABLE();
}
@ -470,17 +265,18 @@ static void lupb_pushmsgval(lua_State *L, upb_fieldtype_t type,
* For string/submessage entries we keep in the userval:
*
* [number index] -> [lupb_string/lupb_msg userdata]
*
* Additionally, for message-typed arrays we keep:
*
* [ARRAY_MSGDEF_INDEX] -> [SymbolTable] (to keep msgdef GC-reachable)
*/
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. */
const lupb_msgclass *lmsgclass;
upb_array *arr;
upb_fieldtype_t type;
} lupb_array;
#define ARRAY_MSGCLASS_INDEX 0
#define ARRAY_MSGDEF_INDEX 1
static lupb_array *lupb_array_check(lua_State *L, int narg) {
return luaL_checkudata(L, narg, LUPB_ARRAY);
@ -498,15 +294,13 @@ static upb_msgval lupb_array_typecheck(lua_State *L, int narg, int msg,
lupb_array *larray = lupb_array_check(L, narg);
upb_msgval val;
if (larray->type != upb_fielddef_type(f) ||
lupb_msg_getsubmsgclass(L, msg, f) != larray->lmsgclass) {
if (larray->type != upb_fielddef_type(f)) {
luaL_error(L, "Array had incorrect type (expected: %d, got: %d)",
(int)upb_fielddef_type(f), (int)larray->type);
}
if (larray->type == UPB_TYPE_MESSAGE) {
lupb_msgclass_typecheck(L, lupb_msg_getsubmsgclass(L, msg, f),
larray->lmsgclass);
lupb_msgdef_typecheck(L, upb_fielddef_msgsubdef(f), larray->msgdef);
}
val.array_val = larray->arr;
@ -531,35 +325,54 @@ static int lupb_array_checkindex(lua_State *L, int narg, uint32_t max) {
return n - 1; /* Lua uses 1-based indexing. :( */
}
static void lupb_array_push(lua_State *L, upb_array *a, const upb_fielddef *f) {
}
/* lupb_array Public API */
/* lupb_array_new():
*
* Handles:
* Array(upb.TYPE_INT32)
* Array(message_type)
*/
static int lupb_array_new(lua_State *L) {
lupb_array *larray;
upb_fieldtype_t type;
const lupb_msgclass *lmsgclass = NULL;
int n = 1;
lupb_arena_new(); /* Userval 1. */
if (lua_type(L, 1) == LUA_TNUMBER) {
type = lupb_checkfieldtype(L, 1);
} else {
lupb_msgdef_check(L, 1);
type = UPB_TYPE_MESSAGE;
lmsgclass = lupb_msgclass_check(L, 1);
lupb_uservalseti(L, -1, ARRAY_MSGCLASS_INDEX, 1); /* GC-root lmsgclass. */
n = 2;
lua_push(L, 1); /* Userval 2. */
}
larray = lupb_newuserdata(L, sizeof(*larray), LUPB_ARRAY);
larray = lupb_newuserdata(L, sizeof(*larray), n, LUPB_ARRAY);
larray->type = type;
larray->lmsgclass = lmsgclass;
larray->arr = upb_array_new(lupb_arena_get(L), type);
return 1;
}
/* lupb_array_newindex():
*
* Handles:
* array[idx] = val
*
* idx can be within the array or one past the end to extend.
*/
static int lupb_array_newindex(lua_State *L) {
lupb_array *larray = lupb_array_check(L, 1);
size_t size = upb_array_size(larray->arr);
upb_fieldtype_t type = larray->type;
uint32_t n = lupb_array_checkindex(L, 2, size + 1);
upb_msgval msgval = lupb_tomsgval(L, type, 3, larray->lmsgclass);
upb_msgval msgval = lupb_tomsgval(L, type, 3, larray->msgdef);
if (n == size) {
upb_array_append(larray->arr, msgval, lupb_arena_get(L));
@ -574,6 +387,13 @@ static int lupb_array_newindex(lua_State *L) {
return 0; /* 1 for chained assignments? */
}
/* lupb_array_index():
*
* Handles:
* array[idx] -> val
*
* idx must be within the array.
*/
static int lupb_array_index(lua_State *L) {
lupb_array *larray = lupb_array_check(L, 1);
size_t size = upb_array_size(larray->arr);
@ -590,6 +410,11 @@ static int lupb_array_index(lua_State *L) {
return 1;
}
/* lupb_array_len():
*
* Handles:
* #array -> len
*/
static int lupb_array_len(lua_State *L) {
lupb_array *larray = lupb_array_check(L, 1);
lua_pushnumber(L, upb_array_size(larray->arr));
@ -612,17 +437,20 @@ static const struct luaL_Reg lupb_array_mm[] = {
*
* [Lua number/string] -> [lupb_string/lupb_msg userdata]
*
* Additionally when the map is message, we store:
*
* [MAP_MSGDEF_INDEX] -> MessageDef
*
* For other value types we don't use the userdata.
*/
typedef struct {
const lupb_msgclass *value_lmsgclass;
upb_map *map;
upb_fieldtype_t key_type;
upb_fieldtype_t value_type;
upb_map *map;
} lupb_map;
#define MAP_MSGCLASS_INDEX 0
#define MAP_MSGDEF_INDEX 1
/* lupb_map internal functions */
@ -640,13 +468,12 @@ static lupb_map *lupb_map_check(lua_State *L, int 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 = lmap->map;
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_msgval val;
UPB_ASSERT(entry && key_field && value_field);
assert(entry && key_field && value_field);
if (lmap->key_type != upb_fielddef_type(key_field)) {
luaL_error(L, "Map had incorrect field type (expected: %s, got: %s)",
@ -659,12 +486,15 @@ static upb_msgval lupb_map_typecheck(lua_State *L, int narg, int msg,
}
if (lmap->value_type == UPB_TYPE_MESSAGE) {
lupb_uservalgeti(L, narg, MAP_MSGDEF_INDEX);
lupb_wrapper_pushwrapper(L
lupb_msgclass_typecheck(
L, lupb_msg_msgclassfor(L, msg, upb_fielddef_msgsubdef(value_field)),
lmap->value_lmsgclass);
}
val.map_val = map;
val.map_val = lmap->map;
return val;
}
@ -675,12 +505,12 @@ static upb_msgval lupb_map_typecheck(lua_State *L, int narg, int msg,
*
* Handles:
* new_map = upb.Map(key_type, value_type)
* new_map = upb.Map(key_type, value_msgdef)
*/
static int lupb_map_new(lua_State *L) {
lupb_map *lmap;
upb_fieldtype_t key_type = lupb_checkfieldtype(L, 1);
upb_fieldtype_t value_type;
const lupb_msgclass *value_lmsgclass = NULL;
if (lua_type(L, 2) == LUA_TNUMBER) {
value_type = lupb_checkfieldtype(L, 2);
@ -692,12 +522,11 @@ static int lupb_map_new(lua_State *L) {
if (value_type == UPB_TYPE_MESSAGE) {
value_lmsgclass = lupb_msgclass_check(L, 2);
lupb_uservalseti(L, -1, MAP_MSGCLASS_INDEX, 2); /* GC-root lmsgclass. */
lupb_uservalseti(L, -1, MAP_MSGDEF_INDEX, 2); /* GC-root lmsgclass. */
}
lmap->key_type = key_type;
lmap->value_type = value_type;
lmap->value_lmsgclass = value_lmsgclass;
lmap->map = upb_map_new(lupb_arena_get(L), key_type, value_type);
return 1;
@ -776,8 +605,7 @@ static int lupb_map_newindex(lua_State *L) {
}
} else {
/* Set in map. */
upb_msgval val =
lupb_tomsgval(L, lmap->value_type, 3, lmap->value_lmsgclass);
upb_msgval val = lupb_tomsgval(L, lmap->value_type, 3, lmap->msgdef);
upb_map_set(map, key, val, lupb_arena_get(L));
@ -852,22 +680,18 @@ static const struct luaL_Reg lupb_map_mm[] = {
*
* Our userval contains:
*
* - [0] -> our message class
* - [lupb_fieldindex(f)] -> [lupb_{string,array,map,msg} userdata]
* - [MSG_MSGDEF_INDEX] -> our message class
*
* Fields with scalar number/bool types don't go in the userval.
*/
#define LUPB_MSG_MSGCLASSINDEX 0
#define LUPB_MSG_ARENA -1
#define MSG_MSGDEF_INDEX 1
int lupb_fieldindex(const upb_fielddef *f) {
return upb_fielddef_index(f) + 1; /* 1-based Lua arrays. */
}
typedef struct {
const lupb_msgclass *lmsgclass;
upb_msg *msg;
} lupb_msg;
@ -878,15 +702,16 @@ static bool in_userval(const upb_fielddef *f) {
upb_fielddef_ismap(f);
}
lupb_msg *lupb_msg_check(lua_State *L, int narg) {
upb_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;
if (!msg->msg) luaL_error(L, "called into dead msg");
return msg->msg;
}
const upb_msg *lupb_msg_checkmsg(lua_State *L, int narg,
const lupb_msgclass *lmsgclass) {
lupb_msg *lmsg = lupb_msg_check(L, narg);
const upb_msgdef *msgdef) {
lupb_msg_check(L, narg);
lupb_uservalgeti
lupb_msgclass_typecheck(L, lmsgclass, lmsg->lmsgclass);
return lmsg->msg;
}
@ -898,10 +723,6 @@ upb_msg *lupb_msg_checkmsg2(lua_State *L, int narg,
return lmsg->msg;
}
const upb_msgdef *lupb_msg_checkdef(lua_State *L, int narg) {
return lupb_msg_check(L, narg)->lmsgclass->msgdef;
}
static const upb_fielddef *lupb_msg_checkfield(lua_State *L,
const lupb_msg *msg,
int fieldarg) {
@ -919,31 +740,6 @@ static const upb_fielddef *lupb_msg_checkfield(lua_State *L,
return f;
}
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);
}
int lupb_msg_pushref(lua_State *L, int msgclass, upb_msg *msg) {
const lupb_msgclass *lmsgclass = lupb_msgclass_check(L, msgclass);
lupb_msg *lmsg = lupb_newuserdata(L, sizeof(lupb_msg), LUPB_MSG);
lmsg->lmsgclass = lmsgclass;
lmsg->msg = msg;
lupb_uservalseti(L, -1, LUPB_MSG_MSGCLASSINDEX, msgclass);
lupb_uservalseti(L, -1, LUPB_MSG_ARENA, -2);
return 1;
}
/* lupb_msg Public API */
/**
@ -973,9 +769,8 @@ static int lupb_msg_pushnew(lua_State *L, int narg) {
* msg[field_descriptor] # (for extensions) (TODO)
*/
static int lupb_msg_index(lua_State *L) {
lupb_msg *lmsg = lupb_msg_check(L, 1);
upb_msg *msg = lupb_msg_check(L, 1);
const upb_fielddef *f = lupb_msg_checkfield(L, lmsg, 2);
const upb_msglayout *l = lmsg->lmsgclass->layout;
if (in_userval(f)) {
lupb_uservalgeti(L, 1, lupb_fieldindex(f));
@ -987,9 +782,9 @@ static int lupb_msg_index(lua_State *L) {
} else if (upb_fielddef_issubmsg(f)) {
/* TODO(haberman) */
} else {
UPB_ASSERT(upb_fielddef_isstring(f));
if (upb_msg_has(lmsg->msg, f, l)) {
upb_msgval val = upb_msg_get(lmsg->msg, f, l);
assert(upb_fielddef_isstring(f));
if (upb_msg_has(msg, f)) {
upb_msgval val = upb_msg_get(msg, f);
lua_pop(L, 1);
lua_pushlstring(L, val.str_val.data, val.str_val.size);
lupb_uservalseti(L, 1, lupb_fieldindex(f), -1);
@ -997,7 +792,7 @@ static int lupb_msg_index(lua_State *L) {
}
}
} else {
upb_msgval val = upb_msg_get(lmsg->msg, f, l);
upb_msgval val = upb_msg_get(msg, f);
lupb_pushmsgval(L, upb_fielddef_type(f), val);
}
@ -1013,11 +808,10 @@ static int lupb_msg_index(lua_State *L) {
* msg[field_descriptor] = bar # (for extensions) (TODO)
*/
static int lupb_msg_newindex(lua_State *L) {
lupb_msg *lmsg = lupb_msg_check(L, 1);
upb_msg *msg = lupb_msg_check(L, 1);
const upb_fielddef *f = lupb_msg_checkfield(L, lmsg, 2);
upb_fieldtype_t type = upb_fielddef_type(f);
upb_arena *arena = lupb_arena_get(L);
const upb_msglayout *layout = lmsg->lmsgclass->layout;
upb_msgval msgval;
/* Typecheck and get msgval. */
@ -1027,18 +821,14 @@ static int lupb_msg_newindex(lua_State *L) {
} else if (upb_fielddef_ismap(f)) {
msgval = lupb_map_typecheck(L, 3, 1, f);
} else {
const lupb_msgclass *lmsgclass = NULL;
if (type == UPB_TYPE_MESSAGE) {
lmsgclass = lupb_msg_getsubmsgclass(L, 1, f);
}
msgval = lupb_tomsgval(L, type, 3, lmsgclass);
const upb_msgdef *msgdef =
type == UPB_TYPE_MESSAGE ? upb_fielddef_msgsubdef(f) : NULL;
msgval = lupb_tomsgval(L, type, 3, msgdef);
}
/* Set in upb_msg and userval (if necessary). */
upb_msg_set(lmsg->msg, f, msgval, layout, arena);
upb_msg_set(msg, f, msgval, arena);
if (in_userval(f)) {
lupb_uservalseti(L, 1, lupb_fieldindex(f), 3);
@ -1056,10 +846,41 @@ static const struct luaL_Reg lupb_msg_mm[] = {
/* lupb_msg toplevel **********************************************************/
static int lupb_decode(lua_State *L) {
size_t len;
const upb_msglayout *layout;
upb_msg *msg = lupb_msg_checkmsg2(L, 1, &layout);
const char *pb = lua_tolstring(L, 2, &len);
upb_decode(pb, len, msg, layout, lupb_arena_get(L));
/* TODO(haberman): check for error. */
return 0;
}
static int lupb_encode(lua_State *L) {
const upb_msglayout *layout;
const upb_msg *msg = lupb_msg_checkmsg2(L, 1, &layout);
upb_arena *arena = upb_arena_new();
size_t size;
char *result;
result = upb_encode(msg, (const void*)layout, arena, &size);
/* Free resources before we potentially bail on error. */
lua_pushlstring(L, result, size);
upb_arena_free(arena);
/* TODO(haberman): check for error. */
return 1;
}
static const struct luaL_Reg lupb_msg_toplevel_m[] = {
{"Array", lupb_array_new},
{"Map", lupb_map_new},
{"MessageFactory", lupb_msgfactory_new},
{"decode", lupb_decode},
{"encode", lupb_encode},
{NULL, NULL}
};

@ -20,16 +20,16 @@
** domain of [u]int64 values.
*/
#include "upb/bindings/lua/upb.h"
#include <float.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "lauxlib.h"
#include "upb/bindings/lua/upb.h"
#include "upb/handlers.h"
#include "upb/msg.h"
/* Lua compatibility code *****************************************************/
/* Lua 5.1 and Lua 5.2 have slightly incompatible APIs. A little bit of
@ -53,10 +53,6 @@ void *luaL_testudata(lua_State *L, int ud, const char *tname) {
return NULL; /* value is not a userdata with a metatable */
}
static void lupb_newlib(lua_State *L, const char *name, const luaL_Reg *funcs) {
luaL_register(L, name, funcs);
}
#elif LUA_VERSION_NUM == 502
int luaL_typerror(lua_State *L, int narg, const char *tname) {
@ -65,17 +61,6 @@ int luaL_typerror(lua_State *L, int narg, const char *tname) {
return luaL_argerror(L, narg, msg);
}
static void lupb_newlib(lua_State *L, const char *name, const luaL_Reg *funcs) {
/* Lua 5.2 modules are not expected to set a global variable, so "name" is
* unused. */
UPB_UNUSED(name);
/* Can't use luaL_newlib(), because funcs is not the actual array.
* Could (micro-)optimize this a bit to count funcs for initial table size. */
lua_createtable(L, 0, 8);
luaL_setfuncs(L, funcs, 0);
}
#else
#error Only Lua 5.1 and 5.2 are supported
#endif
@ -90,28 +75,6 @@ bool lua_isinteger(lua_State *L, int argn) {
/* Utility functions **********************************************************/
/* We store our module table in the registry, keyed by ptr.
* For more info about the motivation/rationale, see this thread:
* http://thread.gmane.org/gmane.comp.lang.lua.general/110632 */
bool lupb_openlib(lua_State *L, void *ptr, const char *name,
const luaL_Reg *funcs) {
/* Lookup cached module table. */
lua_pushlightuserdata(L, ptr);
lua_rawget(L, LUA_REGISTRYINDEX);
if (!lua_isnil(L, -1)) {
return true;
}
lupb_newlib(L, name, funcs);
/* Save module table in cache. */
lua_pushlightuserdata(L, ptr);
lua_pushvalue(L, -2);
lua_rawset(L, LUA_REGISTRYINDEX);
return false;
}
void lupb_checkstatus(lua_State *L, upb_status *s) {
if (!upb_ok(s)) {
lua_pushstring(L, upb_status_errmsg(s));
@ -119,6 +82,20 @@ void lupb_checkstatus(lua_State *L, upb_status *s) {
}
}
/* Pushes a new userdata with the given metatable. */
static void *lupb_newuserdata(lua_State *L, size_t size, const char *type) {
void *ret = lua_newuserdata(L, size);
/* Set metatable. */
luaL_getmetatable(L, type);
assert(!lua_isnil(L, -1)); /* Should have been created by luaopen_upb. */
lua_setmetatable(L, -2);
/* We don't set a uservalue here -- we lazily create it later if necessary. */
return ret;
}
/* Scalar type mapping ********************************************************/
/* Functions that convert scalar/primitive values (numbers, strings, bool)
@ -205,10 +182,6 @@ void lupb_pushfloat(lua_State *L, float d) {
}
static const struct luaL_Reg lupb_toplevel_m[] = {
{NULL, NULL}
};
void lupb_register_type(lua_State *L, const char *name, const luaL_Reg *m,
const luaL_Reg *mm) {
luaL_newmetatable(L, name);
@ -233,13 +206,13 @@ void lupb_register_type(lua_State *L, const char *name, const luaL_Reg *m,
}
int luaopen_upb_c(lua_State *L) {
static char module_key;
if (lupb_openlib(L, &module_key, "upb_c", lupb_toplevel_m)) {
return 1;
}
#if LUA_VERSION == 501
const struct luaL_Reg funcs[] = {{NULL, NULL}};
luaL_register(L, "upb_c", funcs);
#else
lua_createtable(L, 0, 8);
#endif
lupb_def_registertypes(L);
lupb_msg_registertypes(L);
return 1; /* Return package table. */
}

@ -7,65 +7,51 @@
#include "lauxlib.h"
#include "upb/def.h"
#include "upb/handlers.h"
#include "upb/msg.h"
#include "upb/msgfactory.h"
/* Lua 5.1/5.2 compatibility code. */
/* Lua changes its API in incompatible ways in every minor release.
* This is some shim code to paper over the differences. */
#if LUA_VERSION_NUM == 501
#define lua_rawlen lua_objlen
/* Lua >= 5.2's getuservalue/setuservalue functions do not exist in prior
* versions but the older function lua_getfenv() can provide 100% of its
* capabilities (the reverse is not true). */
#define lua_getuservalue(L, index) lua_getfenv(L, index)
#define lua_setuservalue(L, index) lua_setfenv(L, index)
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
#elif LUA_VERSION_NUM >= 502 && LUA_VERSION_NUM <= 504
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
#error Only Lua 5.1-5.4 are supported
#endif
#define lupb_assert(L, predicate) \
if (!(predicate)) \
luaL_error(L, "internal error: %s, %s:%d ", #predicate, __FILE__, __LINE__);
/* Create a new userdata with the given type and |n| uservals, which are popped
* from the stack to initialize the userdata. */
void *lupb_newuserdata(lua_State *L, size_t size, int n, const char *type);
/* Function for initializing the core library. This function is idempotent,
* and should be called at least once before calling any of the functions that
* construct core upb types. */
int luaopen_upb(lua_State *L);
/* Gets or creates a package table for a C module that is uniquely identified by
* "ptr". The easiest way to supply a unique "ptr" is to pass the address of a
* static variable private in the module's .c file.
*
* If this module has already been registered in this lua_State, pushes it and
* returns true.
*
* Otherwise, creates a new module table for this module with the given name,
* pushes it, and registers the given top-level functions in it. It also sets
* it as a global variable, but only if the current version of Lua expects that
* (ie Lua 5.1/LuaJIT).
*
* If "false" is returned, the caller is guaranteed that this lib has not been
* registered in this Lua state before (regardless of any funny business the
* user might have done to the global state), so the caller can safely perform
* one-time initialization. */
bool lupb_openlib(lua_State *L, void *ptr, const char *name,
const luaL_Reg *funcs);
#if LUA_VERSION_NUM < 504
/* Polyfills for this Lua 5.4 function. Pushes userval |n| for the userdata at
* |index|. */
int lua_getiuservalue(lua_State *L, int index, int n);
#endif
/* Registers a type with the given name, methods, and metamethods. */
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);
/* C <-> Lua value conversions. ***********************************************/
/* Custom check/push functions. Unlike the Lua equivalents, they are pinned to
* specific types (instead of lua_Number, etc), and do not allow any implicit
* specific C types (instead of lua_Number, etc), and do not allow any implicit
* conversion or data loss. */
int64_t lupb_checkint64(lua_State *L, int narg);
int32_t lupb_checkint32(lua_State *L, int narg);
@ -84,13 +70,6 @@ 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);
/* Registers a type with the given name, methods, and metamethods. */
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. ***************************************************************/
@ -106,21 +85,25 @@ void lupb_def_registertypes(lua_State *L);
/** 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);
upb_arena *lupb_arena_get(lua_State *L);
int lupb_msg_pushref(lua_State *L, int msgclass, void *msg);
const upb_msg *lupb_msg_checkmsg(lua_State *L, int narg,
const lupb_msgclass *lmsgclass);
const upb_msgdef *msgdef);
upb_msg *lupb_msg_checkmsg2(lua_State *L, int narg,
const upb_msglayout **layout);
const lupb_msgclass *lupb_msgclass_check(lua_State *L, int narg);
const upb_msglayout *lupb_msgclass_getlayout(lua_State *L, int narg);
const upb_msgdef *lupb_msgclass_getmsgdef(const lupb_msgclass *lmsgclass);
void lupb_msg_registertypes(lua_State *L);
#define lupb_assert(L, predicate) \
if (!(predicate)) \
luaL_error(L, "internal error: %s, %s:%d ", #predicate, __FILE__, __LINE__);
#if defined(__GNUC__) || defined(__clang__)
#define LUPB_UNREACHABLE() do { assert(0); __builtin_unreachable(); } while(0)
#else
#define LUPB_UNREACHABLE() do { assert(0); } while(0)
#endif
#endif /* UPB_LUA_UPB_H_ */

@ -1,56 +0,0 @@
/*
** require("upb.pb") -- A Lua extension for upb.pb.
**
** Exposes all the types defined in upb/pb/{*}.h
** Also defines a few convenience functions on top.
*/
#include "upb/bindings/lua/upb.h"
#include "upb/decode.h"
#include "upb/encode.h"
#define LUPB_PBDECODERMETHOD "lupb.pb.decodermethod"
static int lupb_pb_decode(lua_State *L) {
size_t len;
const upb_msglayout *layout;
upb_msg *msg = lupb_msg_checkmsg2(L, 1, &layout);
const char *pb = lua_tolstring(L, 2, &len);
upb_decode(pb, len, msg, layout, lupb_arena_get(L));
/* TODO(haberman): check for error. */
return 0;
}
static int lupb_pb_encode(lua_State *L) {
const upb_msglayout *layout;
const upb_msg *msg = lupb_msg_checkmsg2(L, 1, &layout);
upb_arena *arena = upb_arena_new();
size_t size;
char *result;
result = upb_encode(msg, (const void*)layout, arena, &size);
/* Free resources before we potentially bail on error. */
lua_pushlstring(L, result, size);
upb_arena_free(arena);
/* TODO(haberman): check for error. */
return 1;
}
static const struct luaL_Reg toplevel_m[] = {
{"decode", lupb_pb_decode},
{"encode", lupb_pb_encode},
{NULL, NULL}
};
int luaopen_upb_pb_c(lua_State *L) {
static char module_key;
if (lupb_openlib(L, &module_key, "upb.pb_c", toplevel_m)) {
return 1;
}
return 1;
}

@ -1,3 +0,0 @@
require "upb"
return require "upb.pb_c"

@ -30,35 +30,34 @@ typedef union {
/** upb_msg *******************************************************************/
/* Creates a new message of the given type in the given arena. */
upb_msg *upb_msg_new(const upb_msgdef *m, upb_arena *a);
/* Returns the value associated with this field. */
upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f,
const upb_msglayout *l);
upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f);
/* Returns a mutable pointer to a map, array, or submessage value, constructing
* a new object if it was not previously present. May not be called for
* primitive fields. */
upb_mutmsgval upb_msg_mutable(upb_msg *msg, const upb_fielddef *f,
const upb_msglayout *l, upb_arena *a);
upb_mutmsgval upb_msg_mutable(upb_msg *msg, const upb_fielddef *f, upb_arena *a);
/* 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);
bool upb_msg_has(const upb_msg *msg, const upb_fielddef *f);
/* Sets the given field to the given value. For a msg/array/map/string, the
* value must be in the same arena. */
void upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val,
const upb_msglayout *l, upb_arena *a);
upb_arena *a);
/* Clears any field presence and sets the value back to its default. */
void upb_msg_clearfield(upb_msg *msg, const upb_fielddef *f,
const upb_msglayout *l);
void upb_msg_clearfield(upb_msg *msg, const upb_fielddef *f);
/** upb_array *****************************************************************/
/* Returns the size of the array. */
size_t upb_array_size(const upb_array *arr);
/* Returns the given element. */
/* Returns the given element, which must be within the array's current size. */
upb_msgval upb_array_get(const upb_array *arr, size_t i);
/* Sets the given element, which must be within the array's current size. */

Loading…
Cancel
Save