distribute/codec

Types

Encoder + decoder + sized decoder, bundled. The shared a is the compile-time guarantee that the three sides agree on the message type. Assemble through Codec(...) whenever you can, and only reach for the open aliases for genuinely heterogeneous composition.

pub type Codec(a) {
  Codec(
    encoder: fn(a) -> Result(BitArray, EncodeError),
    decoder: fn(BitArray) -> Result(a, DecodeError),
    sized_decoder: fn(BitArray) -> Result(
      #(a, BitArray),
      DecodeError,
    ),
  )
}

Constructors

  • Codec(
      encoder: fn(a) -> Result(BitArray, EncodeError),
      decoder: fn(BitArray) -> Result(a, DecodeError),
      sized_decoder: fn(BitArray) -> Result(
        #(a, BitArray),
        DecodeError,
      ),
    )
pub type DecodeError {
  InvalidBinary(String)
  TypeMismatch(String)
  DecodeFailed(String)
  InsufficientData(String)
  DecodeTimeout
  TagMismatch(expected: String, got: String)
  VersionMismatch(expected: Int, got: Int)
  PayloadTooLarge(Int)
  ListTooLong(count: Int, cap: Int)
}

Constructors

  • InvalidBinary(String)
  • TypeMismatch(String)
  • DecodeFailed(String)
  • InsufficientData(String)
  • DecodeTimeout
  • TagMismatch(expected: String, got: String)
  • VersionMismatch(expected: Int, got: Int)
  • PayloadTooLarge(Int)

    The received payload exceeds config.max_payload_size_bytes. The Int is the actual byte size of the rejected payload.

  • ListTooLong(count: Int, cap: Int)

    The list-length prefix declares more elements than the decoder will materialise in a single frame. Defends against the “billion-laughs” amplification attack, where a 4-byte payload declares N billion zero-byte elements (e.g. list(nil())) and crashes the receiver with OOM despite the network-level payload size cap accepting the input.

pub type Decoder(a) =
  fn(BitArray) -> Result(a, DecodeError)
pub type EncodeError {
  InvalidValue(String)
  EncodeFailed(String)
  ValueTooLarge(String)
}

Constructors

  • InvalidValue(String)
  • EncodeFailed(String)
  • ValueTooLarge(String)
pub type Encoder(a) =
  fn(a) -> Result(BitArray, EncodeError)

Like Decoder but returns leftover bytes for chaining.

