Skip to content

Commit e4de647

Browse files
authored
Major lljson rework to make round-trippable serialization easier (#61)
Of note, there's now a notion of replacer and reviver callbacks as in JS' `JSON` APIs. An example of their use is in the tests folder as `lljson_typedjson.lua`. We went with this form since it allows constructing a different representation of the object before serializing without requiring you to construct an entire, serializable copy before calling `lljson.encode()`. That allows you to save memory, since the serializable version of each object only need to be alive as long as we're still traversing the object. Additionally, an empty table is now encoded as `[]` by default. This is probably the most common meaning for an empty table, but you can also apply `object_mt` as a metatable or add `__jsonhint="object"` to your own metatable to force serialization as an object. Similarly, `array_mt` or `__jsonhint="array"` will act as a hint to treat your object as an array. `__len` should no longer be used as a hint that the object should be treated as an array, that's what `__jsonhint` is for. Also added a new options table format to `lljson.encode()` and friends. The table now allows you to specify that `__tojson` hooks should be skipped, so you can manually invoke them at your leisure in your replacer hooks. Sparse tables are better-handled because of these changes, and having object-like tables with numeric or `uuid` keys is now allowed, though in the numeric case you must set that `object_mt` metatable so the serializer knows not to treat it as a sparse table.
1 parent 7368193 commit e4de647

File tree

10 files changed

+2287
-924
lines changed

10 files changed

+2287
-924
lines changed

VM/include/lljson.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
#define UTAG_JSON_CONFIG 27
44

55
#define JSON_NULL ((void *)3)
6-
#define JSON_EMPTY_ARRAY ((void *)4)
76
#define JSON_ARRAY ((void *)5)
7+
#define JSON_REMOVE ((void *)6)
8+
#define JSON_OBJECT ((void *)7)
89

910
constexpr int LU_TAG_JSON_INTERNAL = 60;

VM/src/ares.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3034,6 +3034,11 @@ static void scan_metatable(lua_State *L, bool forUnpersist, const std::string& p
30343034
// Register the metatable as a permanent
30353035
std::string mt_name = prefix + "/mt";
30363036

3037+
// empty_array/empty_object are special, they share array_mt/object_mt, which are
3038+
// registered under their canonical names. Skip the alias to avoid duplicates.
3039+
if (mt_name == "g/lljson/empty_array/mt" || mt_name == "g/lljson/empty_object/mt")
3040+
return;
3041+
30373042
if (forUnpersist) {
30383043
lua_pushstring(L, mt_name.c_str()); // ... perms obj_table mt name
30393044
lua_pushvalue(L, -2); // ... perms obj_table mt name mt

0 commit comments

Comments
 (0)