mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-23 13:52:28 +00:00
Polish redbean serialization
This commit is contained in:
parent
7aafa64ab3
commit
2d1731b995
24 changed files with 828 additions and 158 deletions
139
third_party/lua/luaencodejsondata.c
vendored
139
third_party/lua/luaencodejsondata.c
vendored
|
@ -16,23 +16,37 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "net/http/escape.h"
|
||||
#include "third_party/lua/cosmo.h"
|
||||
#include "third_party/lua/lauxlib.h"
|
||||
#include "third_party/lua/lua.h"
|
||||
#include "third_party/lua/visitor.h"
|
||||
|
||||
static int LuaEncodeJsonDataImpl(lua_State *L, char **buf, int level,
|
||||
char *numformat, int idx) {
|
||||
char *numformat, int idx,
|
||||
struct LuaVisited *visited) {
|
||||
char *s;
|
||||
bool isarray;
|
||||
size_t tbllen, z;
|
||||
size_t tbllen, i, z;
|
||||
char ibuf[21], fmt[] = "%.14g";
|
||||
if (level > 0) {
|
||||
switch (lua_type(L, idx)) {
|
||||
|
||||
case LUA_TNIL:
|
||||
appendw(buf, READ32LE("null"));
|
||||
return 0;
|
||||
|
||||
case LUA_TBOOLEAN:
|
||||
appendw(buf, lua_toboolean(L, idx) ? READ32LE("true")
|
||||
: READ64LE("false\0\0"));
|
||||
return 0;
|
||||
|
||||
case LUA_TSTRING:
|
||||
s = lua_tolstring(L, idx, &z);
|
||||
s = EscapeJsStringLiteral(s, z, &z);
|
||||
|
@ -41,21 +55,7 @@ static int LuaEncodeJsonDataImpl(lua_State *L, char **buf, int level,
|
|||
appendw(buf, '"');
|
||||
free(s);
|
||||
return 0;
|
||||
case LUA_TNIL:
|
||||
appendw(buf, READ32LE("null"));
|
||||
return 0;
|
||||
case LUA_TFUNCTION:
|
||||
appendf(buf, "\"func@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
case LUA_TUSERDATA:
|
||||
appendf(buf, "\"udata@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
appendf(buf, "\"light@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
case LUA_TTHREAD:
|
||||
appendf(buf, "\"thread@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
|
||||
case LUA_TNUMBER:
|
||||
if (lua_isinteger(L, idx)) {
|
||||
appendd(buf, ibuf,
|
||||
|
@ -78,58 +78,64 @@ static int LuaEncodeJsonDataImpl(lua_State *L, char **buf, int level,
|
|||
appendf(buf, fmt, lua_tonumber(L, idx));
|
||||
}
|
||||
return 0;
|
||||
case LUA_TBOOLEAN:
|
||||
appends(buf, lua_toboolean(L, idx) ? "true" : "false");
|
||||
return 0;
|
||||
|
||||
case LUA_TTABLE:
|
||||
tbllen = lua_rawlen(L, idx);
|
||||
// encode tables with numeric indices and empty tables as arrays
|
||||
isarray =
|
||||
tbllen > 0 || // integer keys present
|
||||
(lua_pushnil(L), lua_next(L, -2) == 0) || // no non-integer keys
|
||||
(lua_pop(L, 2), false); // pop key/value pushed by lua_next
|
||||
appendw(buf, isarray ? '[' : '{');
|
||||
if (isarray) {
|
||||
for (size_t i = 1; i <= tbllen; i++) {
|
||||
if (i > 1) appendw(buf, ',');
|
||||
lua_rawgeti(L, -1, i); // table/-2, value/-1
|
||||
LuaEncodeJsonDataImpl(L, buf, level - 1, numformat, -1);
|
||||
lua_pop(L, 1);
|
||||
if (LuaPushVisit(visited, lua_topointer(L, idx))) {
|
||||
tbllen = lua_rawlen(L, idx);
|
||||
// encode tables with numeric indices and empty tables as arrays
|
||||
isarray =
|
||||
tbllen > 0 || // integer keys present
|
||||
(lua_pushnil(L), !lua_next(L, -2)) || // no non-integer keys
|
||||
(lua_pop(L, 2), false); // pop key/value pushed by lua_next
|
||||
appendw(buf, isarray ? '[' : '{');
|
||||
if (isarray) {
|
||||
for (i = 1; i <= tbllen; i++) {
|
||||
if (i > 1) appendw(buf, ',');
|
||||
lua_rawgeti(L, -1, i); // table/-2, value/-1
|
||||
LuaEncodeJsonDataImpl(L, buf, level - 1, numformat, -1, visited);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
} else {
|
||||
i = 1;
|
||||
lua_pushnil(L); // push the first key
|
||||
while (lua_next(L, -2)) {
|
||||
if (!lua_isstring(L, -2)) {
|
||||
luaL_error(L, "expected number or string as key value");
|
||||
unreachable;
|
||||
}
|
||||
if (i++ > 1) appendw(buf, ',');
|
||||
appendw(buf, '"');
|
||||
if (lua_type(L, -2) == LUA_TSTRING) {
|
||||
s = lua_tolstring(L, -2, &z);
|
||||
s = EscapeJsStringLiteral(s, z, &z);
|
||||
appendd(buf, s, z);
|
||||
free(s);
|
||||
} else {
|
||||
// we'd still prefer to use lua_tostring on a numeric index, but
|
||||
// can't use it in-place, as it breaks lua_next (changes numeric
|
||||
// key to a string)
|
||||
lua_pushvalue(L, -2); // table/-4, key/-3, value/-2, key/-1
|
||||
s = lua_tolstring(L, idx, &z);
|
||||
appendd(buf, s, z); // use the copy
|
||||
lua_remove(L, -1); // remove copied key: tab/-3, key/-2, val/-1
|
||||
}
|
||||
appendw(buf, '"' | ':' << 010);
|
||||
LuaEncodeJsonDataImpl(L, buf, level - 1, numformat, -1, visited);
|
||||
lua_pop(L, 1); // table/-2, key/-1
|
||||
}
|
||||
// stack: table/-1, as the key was popped by lua_next
|
||||
}
|
||||
appendw(buf, isarray ? ']' : '}');
|
||||
LuaPopVisit(visited);
|
||||
return 0;
|
||||
} else {
|
||||
int i = 1;
|
||||
lua_pushnil(L); // push the first key
|
||||
while (lua_next(L, -2)) {
|
||||
if (!lua_isstring(L, -2)) {
|
||||
luaL_error(L, "expected number or string as key value");
|
||||
unreachable;
|
||||
}
|
||||
if (i++ > 1) appendw(buf, ',');
|
||||
appendw(buf, '"');
|
||||
if (lua_type(L, -2) == LUA_TSTRING) {
|
||||
s = lua_tolstring(L, -2, &z);
|
||||
s = EscapeJsStringLiteral(s, z, &z);
|
||||
appendd(buf, s, z);
|
||||
free(s);
|
||||
} else {
|
||||
// we'd still prefer to use lua_tostring on a numeric index, but
|
||||
// can't use it in-place, as it breaks lua_next (changes numeric
|
||||
// key to a string)
|
||||
lua_pushvalue(L, -2); // table/-4, key/-3, value/-2, key/-1
|
||||
s = lua_tolstring(L, idx, &z);
|
||||
appendd(buf, s, z); // use the copy
|
||||
lua_remove(L, -1); // remove copied key: tab/-3, key/-2, val/-1
|
||||
}
|
||||
appendw(buf, '"' | ':' << 010);
|
||||
LuaEncodeJsonDataImpl(L, buf, level - 1, numformat, -1);
|
||||
lua_pop(L, 1); // table/-2, key/-1
|
||||
}
|
||||
// stack: table/-1, as the key was popped by lua_next
|
||||
// TODO(jart): don't leak memory with longjmp
|
||||
luaL_error(L, "can't serialize cyclic data structure to json");
|
||||
unreachable;
|
||||
}
|
||||
appendw(buf, isarray ? ']' : '}');
|
||||
return 0;
|
||||
|
||||
default:
|
||||
luaL_error(L, "can't serialize value of this type");
|
||||
luaL_error(L, "won't serialize %s to json", luaL_typename(L, idx));
|
||||
unreachable;
|
||||
}
|
||||
} else {
|
||||
|
@ -140,6 +146,9 @@ static int LuaEncodeJsonDataImpl(lua_State *L, char **buf, int level,
|
|||
|
||||
int LuaEncodeJsonData(lua_State *L, char **buf, char *numformat, int idx) {
|
||||
int rc;
|
||||
rc = LuaEncodeJsonDataImpl(L, buf, 64, numformat, idx);
|
||||
struct LuaVisited visited = {0};
|
||||
rc = LuaEncodeJsonDataImpl(L, buf, 64, numformat, idx, &visited);
|
||||
assert(!visited.n);
|
||||
free(visited.p);
|
||||
return rc;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue