Major lljson rework to make round-trippable serialization easier#61
Major lljson rework to make round-trippable serialization easier#61HaroldCindy merged 18 commits intomainfrom
Conversation
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 `__jsontype="object"` to your own metatable to force serialization as an object. Similarly, `array_mt` or `__jsontype="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 `__jsontype` 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.
Co-authored-by: Tapple Gao <tapplek@gmail.com>
This helps improve round-trippability of JSON payloads from outside SL, preserving the `array`-ness or `object`-ness of empty tables especially.
|
Additionally, we automatically set Thank y'all very much for your input! I think we've arrived at something semi-reasonable here, but I'd be interested to hear any thoughts on those recent changes. |
Suzanna-Linn
left a comment
There was a problem hiding this comment.
-
About
track_path:
I like it. -
About calling
__tojsononly once:
Yes, I think that it's the best way. -
About getting
__jsontypebefore calling__tojson(without replacer):
I think that it's good for advanced scripters, but that it will be difficult to understand for intermediate scripters.
I would prefer to have:- __tojson (always)
- replacer
- __jsontype
- serialization (no __tojson)
-
About automatically setting
object_mtandarray_mt:
I think this would be better as an optional parameter.- It could be problem in some cases. For instance: we receive an array from a server, add some keys to it, and send it to another server expecting it to be an object.
- And it's not always useful, only when there is an empty object, or an object that could become empty before the next encoding.
- It's also useful to know in the reviver if a table comes from array or object. I don't think there is any other way to know this. Could we have a
ctx.jsontype: stringin the reviver?
|
Thanks for the feedback!
Interested to hear others' thoughts on this. Is there any non-hypothetical usecase for a metatable that sometimes serializes with object semantics and sometimes with array semantics? Would it be acceptable to check for
That's probably my fault,
It's also useful in, say, cases where the server returns you an empty object specifically, you mutate it by adding some integer keys, and the serializer is able to realize that since this must be an object, those integer keys are meant to be string-ified and not treated as array indices
As @tapple mentioned, this is achievable with a metatable check now that the reviver receives metatable'd tables. |
You can just use __tojson() for doing these kinds of things now, and it's very strange to only consult `__index` in the array case. Barely even works, and was just inherited from cjson. Let's ditch it.
Of note, there's now a notion of replacer and reviver callbacks as in JS'
JSONAPIs. An example of their use is in the tests folder aslljson_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 applyobject_mtas a metatable or add__jsonhint="object"to your own metatable to force serialization as an object. Similarly,array_mtor__jsonhint="array"will act as a hint to treat your object as an array.__lenshould no longer be used as a hint that the object should be treated as an array, that's what__jsonhintis for.Also added a new options table format to
lljson.encode()and friends. The table now allows you to specify that__tojsonhooks should be skipped, so you can manually invoke them at your leisure in your replacer hooks.