libero/wire
Reflective JSON wire format for Libero RPC.
The encoder walks any Gleam value via Erlang runtime introspection and emits a JSON tree that preserves enough structure to rebuild Gleam custom types on the client via a constructor registry.
Wire shape:
- Primitives (Int, Float, Bool, String) → JSON primitives
Nil/None→ JSONnull- Gleam
List(a)→ JSON array of encoded elements - Plain tuple
#(a, b, c)→ JSON array of encoded elements (no tag) - Gleam custom type
Record(1, "alice", ...)→{"@": "record", "v": [1, "alice", ...]}
The distinction between “Gleam custom type” and “plain tuple” is made at
encode time: if the first element of a tuple is a non-boolean atom, the
tuple is treated as a custom type (where the atom is the constructor
name). Otherwise it’s serialized as a plain array. This mirrors Gleam’s
BEAM compilation: Record(...) becomes {record, ...} with the lowercase
atom in position 0.
Types
pub type DecodeError {
DecodeError(message: String, cause: json.DecodeError)
}
Constructors
-
DecodeError(message: String, cause: json.DecodeError)
Values
pub fn decode_call(
text: String,
) -> Result(#(String, List(dynamic.Dynamic)), DecodeError)
Parse {"fn": "records.save", "args": [...]} from text.
Args come back as a List(Dynamic). The dispatch table coerces each
one to its expected type via gleam_stdlib:identity.