pub type SizedDecoder(a) =
  fn(BitArray) -> Result(#(a, BitArray), DecodeError)

Values

pub fn bitarray() -> Codec(BitArray)
pub fn bitarray_decoder() -> fn(BitArray) -> Result(
  BitArray,
  DecodeError,
)
pub fn bitarray_encoder() -> fn(BitArray) -> Result(
  BitArray,
  EncodeError,
)
pub fn bitarray_sized_decoder() -> fn(BitArray) -> Result(
  #(BitArray, BitArray),
  DecodeError,
)
pub fn bool() -> Codec(Bool)
pub fn bool_decoder() -> fn(BitArray) -> Result(Bool, DecodeError)
pub fn bool_encoder() -> fn(Bool) -> Result(BitArray, EncodeError)
pub fn bool_sized_decoder() -> fn(BitArray) -> Result(
  #(Bool, BitArray),
  DecodeError,
)
pub fn decode(
  decoder: fn(BitArray) -> Result(a, DecodeError),
  data: BitArray,
) -> Result(a, DecodeError)
pub fn decode_error_to_string(error: DecodeError) -> String
pub fn decode_sized(
  decoder: fn(BitArray) -> Result(#(a, BitArray), DecodeError),
  data: BitArray,
) -> Result(#(a, BitArray), DecodeError)
pub fn encode(
  encoder: fn(a) -> Result(BitArray, EncodeError),
  value: a,
) -> Result(BitArray, EncodeError)
pub fn encode_error_to_string(error: EncodeError) -> String
pub fn float() -> Codec(Float)
pub fn float_decoder() -> fn(BitArray) -> Result(
  Float,
  DecodeError,
)
pub fn float_encoder() -> fn(Float) -> Result(
  BitArray,
  EncodeError,
)
pub fn float_sized_decoder() -> fn(BitArray) -> Result(
  #(Float, BitArray),
  DecodeError,
)
pub fn int() -> Codec(Int)
pub fn int_decoder() -> fn(BitArray) -> Result(Int, DecodeError)
pub fn int_encoder() -> fn(Int) -> Result(BitArray, EncodeError)
pub fn int_sized_decoder() -> fn(BitArray) -> Result(
  #(Int, BitArray),
  DecodeError,
)
pub fn list(element: Codec(a)) -> Codec(List(a))
pub fn list_decoder(
  element_decoder: fn(BitArray) -> Result(
    #(a, BitArray),
    DecodeError,
  ),
) -> fn(BitArray) -> Result(List(a), DecodeError)
pub fn list_encoder(
  element_encoder: fn(a) -> Result(BitArray, EncodeError),
) -> fn(List(a)) -> Result(BitArray, EncodeError)
pub fn list_sized_decoder(
  element_decoder: fn(BitArray) -> Result(
    #(a, BitArray),
    DecodeError,
  ),
) -> fn(BitArray) -> Result(#(List(a), BitArray), DecodeError)
pub fn map(
  c: Codec(a),
  wrap: fn(a) -> b,
  unwrap: fn(b) -> a,
) -> Codec(b)

Transform a codec. wrap runs after decoding, unwrap before encoding.

pub fn nil() -> Codec(Nil)
pub fn nil_decoder() -> fn(BitArray) -> Result(Nil, DecodeError)

Strict top-level decoder for Nil: the wire form is zero bytes, and any trailing data is a protocol violation (either a bug in the sender or smuggled payload). Earlier drafts accepted the binary regardless, defeating the strict-top-level contract that to_decoder enforces for every other primitive.

pub fn nil_encoder() -> fn(Nil) -> Result(BitArray, EncodeError)
pub fn nil_sized_decoder() -> fn(BitArray) -> Result(
  #(Nil, BitArray),
  DecodeError,
)
pub fn string() -> Codec(String)
pub fn string_decoder() -> fn(BitArray) -> Result(
  String,
  DecodeError,
)
pub fn string_encoder() -> fn(String) -> Result(
  BitArray,
  EncodeError,
)
pub fn string_sized_decoder() -> fn(BitArray) -> Result(
  #(String, BitArray),
  DecodeError,
)
pub fn subject() -> Codec(process.Subject(BitArray))

Subject codec, for the request/response pattern.

pub fn subject_decoder() -> fn(BitArray) -> Result(
  process.Subject(BitArray),
  DecodeError,
)
pub fn subject_encoder() -> fn(process.Subject(BitArray)) -> Result(
  BitArray,
  EncodeError,
)

Encode a Subject(BitArray) via term_to_binary. The PID inside carries node info, so it routes back cross-node.

Mirrors the 32-bit-prefix validation in string_encoder / bitarray_encoder / list_encoder. A Subject larger than 4 GiB is absurd in practice (it would imply a 4 GiB tag), but the bound is enforced for symmetry with the rest of the codec surface.

pub fn subject_sized_decoder() -> fn(BitArray) -> Result(
  #(process.Subject(BitArray), BitArray),
  DecodeError,
)
pub fn to_decoder(
  sized: fn(BitArray) -> Result(#(a, BitArray), DecodeError),
) -> fn(BitArray) -> Result(a, DecodeError)

Turn a SizedDecoder into a top-level Decoder with strict parsing.

The frame must consume the binary completely. Any unconsumed trailing bytes are a protocol violation (data smuggling, double payloads, framing bug) and surface as Error(InvalidBinary("trailing bytes ...")). Earlier drafts silently dropped the leftover.

Composite codecs that need to chain frames within one binary (lists, tuples) call the underlying SizedDecoder directly, so they keep working as before. Only the top-level entry point is strict.

Search Document