cardbox/store/json.rs
1//! The one value that crosses between Lua and the store, and the two conversions that
2//! carry it.
3//!
4//! Everything the host hands Teal or takes back — an event's `meta` and `data`, a row out
5//! of the SQL hatch, a parameter bound into one — is JSON on this side and a plain table
6//! on that one. Keeping the conversion in one place is what keeps "what was measured is
7//! what was stored" true: `json_encode` weighs a batch of rows with exactly the code that
8//! would write it.
9//!
10//! That code is now mlua-batteries', the crate behind `std.json` on the Teal side. It was
11//! written here first because nothing else had it; sharing it buys the one thing a
12//! hand-written pair could not have: an empty list stays a list. Lua cannot tell `{}` from
13//! `[]`, and the convention that settles it — a `__jsontype = "array"` metatable, which
14//! `std.json.array()` sets and `dkjson` reads — only works when both ends agree on it.
15//! Both ends are this crate now, so `cardbox list` on an empty store prints `[]`.
16
17use htl::mlua;
18use mlua_batteries::json::{DEFAULT_MAX_DEPTH, json_to_lua, lua_to_json};
19use serde_json::Value as Json;
20
21/// JSON as it crosses to Teal: a plain Lua value, declared `any`.
22///
23/// A newtype rather than `serde_json::Value` itself, because mlua has no conversion for
24/// that type and a host cannot write one for a foreign type it does not own. The name is
25/// load-bearing in one place only — htl's syntactic mapping spells the ident `Value` as
26/// `any`, which is the escape hatch this is meant to be.
27#[derive(Debug, Clone, PartialEq, Default)]
28pub struct Value(pub Json);
29
30impl From<Json> for Value {
31 fn from(j: Json) -> Self {
32 Value(j)
33 }
34}
35
36impl mlua::FromLua for Value {
37 fn from_lua(value: mlua::Value, _lua: &mlua::Lua) -> mlua::Result<Self> {
38 lua_to_json(&value, DEFAULT_MAX_DEPTH).map(Value)
39 }
40}
41
42impl mlua::IntoLua for Value {
43 fn into_lua(self, lua: &mlua::Lua) -> mlua::Result<mlua::Value> {
44 json_to_lua(lua, &self.0, DEFAULT_MAX_DEPTH)
45 }
46}