Merge pull request #348 from haberman/json-emit-defaults

Fixes for JSON encoder when emitting default values.
pull/13171/head
Joshua Haberman 4 years ago committed by GitHub
commit 5797d95172
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      BUILD
  2. 5
      tests/bindings/lua/test_upb.lua
  3. 1
      upb/bindings/lua/BUILD
  4. 2
      upb/bindings/lua/def.c
  5. 200
      upb/bindings/lua/msg.c
  6. 2
      upb/bindings/lua/upb.h
  7. 6
      upb/json_encode.c

@ -187,7 +187,10 @@ cc_library(
"upb/json_encode.h", "upb/json_encode.h",
], ],
copts = UPB_DEFAULT_COPTS, copts = UPB_DEFAULT_COPTS,
visibility = ["//tests:__pkg__"], visibility = [
"//tests:__pkg__",
"//upb/bindings/lua:__pkg__",
],
deps = [ deps = [
":port", ":port",
":reflection", ":reflection",

@ -695,6 +695,11 @@ function test_encode_skipunknown()
assert_true(#upb.encode(empty_with_unknown, {upb.ENCODE_SKIPUNKNOWN}) == 0) assert_true(#upb.encode(empty_with_unknown, {upb.ENCODE_SKIPUNKNOWN}) == 0)
end end
function test_json_emit_defaults()
local msg = test_messages_proto3.TestAllTypesProto3()
local json = upb.json_encode(msg, {upb.JSONENC_EMITDEFAULTS})
end
function test_gc() function test_gc()
local top = test_messages_proto3.TestAllTypesProto3() local top = test_messages_proto3.TestAllTypesProto3()
local n = 100 local n = 100

@ -19,6 +19,7 @@ cc_library(
copts = UPB_DEFAULT_COPTS, copts = UPB_DEFAULT_COPTS,
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
"//:json",
"//:reflection", "//:reflection",
"//:textformat", "//:textformat",
"//:upb", "//:upb",

@ -497,7 +497,7 @@ static int lupb_msgdef_tostring(lua_State *L) {
} }
static const struct luaL_Reg lupb_msgdef_mm[] = { static const struct luaL_Reg lupb_msgdef_mm[] = {
{"__call", lupb_msg_pushnew}, {"__call", lupb_msgdef_call},
{"__index", lupb_msgdef_index}, {"__index", lupb_msgdef_index},
{"__len", lupb_msgdef_fieldcount}, {"__len", lupb_msgdef_fieldcount},
{"__tostring", lupb_msgdef_tostring}, {"__tostring", lupb_msgdef_tostring},

@ -12,11 +12,12 @@
#include "lauxlib.h" #include "lauxlib.h"
#include "upb/bindings/lua/upb.h" #include "upb/bindings/lua/upb.h"
#include "upb/json_decode.h"
#include "upb/json_encode.h"
#include "upb/port_def.inc"
#include "upb/reflection.h" #include "upb/reflection.h"
#include "upb/text_encode.h" #include "upb/text_encode.h"
#include "upb/port_def.inc"
/* /*
* Message/Map/Array objects. These objects form a directed graph: a message * Message/Map/Array objects. These objects form a directed graph: a message
* can contain submessages, arrays, and maps, which can then point to other * can contain submessages, arrays, and maps, which can then point to other
@ -637,6 +638,20 @@ static const upb_fielddef *lupb_msg_checkfield(lua_State *L, int msg,
return f; return f;
} }
upb_msg *lupb_msg_pushnew(lua_State *L, int narg) {
const upb_msgdef *m = lupb_msgdef_check(L, narg);
lupb_msg *lmsg = lupb_newuserdata(L, sizeof(lupb_msg), 2, LUPB_MSG);
upb_arena *arena = lupb_arena_pushnew(L);
lua_setiuservalue(L, -2, LUPB_ARENA_INDEX);
lua_pushvalue(L, 1);
lua_setiuservalue(L, -2, LUPB_MSGDEF_INDEX);
lmsg->msg = upb_msg_new(m, arena);
lupb_cacheset(L, lmsg->msg);
return lmsg->msg;
}
/** /**
* lupb_msg_newmsgwrapper() * lupb_msg_newmsgwrapper()
* *
@ -726,28 +741,19 @@ static void lupb_msg_typechecksubmsg(lua_State *L, int narg, int msgarg,
/* lupb_msg Public API */ /* lupb_msg Public API */
/** /**
* lupb_msg_pushnew * lupb_msgdef_call
* *
* Handles: * Handles:
* new_msg = MessageClass() * new_msg = MessageClass()
* new_msg = MessageClass{foo = "bar", baz = 3, quux = {foo = 3}} * new_msg = MessageClass{foo = "bar", baz = 3, quux = {foo = 3}}
*/ */
int lupb_msg_pushnew(lua_State *L) { int lupb_msgdef_call(lua_State *L) {
int argcount = lua_gettop(L); int arg_count = lua_gettop(L);
const upb_msgdef *m = lupb_msgdef_check(L, 1); lupb_msg_pushnew(L, 1);
lupb_msg *lmsg = lupb_newuserdata(L, sizeof(lupb_msg), 2, LUPB_MSG);
upb_arena *arena = lupb_arena_pushnew(L);
lua_setiuservalue(L, -2, LUPB_ARENA_INDEX);
lua_pushvalue(L, 1);
lua_setiuservalue(L, -2, LUPB_MSGDEF_INDEX);
lmsg->msg = upb_msg_new(m, arena);
lupb_cacheset(L, lmsg->msg);
if (argcount > 1) { if (arg_count > 1) {
/* Set initial fields from table. */ /* Set initial fields from table. */
int msg = lua_gettop(L); int msg = arg_count + 1;
lua_pushnil(L); lua_pushnil(L);
while (lua_next(L, 2) != 0) { while (lua_next(L, 2) != 0) {
lua_pushvalue(L, -2); /* now stack is key, val, key */ lua_pushvalue(L, -2); /* now stack is key, val, key */
@ -883,6 +889,19 @@ static const struct luaL_Reg lupb_msg_mm[] = {
/* lupb_msg toplevel **********************************************************/ /* lupb_msg toplevel **********************************************************/
static int lupb_getoptions(lua_State *L, int narg) {
int options = 0;
if (lua_gettop(L) >= narg) {
size_t len = lua_rawlen(L, narg);
for (size_t i = 1; i <= len; i++) {
lua_rawgeti(L, narg, i);
options |= lupb_checkuint32(L, -1);
lua_pop(L, 1);
}
}
return options;
}
/** /**
* lupb_decode() * lupb_decode()
* *
@ -894,26 +913,16 @@ static int lupb_decode(lua_State *L) {
const upb_msgdef *m = lupb_msgdef_check(L, 1); const upb_msgdef *m = lupb_msgdef_check(L, 1);
const char *pb = lua_tolstring(L, 2, &len); const char *pb = lua_tolstring(L, 2, &len);
const upb_msglayout *layout = upb_msgdef_layout(m); const upb_msglayout *layout = upb_msgdef_layout(m);
upb_msg *msg = lupb_msg_pushnew(L, 1);
upb_arena *arena = lupb_arenaget(L, -1);
char *buf; char *buf;
upb_msg *msg;
upb_arena *arena;
bool ok; bool ok;
/* 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);
arena = lupb_arena_check(L, -1);
lua_pop(L, 1);
/* Copy input data to arena, message will reference it. */ /* Copy input data to arena, message will reference it. */
buf = upb_arena_malloc(arena, len); buf = upb_arena_malloc(arena, len);
memcpy(buf, pb, len); memcpy(buf, pb, len);
ok = upb_decode(buf, len, msg, layout, arena); ok = _upb_decode(buf, len, msg, layout, arena, UPB_DECODE_ALIAS);
if (!ok) { if (!ok) {
lua_pushstring(L, "Error decoding protobuf."); lua_pushstring(L, "Error decoding protobuf.");
@ -924,38 +933,81 @@ static int lupb_decode(lua_State *L) {
} }
/** /**
* lupb_msg_textencode() * lupb_encode()
* *
* Handles: * Handles:
* text_string = upb.text_encode(msg, {upb.TXTENC_SINGLELINE}) * bin_string = upb.encode(msg)
*/ */
static int lupb_textencode(lua_State *L) { static int lupb_encode(lua_State *L) {
int argcount = lua_gettop(L); const upb_msg *msg = lupb_msg_check(L, 1);
upb_msg *msg = lupb_msg_check(L, 1); const upb_msgdef *m = lupb_msg_getmsgdef(L, 1);
const upb_msgdef *m; const upb_msglayout *layout = upb_msgdef_layout(m);
char buf[1024]; int options = lupb_getoptions(L, 2);
upb_arena *arena;
size_t size; size_t size;
int options = 0; char *result;
lua_getiuservalue(L, 1, LUPB_MSGDEF_INDEX); arena = lupb_arena_pushnew(L);
m = lupb_msgdef_check(L, -1); result = upb_encode_ex(msg, (const void*)layout, options, arena, &size);
if (argcount > 1) { if (!result) {
size_t len = lua_rawlen(L, 2); lua_pushstring(L, "Error encoding protobuf.");
for (size_t i = 1; i <= len; i++) { return lua_error(L);
lua_rawgeti(L, 2, i);
options |= lupb_checkuint32(L, -1);
lua_pop(L, 1);
}
} }
size = upb_text_encode(msg, m, NULL, options, buf, sizeof(buf)); lua_pushlstring(L, result, size);
return 1;
}
/**
* lupb_jsondecode()
*
* Handles:
* text_string = upb.json_decode(MessageClass, json_str, {upb.JSONDEC_IGNOREUNKNOWN})
*/
static int lupb_jsondecode(lua_State *L) {
size_t len;
const upb_msgdef *m = lupb_msgdef_check(L, 1);
const char *json = lua_tolstring(L, 2, &len);
int options = lupb_getoptions(L, 3);
upb_msg *msg;
upb_arena *arena;
upb_status status;
msg = lupb_msg_pushnew(L, 1);
arena = lupb_arenaget(L, -1);
upb_status_clear(&status);
upb_json_decode(json, len, msg, m, NULL, options, arena, &status);
lupb_checkstatus(L, &status);
return 1;
}
/**
* lupb_jsonencode()
*
* Handles:
* text_string = upb.json_encode(msg, {upb.JSONENC_EMITDEFAULTS})
*/
static int lupb_jsonencode(lua_State *L) {
upb_msg *msg = lupb_msg_check(L, 1);
const upb_msgdef *m = lupb_msg_getmsgdef(L, 1);
int options = lupb_getoptions(L, 2);
char buf[1024];
size_t size;
upb_status status;
upb_status_clear(&status);
size = upb_json_encode(msg, m, NULL, options, buf, sizeof(buf), &status);
lupb_checkstatus(L, &status);
if (size < sizeof(buf)) { if (size < sizeof(buf)) {
lua_pushlstring(L, buf, size); lua_pushlstring(L, buf, size);
} else { } else {
char *ptr = malloc(size + 1); char *ptr = malloc(size + 1);
upb_text_encode(msg, m, NULL, options, ptr, size + 1); upb_json_encode(msg, m, NULL, options, ptr, size + 1, &status);
lupb_checkstatus(L, &status);
lua_pushlstring(L, ptr, size); lua_pushlstring(L, ptr, size);
free(ptr); free(ptr);
} }
@ -964,42 +1016,29 @@ static int lupb_textencode(lua_State *L) {
} }
/** /**
* lupb_encode() * lupb_textencode()
* *
* Handles: * Handles:
* bin_string = upb.encode(msg) * text_string = upb.text_encode(msg, {upb.TXTENC_SINGLELINE})
*/ */
static int lupb_encode(lua_State *L) { static int lupb_textencode(lua_State *L) {
int argcount = lua_gettop(L); upb_msg *msg = lupb_msg_check(L, 1);
const upb_msg *msg = lupb_msg_check(L, 1); const upb_msgdef *m = lupb_msg_getmsgdef(L, 1);
const upb_msglayout *layout; int options = lupb_getoptions(L, 2);
upb_arena *arena = lupb_arena_pushnew(L); char buf[1024];
size_t size; size_t size;
char *result;
int options = 0;
if (argcount > 1) {
size_t len = lua_rawlen(L, 2);
for (size_t i = 1; i <= len; i++) {
lua_rawgeti(L, 2, i);
options |= lupb_checkuint32(L, -1);
lua_pop(L, 1);
}
}
lua_getiuservalue(L, 1, LUPB_MSGDEF_INDEX); size = upb_text_encode(msg, m, NULL, options, buf, sizeof(buf));
layout = upb_msgdef_layout(lupb_msgdef_check(L, -1));
lua_pop(L, 1);
result = upb_encode_ex(msg, (const void*)layout, options, arena, &size);
if (!result) { if (size < sizeof(buf)) {
lua_pushstring(L, "Error encoding protobuf."); lua_pushlstring(L, buf, size);
return lua_error(L); } else {
char *ptr = malloc(size + 1);
upb_text_encode(msg, m, NULL, options, ptr, size + 1);
lua_pushlstring(L, ptr, size);
free(ptr);
} }
lua_pushlstring(L, result, size);
return 1; return 1;
} }
@ -1013,6 +1052,8 @@ static const struct luaL_Reg lupb_msg_toplevel_m[] = {
{"Map", lupb_map_new}, {"Map", lupb_map_new},
{"decode", lupb_decode}, {"decode", lupb_decode},
{"encode", lupb_encode}, {"encode", lupb_encode},
{"json_decode", lupb_jsondecode},
{"json_encode", lupb_jsonencode},
{"text_encode", lupb_textencode}, {"text_encode", lupb_textencode},
{NULL, NULL} {NULL, NULL}
}; };
@ -1032,5 +1073,10 @@ void lupb_msg_registertypes(lua_State *L) {
lupb_setfieldi(L, "ENCODE_DETERMINISTIC", UPB_ENCODE_DETERMINISTIC); lupb_setfieldi(L, "ENCODE_DETERMINISTIC", UPB_ENCODE_DETERMINISTIC);
lupb_setfieldi(L, "ENCODE_SKIPUNKNOWN", UPB_ENCODE_SKIPUNKNOWN); lupb_setfieldi(L, "ENCODE_SKIPUNKNOWN", UPB_ENCODE_SKIPUNKNOWN);
lupb_setfieldi(L, "JSONENC_EMITDEFAULTS", UPB_JSONENC_EMITDEFAULTS);
lupb_setfieldi(L, "JSONENC_PROTONAMES", UPB_JSONENC_PROTONAMES);
lupb_setfieldi(L, "JSONDEC_IGNOREUNKNOWN", UPB_JSONDEC_IGNOREUNKNOWN);
lupb_cacheinit(L); lupb_cacheinit(L);
} }

@ -75,7 +75,7 @@ void lupb_def_registertypes(lua_State *L);
/** From msg.c. ***************************************************************/ /** From msg.c. ***************************************************************/
int lupb_msg_pushnew(lua_State *L); int lupb_msgdef_call(lua_State *L);
upb_arena *lupb_arena_pushnew(lua_State *L); upb_arena *lupb_arena_pushnew(lua_State *L);
void lupb_msg_registertypes(lua_State *L); void lupb_msg_registertypes(lua_State *L);

@ -594,7 +594,7 @@ static void jsonenc_mapkey(jsonenc *e, upb_msgval val, const upb_fielddef *f) {
static void jsonenc_array(jsonenc *e, const upb_array *arr, static void jsonenc_array(jsonenc *e, const upb_array *arr,
const upb_fielddef *f) { const upb_fielddef *f) {
size_t i; size_t i;
size_t size = upb_array_size(arr); size_t size = arr ? upb_array_size(arr) : 0;
bool first = true; bool first = true;
jsonenc_putstr(e, "["); jsonenc_putstr(e, "[");
@ -616,11 +616,13 @@ static void jsonenc_map(jsonenc *e, const upb_map *map, const upb_fielddef *f) {
jsonenc_putstr(e, "{"); jsonenc_putstr(e, "{");
if (map) {
while (upb_mapiter_next(map, &iter)) { while (upb_mapiter_next(map, &iter)) {
jsonenc_putsep(e, ",", &first); jsonenc_putsep(e, ",", &first);
jsonenc_mapkey(e, upb_mapiter_key(map, iter), key_f); jsonenc_mapkey(e, upb_mapiter_key(map, iter), key_f);
jsonenc_scalar(e, upb_mapiter_value(map, iter), val_f); jsonenc_scalar(e, upb_mapiter_value(map, iter), val_f);
} }
}
jsonenc_putstr(e, "}"); jsonenc_putstr(e, "}");
} }
@ -659,8 +661,10 @@ static void jsonenc_msgfields(jsonenc *e, const upb_msg *msg,
int n = upb_msgdef_fieldcount(m); int n = upb_msgdef_fieldcount(m);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
f = upb_msgdef_field(m, i); f = upb_msgdef_field(m, i);
if (!upb_fielddef_haspresence(f) || upb_msg_has(msg, f)) {
jsonenc_fieldval(e, f, upb_msg_get(msg, f), &first); jsonenc_fieldval(e, f, upb_msg_get(msg, f), &first);
} }
}
} else { } else {
/* Iterate over non-empty fields. */ /* Iterate over non-empty fields. */
size_t iter = UPB_MSG_BEGIN; size_t iter = UPB_MSG_BEGIN;

Loading…
Cancel
Save