Current section

Files

Jump to
libero src libero@wire.erl
Raw

src/libero@wire.erl

-module(libero@wire).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/libero/wire.gleam").
-export([encode/1, decode/1, decode_safe/1, decode_call/1]).
-export_type([decode_error/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" ETF (Erlang Term Format) wire codec for Libero RPC.\n"
"\n"
" Encoding walks any Gleam value through `erlang:term_to_binary/1`,\n"
" which preserves the full Erlang type structure - atoms, tuples,\n"
" maps, lists - natively. Decoding uses `erlang:binary_to_term/1`\n"
" to reconstruct the original terms. No manual walk or rebuild is\n"
" needed because ETF is the BEAM's native serialization format.\n"
"\n"
" **Wire shape:**\n"
" - The call envelope is `{fn_name_binary, args_list}` - a 2-tuple\n"
" where the first element is a UTF-8 binary (Gleam String) and the\n"
" second is a list of arbitrary terms.\n"
" - The response is the Gleam value directly (e.g. `Ok(value)` or\n"
" `Error(MalformedRequest)`), serialized as ETF.\n"
"\n"
" **Cross-target:** `encode` and `decode` work on both Erlang and\n"
" JavaScript targets. The Erlang path uses the BEAM's native\n"
" `term_to_binary` / `binary_to_term`. The JavaScript path uses\n"
" libero's own ETF encoder/decoder in `rpc_ffi.mjs`, which requires\n"
" that any custom-type constructors in the value have been registered\n"
" via `register_all()` at boot (libero's generator emits that\n"
" registration for every type reachable from the `@rpc` type graph).\n"
).
-type decode_error() :: {decode_error, binary()}.
-file("src/libero/wire.gleam", 36).
?DOC(
" Encode any Gleam value to an ETF binary.\n"
"\n"
" Works on both Erlang and JavaScript targets. Used internally by\n"
" libero to serialize RPC responses, and also available for non-RPC\n"
" paths (e.g. passing server-rendered state into a Lustre SPA via\n"
" flags, in the Elm \"init flags\" style).\n"
).
-spec encode(any()) -> bitstring().
encode(Value) ->
libero_ffi:encode(Value).
-file("src/libero/wire.gleam", 59).
?DOC(
" Decode an ETF binary into an arbitrary Gleam value.\n"
"\n"
" Works on both Erlang and JavaScript targets. Use this for non-RPC\n"
" paths — for example, reading server-rendered state from Lustre\n"
" flags on client boot. For decoding incoming RPC call envelopes\n"
" specifically, use `decode_call` instead.\n"
"\n"
" Any custom types in the decoded value must be reachable from the\n"
" `@rpc` type graph so their constructors are registered with the\n"
" JavaScript codec (via `register_all()` at boot). On Erlang this\n"
" is automatic because atoms are pre-registered by the generated\n"
" `rpc_atoms` module.\n"
"\n"
" **Panics on malformed input.** In a typical libero deployment\n"
" both sides are controlled, so this is a sharp-edge check rather\n"
" than a user-facing error. For untrusted input, use `decode_safe`\n"
" which returns a `Result`.\n"
).
-spec decode(bitstring()) -> any().
decode(Data) ->
libero_ffi:decode(Data).
-file("src/libero/wire.gleam", 70).
?DOC(
" Decode an ETF binary into an arbitrary Gleam value, returning a\n"
" `Result` instead of panicking on malformed input.\n"
"\n"
" Use this for non-RPC paths where the input may be untrusted or\n"
" user-influenced — for example, reading server-rendered state from\n"
" Lustre flags on client boot where the binary may have been\n"
" corrupted in transit.\n"
).
-spec decode_safe(bitstring()) -> {ok, any()} | {error, decode_error()}.
decode_safe(Data) ->
libero_ffi:decode_safe(Data).
-file("src/libero/wire.gleam", 94).
?DOC(
" Parse a `{<<\"fn_name\">>, [arg1, arg2, ...]}` tuple from an ETF binary.\n"
" Returns the function name and args list. Since `binary_to_term`\n"
" returns real Erlang terms, no rebuild step is needed - atoms are\n"
" atoms, tuples are tuples, maps are maps.\n"
"\n"
" This is specifically for RPC call envelopes. For decoding\n"
" arbitrary values, use `decode`.\n"
).
-spec decode_call(bitstring()) -> {ok,
{binary(), list(gleam@dynamic:dynamic_())}} |
{error, decode_error()}.
decode_call(Data) ->
libero_wire_ffi:decode_call(Data).