diff --git a/BUILD b/BUILD index 9d3ae34883..c5a3e977fc 100644 --- a/BUILD +++ b/BUILD @@ -656,6 +656,7 @@ cc_library( ], deps = [ ":reflection", + ":textformat", ":upb", "@lua//:liblua", ], diff --git a/tests/bindings/lua/test_upb.lua b/tests/bindings/lua/test_upb.lua index fb76224e20..eaaf7e4085 100644 --- a/tests/bindings/lua/test_upb.lua +++ b/tests/bindings/lua/test_upb.lua @@ -458,6 +458,11 @@ function test_foo() assert_error_match("lupb.array expected", function () set.file = 1 end) set = upb.decode(FileDescriptorSet, descriptor) + + -- Test that we can at least call this without crashing. + set_textformat = tostring(set) + + -- print(set_textformat) assert_equal(#set.file, 1) assert_equal(set.file[1].name, "google/protobuf/descriptor.proto") end diff --git a/upb/bindings/lua/msg.c b/upb/bindings/lua/msg.c index 82d65e0fa6..aca4c32c64 100644 --- a/upb/bindings/lua/msg.c +++ b/upb/bindings/lua/msg.c @@ -13,6 +13,7 @@ #include "lauxlib.h" #include "upb/bindings/lua/upb.h" #include "upb/reflection.h" +#include "upb/textencode.h" #include "upb/port_def.inc" @@ -887,9 +888,41 @@ static int lupb_msg_newindex(lua_State *L) { return 1; } +/** + * lupb_msg_tostring() + * + * Handles: + * tostring(msg) + * print(msg) + * etc. + */ +static int lupb_msg_tostring(lua_State *L) { + upb_msg *msg = lupb_msg_check(L, 1); + const upb_msgdef *m; + char buf[1024]; + size_t size; + + lua_getiuservalue(L, 1, LUPB_MSGDEF_INDEX); + m = lupb_msgdef_check(L, -1); + + size = upb_textencode(msg, m, NULL, 0, buf, sizeof(buf)); + + if (size < sizeof(buf)) { + lua_pushlstring(L, buf, size); + } else { + char *ptr = malloc(size + 1); + upb_textencode(msg, m, NULL, 0, ptr, size + 1); + lua_pushlstring(L, ptr, size); + free(ptr); + } + + return 1; +} + static const struct luaL_Reg lupb_msg_mm[] = { {"__index", lupb_msg_index}, {"__newindex", lupb_msg_newindex}, + {"__tostring", lupb_msg_tostring}, {NULL, NULL} }; diff --git a/upb/reflection.c b/upb/reflection.c index b3bc883c77..09483ac8da 100644 --- a/upb/reflection.c +++ b/upb/reflection.c @@ -82,7 +82,7 @@ bool upb_msg_has(const upb_msg *msg, const upb_fielddef *f) { return *oneofcase(msg, field) == field->number; } else if (field->presence > 0) { uint32_t hasbit = field->presence; - return *PTR_AT(msg, hasbit / 8, char) | (1 << (hasbit % 8)); + return *PTR_AT(msg, hasbit / 8, char) & (1 << (hasbit % 8)); } else { UPB_ASSERT(field->descriptortype == UPB_DESCRIPTOR_TYPE_MESSAGE || field->descriptortype == UPB_DESCRIPTOR_TYPE_GROUP); diff --git a/upb/textencode.c b/upb/textencode.c index 8af78ffd4a..b110664219 100644 --- a/upb/textencode.c +++ b/upb/textencode.c @@ -21,8 +21,6 @@ typedef struct { static void txtenc_msg(txtenc *e, const upb_msg *msg, const upb_msgdef *m); -#define CHK(x) do { if (!(x)) { return false; } } while(0) - static void txtenc_putbytes(txtenc *e, const void *data, size_t len) { size_t have = e->end - e->ptr; if (UPB_LIKELY(have >= len)) { @@ -159,6 +157,7 @@ static void txtenc_field(txtenc *e, upb_msgval val, const upb_fielddef *f) { break; case UPB_TYPE_MESSAGE: txtenc_putstr(e, "{"); + txtenc_endfield(e); e->indent_depth++; txtenc_msg(e, val.msg_val, upb_fielddef_msgsubdef(f)); e->indent_depth--; @@ -224,6 +223,8 @@ static void txtenc_map(txtenc *e, const upb_map *map, const upb_fielddef *f) { } } +#define CHK(x) do { if (!(x)) { return false; } } while(0) + static const char *txtenc_parsevarint(const char *ptr, const char *limit, uint64_t *val) { uint8_t byte; @@ -333,6 +334,8 @@ static const char *txtenc_unknown(txtenc *e, const char *ptr, const char *end, return groupnum == -1 ? ptr : NULL; } +#undef CHK + static void txtenc_msg(txtenc *e, const upb_msg *msg, const upb_msgdef *m) { size_t iter = UPB_MSG_BEGIN; @@ -389,5 +392,3 @@ size_t upb_textencode(const upb_msg *msg, const upb_msgdef *m, txtenc_msg(&e, msg, m); return txtenc_nullz(&e, size); } - -#undef CHK