libero/wire

ETF (Erlang Term Format) wire codec for Libero RPC.

Encoding walks any Gleam value through erlang:term_to_binary/1, which preserves the full Erlang type structure - atoms, tuples, maps, lists - natively. Decoding uses erlang:binary_to_term/1 to reconstruct the original terms. No manual walk or rebuild is needed because ETF is the BEAM’s native serialization format.

Wire shape:

Cross-target: encode and decode work on both Erlang and JavaScript targets. The Erlang path uses the BEAM’s native term_to_binary / binary_to_term. The JavaScript path uses libero’s own ETF encoder/decoder in rpc_ffi.mjs, which requires that any custom-type constructors in the value have been registered via register_all() at boot (libero’s generator emits that registration for every type reachable from the @rpc type graph).

Types

pub type DecodeError {
  DecodeError(message: String)
}

Constructors

  • DecodeError(message: String)

Values

pub fn decode(data: BitArray) -> a

Decode an ETF binary into an arbitrary Gleam value.

Works on both Erlang and JavaScript targets. Use this for non-RPC paths — for example, reading server-rendered state from Lustre flags on client boot. For decoding incoming RPC call envelopes specifically, use decode_call instead.

Any custom types in the decoded value must be reachable from the @rpc type graph so their constructors are registered with the JavaScript codec (via register_all() at boot). On Erlang this is automatic because atoms are pre-registered by the generated rpc_atoms module.

Panics on malformed input. In a typical libero deployment both sides are controlled, so this is a sharp-edge check rather than a user-facing error. For untrusted input, use decode_safe which returns a Result.

pub fn decode_call(
  data: BitArray,
) -> Result(#(String, List(dynamic.Dynamic)), DecodeError)

Parse a {<<"fn_name">>, [arg1, arg2, ...]} tuple from an ETF binary. Returns the function name and args list. Since binary_to_term returns real Erlang terms, no rebuild step is needed - atoms are atoms, tuples are tuples, maps are maps.

This is specifically for RPC call envelopes. For decoding arbitrary values, use decode.

pub fn decode_safe(data: BitArray) -> Result(a, DecodeError)

Decode an ETF binary into an arbitrary Gleam value, returning a Result instead of panicking on malformed input.

Use this for non-RPC paths where the input may be untrusted or user-influenced — for example, reading server-rendered state from Lustre flags on client boot where the binary may have been corrupted in transit.

pub fn encode(value: a) -> BitArray

Encode any Gleam value to an ETF binary.

Works on both Erlang and JavaScript targets. Used internally by libero to serialize RPC responses, and also available for non-RPC paths (e.g. passing server-rendered state into a Lustre SPA via flags, in the Elm “init flags” style).

Search Document