More progress on Lua extension.

pull/13171/head
Joshua Haberman 5 years ago
parent d6c3152c0b
commit 4c57b1fefd
  1. 33
      BUILD
  2. 10
      tests/bindings/lua/main.c
  3. 372
      tests/bindings/lua/test_upb.lua
  4. 11
      tools/make_cmakelists.py
  5. 59
      upb/bindings/lua/def.c
  6. 57
      upb/bindings/lua/msg.c
  7. 7
      upb/decode.c
  8. 8
      upb/def.c
  9. 188
      upb/encode.c
  10. 6
      upb/msg.h
  11. 6
      upb/reflection.c
  12. 4
      upbc/generator.cc

33
BUILD

@ -10,6 +10,10 @@ load(
"upb_proto_library",
"upb_proto_reflection_library",
)
load(
"//:upb/bindings/lua/lua_proto_library.bzl",
"lua_proto_library",
)
licenses(["notice"]) # BSD (Google-authored w/ possible external contributions)
@ -585,9 +589,12 @@ cc_test(
data = [
"@com_google_protobuf//:conformance_proto",
"@com_google_protobuf//:descriptor_proto",
":descriptor_proto_lua",
":test_messages_proto3_proto_lua",
"tests/bindings/lua/test_upb.lua",
"third_party/lunit/console.lua",
"third_party/lunit/lunit.lua",
"upb/bindings/lua/upb.lua",
],
deps = [
":lupb",
@ -595,6 +602,32 @@ cc_test(
]
)
cc_binary(
name = "protoc-gen-lua",
srcs = ["upb/bindings/lua/upbc.cc"],
copts = select({
":windows": [],
"//conditions:default": CPPOPTS
}),
visibility = ["//visibility:public"],
deps = [
"@absl//absl/strings",
"@com_google_protobuf//:protoc_lib"
],
)
lua_proto_library(
name = "descriptor_proto_lua",
visibility = ["//visibility:public"],
deps = ["@com_google_protobuf//:descriptor_proto"],
)
lua_proto_library(
name = "test_messages_proto3_proto_lua",
testonly = 1,
deps = ["@com_google_protobuf//:test_messages_proto3_proto"],
)
# Test the CMake build #########################################################
filegroup(

@ -22,7 +22,15 @@ static void sighandler(int i) {
const char *init =
"package.preload['lupb'] = ... "
"package.path = './?.lua;./third_party/lunit/?.lua'";
"package.path = '"
"./?.lua;"
"./third_party/lunit/?.lua;"
"external/com_google_protobuf/?.lua;"
"external/com_google_protobuf/src/?.lua;"
"bazel-bin/external/com_google_protobuf/src/?.lua;"
"bazel-bin/external/com_google_protobuf/?.lua;"
"upb/bindings/lua/?.lua"
"'";
int main() {
int ret = 0;

@ -1,6 +1,8 @@
local upb = require "lupb"
local lunit = require "lunit"
local test_messages_proto3 = require "google.protobuf.test_messages_proto3_pb"
local descriptor = require "google.protobuf.descriptor_pb"
if _VERSION >= 'Lua 5.2' then
_ENV = lunit.module("testupb", "seeall")
@ -16,227 +18,34 @@ function iter_to_array(iter)
return arr
end
--[[
function test_msgdef()
local f2 = upb.FieldDef{name = "field2", number = 1, type = upb.TYPE_INT32}
local o = upb.OneofDef{name = "field1", fields = {f2}}
local f = upb.FieldDef{name = "field3", number = 2, type = upb.TYPE_INT32}
local m = upb.MessageDef{fields = {o, f}}
assert_equal(f, m:lookup_name("field3"))
assert_equal(o, m:lookup_name("field1"))
assert_equal(f2, m:lookup_name("field2"))
end
function test_fielddef()
local f = upb.FieldDef()
assert_false(f:is_frozen())
assert_nil(f:number())
assert_nil(f:name())
assert_nil(f:type())
function test_def_readers()
local m = test_messages_proto3.TestAllTypesProto3
assert_equal("TestAllTypesProto3", m:name())
assert_equal("protobuf_test_messages.proto3.TestAllTypesProto3", m:full_name())
-- field
local f = m:field("optional_int32")
local f2 = m:field(1)
assert_equal(f, f2)
assert_equal(1, f:number())
assert_equal("optional_int32", f:name())
assert_equal(upb.LABEL_OPTIONAL, f:label())
f:set_name("foo_field")
f:set_number(3)
f:set_label(upb.LABEL_REPEATED)
f:set_type(upb.TYPE_FLOAT)
assert_equal("foo_field", f:name())
assert_equal(3, f:number())
assert_equal(upb.LABEL_REPEATED, f:label())
assert_equal(upb.TYPE_FLOAT, f:type())
local f2 = upb.FieldDef{
name = "foo", number = 5, type = upb.TYPE_DOUBLE, label = upb.LABEL_REQUIRED
}
assert_equal("foo", f2:name())
assert_equal(5, f2:number())
assert_equal(upb.TYPE_DOUBLE, f2:type())
assert_equal(upb.LABEL_REQUIRED, f2:label())
assert_equal(upb.DESCRIPTOR_TYPE_INT32, f:descriptor_type())
assert_equal(upb.TYPE_INT32, f:type())
assert_nil(f:containing_oneof())
assert_equal(m, f:containing_type())
assert_equal(0, f:default())
-- enum
local e = test_messages_proto3['TestAllTypesProto3.NestedEnum']
assert_true(#e > 3 and #e < 10)
assert_equal(2, e:value("BAZ"))
end
function test_enumdef()
local e = upb.EnumDef()
assert_equal(0, #e)
assert_nil(e:value(5))
assert_nil(e:value("NONEXISTENT_NAME"))
for name, value in e:values() do
fail()
end
e:add("VAL1", 1)
e:add("VAL2", 2)
local values = {}
for name, value in e:values() do
values[name] = value
end
assert_equal(1, values["VAL1"])
assert_equal(2, values["VAL2"])
local e2 = upb.EnumDef{
values = {
{"FOO", 1},
{"BAR", 77},
}
}
assert_equal(1, e2:value("FOO"))
assert_equal(77, e2:value("BAR"))
assert_equal("FOO", e2:value(1))
assert_equal("BAR", e2:value(77))
e2:freeze()
local f = upb.FieldDef{type = upb.TYPE_ENUM}
-- No default set and no EnumDef to get a default from.
assert_equal(f:default(), nil)
f:set_subdef(upb.EnumDef())
-- No default to pull in from the EnumDef.
assert_equal(f:default(), nil)
f:set_subdef(e2)
-- First member added to e2.
assert_equal(f:default(), "FOO")
f:set_subdef(nil)
assert_equal(f:default(), nil)
f:set_default(1)
assert_equal(f:default(), 1)
f:set_default("YOYOYO")
assert_equal(f:default(), "YOYOYO")
f:set_subdef(e2)
f:set_default(1)
-- It prefers to return a string, and could resolve the explicit "1" we set
-- it to to the string value.
assert_equal(f:default(), "FOO")
-- FieldDef can specify default value by name or number, but the value must
-- exist at freeze time.
local m1 = upb.build_defs{
upb.MessageDef{
full_name = "A",
fields = {
upb.FieldDef{
name = "f1",
number = 1,
type = upb.TYPE_ENUM,
subdef = e2,
default = "BAR"
},
upb.FieldDef{
name = "f2",
number = 2,
type = upb.TYPE_ENUM,
subdef = e2,
default = 77
}
}
}
}
assert_equal(m1:field("f1"):default(), "BAR")
assert_equal(m1:field("f1"):default(), "BAR")
assert_error_match(
"enum default for field A.f1 .DOESNT_EXIST. is not in the enum",
function()
local m1 = upb.build_defs{
upb.MessageDef{
full_name = "A",
fields = {
upb.FieldDef{
name = "f1",
number = 1,
type = upb.TYPE_ENUM,
subdef = e2,
default = "DOESNT_EXIST"
}
}
}
}
end
)
assert_error_match(
"enum default for field A.f1 .142. is not in the enum",
function()
local m1 = upb.build_defs{
upb.MessageDef{
full_name = "A",
fields = {
upb.FieldDef{
name = "f1",
number = 1,
type = upb.TYPE_ENUM,
subdef = e2,
default = 142
}
}
}
}
end
)
end
function test_empty_msgdef()
local md = upb.MessageDef()
assert_nil(md:full_name()) -- Def without name is anonymous.
assert_false(md:is_frozen())
assert_equal(0, #md)
assert_nil(md:field("nonexistent_field"))
assert_nil(md:field(3))
for field in md:fields() do
fail()
end
upb.freeze(md)
assert_true(md:is_frozen())
assert_equal(0, #md)
assert_nil(md:field("nonexistent_field"))
assert_nil(md:field(3))
for field in md:fields() do
fail()
end
end
function test_msgdef_constructor()
local f1 = upb.FieldDef{name = "field1", number = 7, type = upb.TYPE_INT32}
local f2 = upb.FieldDef{name = "field2", number = 8, type = upb.TYPE_INT32}
local md = upb.MessageDef{
full_name = "TestMessage",
fields = {f1, f2}
}
assert_equal("TestMessage", md:full_name())
assert_false(md:is_frozen())
assert_equal(2, #md)
assert_equal(f1, md:field("field1"))
assert_equal(f2, md:field("field2"))
assert_equal(f1, md:field(7))
assert_equal(f2, md:field(8))
local count = 0
local found = {}
for field in md:fields() do
count = count + 1
found[field] = true
end
assert_equal(2, count)
assert_true(found[f1])
assert_true(found[f2])
--[[
upb.freeze(md)
end
function test_enumdef()
function test_iteration()
-- Test that we cannot crash the process even if we modify the set of fields
-- during iteration.
@ -510,81 +319,85 @@ function test_msg_primitives()
test_for_numeric_type(upb.TYPE_DOUBLE, 10^101)
end
==]]
function test_msg_map()
msg = test_messages_proto3.TestAllTypesProto3()
msg.map_int32_int32[5] = 10
msg.map_int32_int32[6] = 12
assert_equal(10, msg.map_int32_int32[5])
assert_equal(12, msg.map_int32_int32[6])
local serialized = upb.encode(msg)
assert_true(#serialized > 0)
local msg2 = upb.decode(test_messages_proto3.TestAllTypesProto3, serialized)
assert_equal(10, msg2.map_int32_int32[5])
assert_equal(12, msg2.map_int32_int32[6])
end
function test_msg_array()
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},
}
}
}
msg = test_messages_proto3.TestAllTypesProto3()
factory = upb.MessageFactory(symtab)
TestMessage = factory:get_message_class("TestMessage")
msg = TestMessage()
assert_not_nil(msg.repeated_int32)
assert_equal(msg.repeated_int32, msg.repeated_int32)
assert_equal(0, #msg.repeated_int32)
assert_nil(msg.i32_array)
msg.repeated_int32[1] = 2
assert_equal(1, #msg.repeated_int32);
assert_equal(2, msg.repeated_int32[1]);
-- Can't assign a scalar; array is expected.
assert_error_match("lupb.array expected", function() msg.i32_array = 5 end)
assert_error_match("lupb.array expected", function() msg.repeated_int32 = 5 end)
-- Can't assign array of the wrong type.
local function assign_int64()
msg.i32_array = upb.Array(upb.TYPE_INT64)
msg.repeated_int32 = upb.Array(upb.TYPE_INT64)
end
assert_error_match("Array had incorrect type", assign_int64)
assert_error_match("array type mismatch", assign_int64)
local arr = upb.Array(upb.TYPE_INT32)
msg.i32_array = arr
assert_equal(arr, msg.i32_array)
arr[1] = 6
assert_equal(1, #arr)
msg.repeated_int32 = arr
assert_equal(msg.repeated_int32, msg.repeated_int32)
assert_equal(arr, msg.repeated_int32)
assert_equal(1, #msg.repeated_int32)
assert_equal(6, msg.repeated_int32[1])
-- Can't assign other Lua types.
assert_error_match("array expected", function() msg.i32_array = "abc" end)
assert_error_match("array expected", function() msg.i32_array = true end)
assert_error_match("array expected", function() msg.i32_array = false end)
assert_error_match("array expected", function() msg.i32_array = nil end)
assert_error_match("array expected", function() msg.i32_array = {} end)
assert_error_match("array expected", function() msg.i32_array = print end)
assert_error_match("array expected", function() msg.repeated_int32 = "abc" end)
assert_error_match("array expected", function() msg.repeated_int32 = true end)
assert_error_match("array expected", function() msg.repeated_int32 = false end)
assert_error_match("array expected", function() msg.repeated_int32 = nil end)
assert_error_match("array expected", function() msg.repeated_int32 = {} end)
assert_error_match("array expected", function() msg.repeated_int32 = print end)
end
function test_msg_submsg()
local symtab = upb.SymbolTable{
upb.MessageDef{full_name = "TestMessage", fields = {
upb.FieldDef{name = "submsg", number = 1, type = upb.TYPE_MESSAGE,
subdef_name = ".SubMessage"},
}
},
upb.MessageDef{full_name = "SubMessage"}
}
factory = upb.MessageFactory(symtab)
TestMessage = factory:get_message_class("TestMessage")
SubMessage = factory:get_message_class("SubMessage")
msg = TestMessage()
--msg = test_messages_proto3.TestAllTypesProto3()
msg = test_messages_proto3['TestAllTypesProto3']()
assert_nil(msg.submsg)
assert_nil(msg.optional_nested_message)
-- Can't assign message of the wrong type.
local function assign_int64()
msg.submsg = TestMessage()
msg.optional_nested_message = test_messages_proto3.TestAllTypesProto3()
end
assert_error_match("Message had incorrect type", assign_int64)
assert_error_match("message type mismatch", assign_int64)
local sub = SubMessage()
msg.submsg = sub
assert_equal(sub, msg.submsg)
local nested = test_messages_proto3['TestAllTypesProto3.NestedMessage']()
msg.optional_nested_message = nested
assert_equal(nested, msg.optional_nested_message)
-- Can't assign other Lua types.
assert_error_match("msg expected", function() msg.submsg = "abc" end)
assert_error_match("msg expected", function() msg.submsg = true end)
assert_error_match("msg expected", function() msg.submsg = false end)
assert_error_match("msg expected", function() msg.submsg = nil end)
assert_error_match("msg expected", function() msg.submsg = {} end)
assert_error_match("msg expected", function() msg.submsg = print end)
assert_error_match("msg expected", function() msg.optional_nested_message = "abc" end)
assert_error_match("msg expected", function() msg.optional_nested_message = true end)
assert_error_match("msg expected", function() msg.optional_nested_message = false end)
assert_error_match("msg expected", function() msg.optional_nested_message = nil end)
assert_error_match("msg expected", function() msg.optional_nested_message = {} end)
assert_error_match("msg expected", function() msg.optional_nested_message = print end)
end
--]]
-- Lua 5.1 and 5.2 have slightly different semantics for how a finalizer
-- can be defined in Lua.
if _VERSION >= 'Lua 5.2' then
@ -765,6 +578,35 @@ function test_numeric_map()
map[key_vals.valid_val] = val_vals.valid_val
assert_equal(1, #map)
assert_equal(val_vals.valid_val, map[key_vals.valid_val])
i = 0
for k, v in pairs(map) do
assert_equal(key_vals.valid_val, k)
assert_equal(val_vals.valid_val, v)
end
-- Out of range key/val
local errmsg = "not an integer or out of range"
if key_vals.too_small then
assert_error_match(errmsg, function() map[key_vals.too_small] = 1 end)
end
if key_vals.too_big then
assert_error_match(errmsg, function() map[key_vals.too_big] = 1 end)
end
if key_vals.other_bad then
assert_error_match(errmsg, function() map[key_vals.other_bad] = 1 end)
end
if val_vals.too_small then
assert_error_match(errmsg, function() map[1] = val_vals.too_small end)
end
if val_vals.too_big then
assert_error_match(errmsg, function() map[1] = val_vals.too_big end)
end
if val_vals.other_bad then
assert_error_match(errmsg, function() map[1] = val_vals.other_bad end)
end
end
for k in pairs(numeric_types) do

@ -100,16 +100,7 @@ class BuildFileFunctions(object):
def py_binary(self, **kwargs):
pass
def lua_cclibrary(self, **kwargs):
pass
def lua_library(self, **kwargs):
pass
def lua_binary(self, **kwargs):
pass
def lua_test(self, **kwargs):
def lua_proto_library(self, **kwargs):
pass
def sh_test(self, **kwargs):

@ -364,6 +364,17 @@ static int lupb_msgdef_lookupname(lua_State *L) {
return 1;
}
/* lupb_msgdef_name()
*
* Handles:
* msg.name() -> string
*/
static int lupb_msgdef_name(lua_State *L) {
const upb_msgdef *m = lupb_msgdef_check(L, 1);
lua_pushstring(L, upb_msgdef_name(m));
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;
@ -386,6 +397,19 @@ static int lupb_msgdef_fields(lua_State *L) {
return 1;
}
static int lupb_msgdef_file(lua_State *L) {
const upb_msgdef *m = lupb_msgdef_check(L, 1);
const upb_filedef *file = upb_msgdef_file(m);
lupb_wrapper_pushwrapper(L, 1, file, LUPB_FILEDEF);
return 1;
}
static int lupb_msgdef_fullname(lua_State *L) {
const upb_msgdef *m = lupb_msgdef_check(L, 1);
lua_pushstring(L, upb_msgdef_fullname(m));
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;
@ -419,16 +443,27 @@ static int lupb_msgdef_syntax(lua_State *L) {
return 1;
}
static int lupb_msgdef_tostring(lua_State *L) {
const upb_msgdef *m = lupb_msgdef_check(L, 1);
lua_pushfstring(L, "<upb.MessageDef name=%s, field_count=%d>",
upb_msgdef_fullname(m), (int)upb_msgdef_numfields(m));
return 1;
}
static const struct luaL_Reg lupb_msgdef_mm[] = {
{"__call", lupb_msg_pushnew},
{"__len", lupb_msgdef_len},
{"__tostring", lupb_msgdef_tostring},
{NULL, NULL}
};
static const struct luaL_Reg lupb_msgdef_m[] = {
{"field", lupb_msgdef_field},
{"fields", lupb_msgdef_fields},
{"file", lupb_msgdef_file},
{"full_name", lupb_msgdef_fullname},
{"lookup_name", lupb_msgdef_lookupname},
{"name", lupb_msgdef_name},
{"oneofs", lupb_msgdef_oneofs},
{"syntax", lupb_msgdef_syntax},
{"_map_entry", lupb_msgdef_mapentry},
@ -448,6 +483,13 @@ static int lupb_enumdef_len(lua_State *L) {
return 1;
}
static int lupb_enumdef_file(lua_State *L) {
const upb_enumdef *e = lupb_enumdef_check(L, 1);
const upb_filedef *file = upb_enumdef_file(e);
lupb_wrapper_pushwrapper(L, 1, file, LUPB_FILEDEF);
return 1;
}
/* lupb_enumdef_value()
*
* Handles:
@ -510,6 +552,7 @@ static const struct luaL_Reg lupb_enumdef_mm[] = {
};
static const struct luaL_Reg lupb_enumdef_m[] = {
{"file", lupb_enumdef_file},
{"value", lupb_enumdef_value},
{"values", lupb_enumdef_values},
{NULL, NULL}
@ -619,6 +662,7 @@ upb_symtab *lupb_symtab_check(lua_State *L, int narg) {
void lupb_symtab_pushwrapper(lua_State *L, int narg, const void *def,
const char *type) {
narg = lua_absindex(L, narg);
assert(luaL_testudata(L, narg, LUPB_SYMTAB));
if (def == NULL) {
@ -687,6 +731,7 @@ static int lupb_symtab_addfile(lua_State *L) {
const char *str = luaL_checklstring(L, 2, &len);
upb_arena *arena = lupb_arena_pushnew(L);;
const google_protobuf_FileDescriptorProto *file;
const upb_filedef *file_def;
upb_status status;
upb_status_clear(&status);
@ -696,10 +741,12 @@ static int lupb_symtab_addfile(lua_State *L) {
luaL_argerror(L, 2, "failed to parse descriptor");
}
upb_symtab_addfile(s, file, &status);
file_def = upb_symtab_addfile(s, file, &status);
lupb_checkstatus(L, &status);
return 0;
lupb_symtab_pushwrapper(L, 1, file_def, LUPB_FILEDEF);
return 1;
}
static int lupb_symtab_addset(lua_State *L) {
@ -741,6 +788,13 @@ static int lupb_symtab_lookupenum(lua_State *L) {
return 1;
}
static int lupb_symtab_tostring(lua_State *L) {
const upb_symtab *s = lupb_symtab_check(L, 1);
lua_pushfstring(L, "<upb.SymbolTable file_count=%d>",
(int)upb_symtab_filecount(s));
return 1;
}
static const struct luaL_Reg lupb_symtab_m[] = {
{"add_file", lupb_symtab_addfile},
{"add_set", lupb_symtab_addset},
@ -751,6 +805,7 @@ static const struct luaL_Reg lupb_symtab_m[] = {
static const struct luaL_Reg lupb_symtab_mm[] = {
{"__gc", lupb_symtab_gc},
{"__tostring", lupb_symtab_tostring},
{NULL, NULL}
};

@ -181,7 +181,7 @@ typedef struct {
upb_arena *arena;
} lupb_arena;
upb_arena *lupb_arena_check(lua_State *L, int narg) {
static upb_arena *lupb_arena_check(lua_State *L, int narg) {
lupb_arena *a = luaL_checkudata(L, narg, LUPB_ARENA);
return a->arena;
}
@ -206,7 +206,7 @@ upb_arena *lupb_arena_pushnew(lua_State *L) {
*
* Merges |from| into |to| so that there is a single arena group that contains
* both, and both arenas will point at this new table. */
void lupb_arena_merge(lua_State *L, int to, int from) {
static void lupb_arena_merge(lua_State *L, int to, int from) {
int i, from_count, to_count;
lua_getiuservalue(L, to, LUPB_ARENAGROUP_INDEX);
lua_getiuservalue(L, from, LUPB_ARENAGROUP_INDEX);
@ -240,7 +240,7 @@ void lupb_arena_merge(lua_State *L, int to, int from) {
*
* This is mainly useful for pinning strings we have parsed protobuf data from.
* It will allow us to point directly to string data in the original string. */
void lupb_arena_addobj(lua_State *L, int narg) {
static void lupb_arena_addobj(lua_State *L, int narg) {
lua_getiuservalue(L, narg, LUPB_ARENAGROUP_INDEX);
int n = lua_rawlen(L, -1);
lua_pushvalue(L, -2);
@ -376,7 +376,6 @@ static void lupb_pushmsgval(lua_State *L, int container, upb_fieldtype_t type,
assert(container);
if (!lupb_cacheget(L, val.msg_val)) {
lupb_msg_newmsgwrapper(L, container, val);
lupb_cacheset(L, val.msg_val);
}
return;
}
@ -436,6 +435,7 @@ static int lupb_array_new(lua_State *L) {
lua_setiuservalue(L, -2, LUPB_ARENA_INDEX);
larray->arr = upb_array_new(arena, larray->type);
lupb_cacheset(L, larray->arr);
return 1;
}
@ -542,6 +542,7 @@ static int lupb_map_new(lua_State *L) {
lmap->key_type = lupb_checkfieldtype(L, 1);
lmap->map = upb_map_new(arena, lmap->key_type, lmap->value_type);
lupb_cacheset(L, lmap->map);
return 1;
}
@ -669,7 +670,9 @@ static const upb_fielddef *lupb_msg_checkfield(lua_State *L, int msg,
lua_getiuservalue(L, msg, LUPB_MSGDEF_INDEX);
m = lupb_msgdef_check(L, -1);
f = upb_msgdef_ntof(m, fieldname, len);
luaL_argcheck(L, f != NULL, field, "no such field");
if (f == NULL) {
luaL_error(L, "no such field '%s'", fieldname);
}
lua_pop(L, 1);
return f;
@ -684,6 +687,7 @@ static const upb_fielddef *lupb_msg_checkfield(lua_State *L, int msg,
static void lupb_msg_newmsgwrapper(lua_State *L, int narg, upb_msgval val) {
lupb_msg *lmsg = lupb_newuserdata(L, sizeof(*lmsg), 2, LUPB_MSG);
lmsg->msg = (upb_msg*)val.msg_val; /* XXX: cast isn't great. */
lupb_cacheset(L, lmsg->msg);
/* Copy both arena and msgdef into the wrapper. */
lua_getiuservalue(L, narg, LUPB_ARENA_INDEX);
@ -763,6 +767,8 @@ static void lupb_msg_newwrapper(lua_State *L, int narg, const upb_fielddef *f,
* must be in the same group. */
lua_getiuservalue(L, narg, LUPB_ARENA_INDEX);
lua_setiuservalue(L, -2, LUPB_ARENA_INDEX);
lupb_cacheset(L, val.msg_val);
}
/**
@ -787,8 +793,10 @@ static void lupb_msg_typechecksubmsg(lua_State *L, int narg, int msgarg,
*
* Handles:
* new_msg = MessageClass()
* new_msg = MessageClass{foo = "bar", baz = 3, quux = {foo = 3}}
*/
int lupb_msg_pushnew(lua_State *L) {
int argcount = lua_gettop(L);
const upb_msgdef *m = lupb_msgdef_check(L, 1);
lupb_msg *lmsg = lupb_newuserdata(L, sizeof(lupb_msg), 2, LUPB_MSG);
upb_arena *arena = lupb_arena_pushnew(L);
@ -798,6 +806,18 @@ int lupb_msg_pushnew(lua_State *L) {
lua_setiuservalue(L, -2, LUPB_MSGDEF_INDEX);
lmsg->msg = upb_msg_new(m, arena);
lupb_cacheset(L, lmsg->msg);
if (argcount > 1) {
/* Set initial fields from table. */
int msg = lua_gettop(L);
lua_pushnil(L);
while (lua_next(L, 2) != 0) {
lua_pushvalue(L, -2); /* now stack is key, val, key */
lua_insert(L, -3); /* now stack is key, key, val */
lua_settable(L, msg);
}
}
return 1;
}
@ -819,7 +839,6 @@ static int lupb_msg_index(lua_State *L) {
/* Wrapped type; get or create wrapper. */
if (lupb_msg_lazycreate(L, 1, f, &val) || !lupb_cacheget(L, val.msg_val)) {
lupb_msg_newwrapper(L, 1, f, val);
lupb_cacheset(L, val.msg_val);
}
} else {
/* Value type, just push value and return .*/
@ -841,6 +860,7 @@ static int lupb_msg_newindex(lua_State *L) {
upb_msg *msg = lupb_msg_check(L, 1);
const upb_fielddef *f = lupb_msg_checkfield(L, 1, 2);
upb_msgval msgval;
bool merge_arenas = true;
if (upb_fielddef_ismap(f)) {
lupb_map *lmap = lupb_map_check(L, 3);
@ -869,6 +889,14 @@ static int lupb_msg_newindex(lua_State *L) {
msgval.msg_val = msg;
} else {
msgval = lupb_tomsgval(L, upb_fielddef_type(f), 3, 1, LUPB_COPY);
merge_arenas = false;
}
if (merge_arenas) {
lua_getiuservalue(L, 1, LUPB_ARENA_INDEX);
lua_getiuservalue(L, 3, LUPB_ARENA_INDEX);
lupb_arena_merge(L, lua_absindex(L, -2), lua_absindex(L, -1));
lua_pop(L, 2);
}
upb_msg_set(msg, f, msgval, lupb_arenaget(L, 1));
@ -887,6 +915,12 @@ static const struct luaL_Reg lupb_msg_mm[] = {
/* lupb_msg toplevel **********************************************************/
/**
* lupb_decode()
*
* Handles:
* msg = upb.decode(MessageClass, bin_string)
*/
static int lupb_decode(lua_State *L) {
size_t len;
const upb_msgdef *m = lupb_msgdef_check(L, 1);
@ -896,7 +930,10 @@ static int lupb_decode(lua_State *L) {
upb_arena *arena;
bool ok;
lupb_msg_pushnew(L);
/* Create message. */
lua_pushcfunction(L, &lupb_msg_pushnew);
lua_pushvalue(L, 1);
lua_call(L, 1, 1);
msg = lupb_msg_check(L, -1);
lua_getiuservalue(L, -1, LUPB_ARENA_INDEX);
@ -917,6 +954,12 @@ static int lupb_decode(lua_State *L) {
return 1;
}
/**
* lupb_encode()
*
* Handles:
* bin_string = upb.encode(msg)
*/
static int lupb_encode(lua_State *L) {
const upb_msg *msg = lupb_msg_check(L, 1);
const upb_msglayout *layout;

@ -471,6 +471,13 @@ static bool upb_decode_delimitedfield(upb_decstate *d, upb_decframe *frame,
if (field->label == UPB_LABEL_REPEATED) {
return upb_decode_toarray(d, frame, field, len);
} else if (field->label == UPB_LABEL_MAP) {
/* Max map entry size is string key/val. */
char submsg[sizeof(upb_strview) * 2];
const upb_msglayout *layout = frame->layout->submsgs[field->submsg_index];
CHK(upb_decode_msgfield(d, &submsg, layout, len));
/* TODO: insert into map. */
return true;
} else {
switch (field->descriptortype) {
case UPB_DESCRIPTOR_TYPE_STRING:

@ -932,6 +932,10 @@ static bool make_layout(const upb_symtab *symtab, const upb_msgdef *m) {
field->descriptortype = upb_fielddef_descriptortype(f);
field->label = upb_fielddef_label(f);
if (upb_fielddef_ismap(f)) {
field->label = UPB_LABEL_MAP;
}
/* TODO: we probably should sort the fields by field number to match the
* output of upbc, and to improve search speed for the table parser. */
f->layout_index = f->index_;
@ -1897,6 +1901,10 @@ const upb_filedef *upb_symtab_lookupfile(const upb_symtab *s, const char *name)
: NULL;
}
int upb_symtab_filecount(const upb_symtab *s) {
return upb_strtable_count(&s->files);
}
static const upb_filedef *_upb_symtab_addfile(
upb_symtab *s, const google_protobuf_FileDescriptorProto *file_proto,
const upb_msglayout **layouts, upb_status *status) {

@ -138,6 +138,82 @@ static bool upb_put_fixedarray(upb_encstate *e, const upb_array *arr,
bool upb_encode_message(upb_encstate *e, const char *msg,
const upb_msglayout *m, size_t *size);
static bool upb_encode_scalarfield(upb_encstate *e, const void *_field_mem,
const upb_msglayout *m,
const upb_msglayout_field *f,
bool skip_zero_value) {
const char *field_mem = _field_mem;
#define CASE(ctype, type, wire_type, encodeval) do { \
ctype val = *(ctype*)field_mem; \
if (skip_zero_value && val == 0) { \
return true; \
} \
return upb_put_ ## type(e, encodeval) && \
upb_put_tag(e, f->number, wire_type); \
} while(0)
switch (f->descriptortype) {
case UPB_DESCRIPTOR_TYPE_DOUBLE:
CASE(double, double, UPB_WIRE_TYPE_64BIT, val);
case UPB_DESCRIPTOR_TYPE_FLOAT:
CASE(float, float, UPB_WIRE_TYPE_32BIT, val);
case UPB_DESCRIPTOR_TYPE_INT64:
case UPB_DESCRIPTOR_TYPE_UINT64:
CASE(uint64_t, varint, UPB_WIRE_TYPE_VARINT, val);
case UPB_DESCRIPTOR_TYPE_UINT32:
CASE(uint32_t, varint, UPB_WIRE_TYPE_VARINT, val);
case UPB_DESCRIPTOR_TYPE_INT32:
case UPB_DESCRIPTOR_TYPE_ENUM:
CASE(int32_t, varint, UPB_WIRE_TYPE_VARINT, (int64_t)val);
case UPB_DESCRIPTOR_TYPE_SFIXED64:
case UPB_DESCRIPTOR_TYPE_FIXED64:
CASE(uint64_t, fixed64, UPB_WIRE_TYPE_64BIT, val);
case UPB_DESCRIPTOR_TYPE_FIXED32:
case UPB_DESCRIPTOR_TYPE_SFIXED32:
CASE(uint32_t, fixed32, UPB_WIRE_TYPE_32BIT, val);
case UPB_DESCRIPTOR_TYPE_BOOL:
CASE(bool, varint, UPB_WIRE_TYPE_VARINT, val);
case UPB_DESCRIPTOR_TYPE_SINT32:
CASE(int32_t, varint, UPB_WIRE_TYPE_VARINT, upb_zzencode_32(val));
case UPB_DESCRIPTOR_TYPE_SINT64:
CASE(int64_t, varint, UPB_WIRE_TYPE_VARINT, upb_zzencode_64(val));
case UPB_DESCRIPTOR_TYPE_STRING:
case UPB_DESCRIPTOR_TYPE_BYTES: {
upb_strview view = *(upb_strview*)field_mem;
if (skip_zero_value && view.size == 0) {
return true;
}
return upb_put_bytes(e, view.data, view.size) &&
upb_put_varint(e, view.size) &&
upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED);
}
case UPB_DESCRIPTOR_TYPE_GROUP: {
size_t size;
void *submsg = *(void **)field_mem;
const upb_msglayout *subm = m->submsgs[f->submsg_index];
if (submsg == NULL) {
return true;
}
return upb_put_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP) &&
upb_encode_message(e, submsg, subm, &size) &&
upb_put_tag(e, f->number, UPB_WIRE_TYPE_START_GROUP);
}
case UPB_DESCRIPTOR_TYPE_MESSAGE: {
size_t size;
void *submsg = *(void **)field_mem;
const upb_msglayout *subm = m->submsgs[f->submsg_index];
if (submsg == NULL) {
return true;
}
return upb_encode_message(e, submsg, subm, &size) &&
upb_put_varint(e, size) &&
upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED);
}
}
#undef CASE
UPB_UNREACHABLE();
}
static bool upb_encode_array(upb_encstate *e, const char *field_mem,
const upb_msglayout *m,
const upb_msglayout_field *f) {
@ -236,81 +312,37 @@ do { ; } while(0)
return true;
}
static bool upb_encode_scalarfield(upb_encstate *e, const char *field_mem,
const upb_msglayout *m,
const upb_msglayout_field *f,
bool skip_zero_value) {
#define CASE(ctype, type, wire_type, encodeval) do { \
ctype val = *(ctype*)field_mem; \
if (skip_zero_value && val == 0) { \
return true; \
} \
return upb_put_ ## type(e, encodeval) && \
upb_put_tag(e, f->number, wire_type); \
} while(0)
static bool upb_encode_map(upb_encstate *e, const char *field_mem,
const upb_msglayout *m,
const upb_msglayout_field *f) {
const upb_map *map = *(const upb_map**)field_mem;
const upb_msglayout *entry = m->submsgs[f->submsg_index];
const upb_msglayout_field *key_field = &entry->fields[0];
const upb_msglayout_field *val_field = &entry->fields[1];
upb_strtable_iter i;
if (map == NULL) {
return true;
}
switch (f->descriptortype) {
case UPB_DESCRIPTOR_TYPE_DOUBLE:
CASE(double, double, UPB_WIRE_TYPE_64BIT, val);
case UPB_DESCRIPTOR_TYPE_FLOAT:
CASE(float, float, UPB_WIRE_TYPE_32BIT, val);
case UPB_DESCRIPTOR_TYPE_INT64:
case UPB_DESCRIPTOR_TYPE_UINT64:
CASE(uint64_t, varint, UPB_WIRE_TYPE_VARINT, val);
case UPB_DESCRIPTOR_TYPE_UINT32:
CASE(uint32_t, varint, UPB_WIRE_TYPE_VARINT, val);
case UPB_DESCRIPTOR_TYPE_INT32:
case UPB_DESCRIPTOR_TYPE_ENUM:
CASE(int32_t, varint, UPB_WIRE_TYPE_VARINT, (int64_t)val);
case UPB_DESCRIPTOR_TYPE_SFIXED64:
case UPB_DESCRIPTOR_TYPE_FIXED64:
CASE(uint64_t, fixed64, UPB_WIRE_TYPE_64BIT, val);
case UPB_DESCRIPTOR_TYPE_FIXED32:
case UPB_DESCRIPTOR_TYPE_SFIXED32:
CASE(uint32_t, fixed32, UPB_WIRE_TYPE_32BIT, val);
case UPB_DESCRIPTOR_TYPE_BOOL:
CASE(bool, varint, UPB_WIRE_TYPE_VARINT, val);
case UPB_DESCRIPTOR_TYPE_SINT32:
CASE(int32_t, varint, UPB_WIRE_TYPE_VARINT, upb_zzencode_32(val));
case UPB_DESCRIPTOR_TYPE_SINT64:
CASE(int64_t, varint, UPB_WIRE_TYPE_VARINT, upb_zzencode_64(val));
case UPB_DESCRIPTOR_TYPE_STRING:
case UPB_DESCRIPTOR_TYPE_BYTES: {
upb_strview view = *(upb_strview*)field_mem;
if (skip_zero_value && view.size == 0) {
return true;
}
return upb_put_bytes(e, view.data, view.size) &&
upb_put_varint(e, view.size) &&
upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED);
}
case UPB_DESCRIPTOR_TYPE_GROUP: {
size_t size;
void *submsg = *(void **)field_mem;
const upb_msglayout *subm = m->submsgs[f->submsg_index];
if (submsg == NULL) {
return true;
}
return upb_put_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP) &&
upb_encode_message(e, submsg, subm, &size) &&
upb_put_tag(e, f->number, UPB_WIRE_TYPE_START_GROUP);
}
case UPB_DESCRIPTOR_TYPE_MESSAGE: {
size_t size;
void *submsg = *(void **)field_mem;
const upb_msglayout *subm = m->submsgs[f->submsg_index];
if (submsg == NULL) {
return true;
}
return upb_encode_message(e, submsg, subm, &size) &&
upb_put_varint(e, size) &&
upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED);
}
upb_strtable_begin(&i, &map->table);
for(; !upb_strtable_done(&i); upb_strtable_next(&i)) {
size_t pre_len = e->limit - e->ptr;
size_t size;
upb_strview key = upb_strtable_iter_key(&i);
const upb_value val = upb_strtable_iter_value(&i);
/* XXX; string key/value */
CHK(upb_encode_scalarfield(e, &val, entry, val_field, false));
CHK(upb_encode_scalarfield(e, key.data, entry, key_field, false));
size = (e->limit - e->ptr) - pre_len;
CHK(upb_put_varint(e, size));
CHK(upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED));
}
#undef CASE
UPB_UNREACHABLE();
return true;
}
bool upb_encode_message(upb_encstate *e, const char *msg,
const upb_msglayout *m, size_t *size) {
int i;
@ -318,11 +350,19 @@ bool upb_encode_message(upb_encstate *e, const char *msg,
const char *unknown;
size_t unknown_size;
unknown = upb_msg_getunknown(msg, &unknown_size);
if (unknown) {
upb_put_bytes(e, unknown, unknown_size);
}
for (i = m->field_count - 1; i >= 0; i--) {
const upb_msglayout_field *f = &m->fields[i];
if (f->label == UPB_LABEL_REPEATED) {
CHK(upb_encode_array(e, msg + f->offset, m, f));
} else if (f->label == UPB_LABEL_MAP) {
CHK(upb_encode_map(e, msg + f->offset, m, f));
} else {
bool skip_empty = false;
if (f->presence == 0) {
@ -343,12 +383,6 @@ bool upb_encode_message(upb_encstate *e, const char *msg,
}
}
unknown = upb_msg_getunknown(msg, &unknown_size);
if (unknown) {
upb_put_bytes(e, unknown, unknown_size);
}
*size = (e->limit - e->ptr) - pre_len;
return true;
}

@ -28,6 +28,12 @@ typedef void upb_msg;
* members are public so generated code can initialize them, but users MUST NOT
* read or write any of its members. */
/* This isn't a real label according to descriptor.proto, but in the table we
* use this for map fields instead of UPB_LABEL_REPEATED. */
enum {
UPB_LABEL_MAP = 4
};
typedef struct {
uint32_t number;
uint16_t offset;

@ -66,7 +66,8 @@ upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f) {
const char *mem = PTR_AT(msg, field->offset, char);
upb_msgval val;
if (field->presence == 0 || upb_msg_has(msg, f)) {
memcpy(&val, mem, field_size[field->descriptortype]);
int size = upb_fielddef_isseq(f) ? sizeof(void*) : field_size[field->descriptortype];
memcpy(&val, mem, size);
} else {
/* TODO(haberman): change upb_fielddef to not require this switch(). */
switch (upb_fielddef_type(f)) {
@ -131,7 +132,8 @@ void upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val,
upb_arena *a) {
const upb_msglayout_field *field = upb_fielddef_layout(f);
char *mem = PTR_AT(msg, field->offset, char);
memcpy(mem, &val, field_size[field->descriptortype]);
int size = upb_fielddef_isseq(f) ? sizeof(void*) : field_size[field->descriptortype];
memcpy(mem, &val, size);
if (in_oneof(field)) {
*oneofcase(msg, field) = field->number;
}

@ -670,6 +670,8 @@ void WriteSource(const protobuf::FileDescriptor* file, Output& output) {
case_offset.size64 = -case_offset.size64 - 1;
presence = GetSizeInit(case_offset);
}
// Sync '4' with UPB_LABEL_MAP in upb/msg.h.
int label = field->is_map() ? 4 : field->label();
output(" {$0, $1, $2, $3, $4, $5},\n",
field->number(),
@ -677,7 +679,7 @@ void WriteSource(const protobuf::FileDescriptor* file, Output& output) {
presence,
submsg_index,
field->type(),
field->label());
label);
}
output("};\n\n");
}

Loading…
Cancel
Save