Skip to main content

Module marshal

Module marshal 

Source
Expand description

Marshalling between the interpreter’s RuntimeValue and the Send-able [RtPayload] that crosses task/thread boundaries through channels.

materialize moves a value OUT of a task’s Rc-based heap into an owned, self-contained RtPayload; rebuild reconstructs a fresh Rc-based value in the receiving task’s heap. The pair mirrors RuntimeValue::deep_clone but crosses the Send boundary. Values that cannot cross (closures) yield a MarshalError; the Send/escape analysis (Phase 4) rejects them statically, so this is a defensive backstop, not the primary gate.

Structs§

Negotiated
The encoding choices negotiated for sending TO a peer, from my profile and the peer’s advertised one.
PeerProfile
A peer’s PUBLISHED acceptance surface — the single declarative object it EXPOSES to the other side AND that its own decoder ENFORCES. Declare it once: it is both advertised (in the handshake) and the budget the decode path checks, so the two can never drift. Carries the resource budget (ReceiveLimits), the peer’s type-registry epoch (a content hash of its type table — when both peers’ epochs match, struct/enum NAMES need not travel, since both derive the same ids), and a feature bitset (FEAT_*).
ReceiveLimits
A receiver’s admission-control budget — the limits it will accept from a sender, so a malicious or buggy peer cannot exhaust the receiver’s memory, stack, or CPU. Enforced DURING decode, BEFORE the offending allocation or recursion happens, so an over-budget message is refused cleanly (the decode returns None) rather than processed. A receiver advertises these in the capability handshake so a cooperative sender stays within them; an uncooperative one is still bounded by the enforcement.
WireSchemaCache
A connection-scoped schema dictionary (one per direction per peer). A struct schema (type name + field names) is transmitted ONCE and referenced thereafter — the RPC-grade win for streams of same-shaped struct messages. The mode picks the id scheme (see WireSchemaMode); every mode is corruption-free — a decoder that cannot resolve a reference returns None rather than mis-decoding. An optional keyframe interval re-emits a definition every k references so a late or lossy receiver self-heals.
WireStructsCursor
A parse-once cursor over a record-list view (T_STRUCTS_VIEW / T_STRUCTS_FVIEW): the schema and tables are read ONCE at open, then every (row, field) access is O(1) — pure arithmetic for the fixed-stride view, a two-u32 offset jump for the variable view — with no per-call re-scan.
WireTypeRegistry
A program-derived registry of every struct/enum schema, shared by both ends of a Logos↔Logos link (each side builds it from the SAME program type definitions). Every type gets a stable small id — canonical by fingerprint, so declaration order is irrelevant and sender + receiver always agree. The codec ships the id instead of the type/field NAMES, and the receiver — running the same program — resolves it. This is the “duh, you use that” default that drops names off the wire entirely.
WireView
A borrowed view over one wire message’s top-level value. Holds no owned data and never decodes the rest of the message; reads are in place. Open it with view_message.

Enums§

GenCmp
GenExpr
A restricted, pure, TOTAL expression over the element index i. Every op is total (div/mod by zero is 0, wrapping i64 arithmetic), and a malformed/hostile tree is bounded at decode by a node budget + depth cap, so evaluation can never panic, diverge, overflow, or escape.
MarshalError
Why a value could not be marshalled across a task boundary.
WireCodec
The wire encoding for a message body.
WireColumn
One column of a build_columnar_record message — a borrowed slice that lands in the wire’s zero-copy aligned layout with no intermediate RuntimeValue.
WireCompression
The compression codec for an encoded body — the sender’s dial. The wire is self-describing (the header carries the codec), so this is purely a sender preference; any peer decodes any codec. Each is kept only if it actually shrank the body (see message_to_wire_with), so compression never hurts the fast path.
WireCompressionLevel
The compression effort dial — a sender-only preference (the codec output is self-describing, so the decoder needs no knowledge of the level). Fast favors throughput, Max favors ratio, Balanced is the default middle.
WireFloats
How float arrays are encoded. Memcpy is the raw 8-byte-per-element blob (the memory-bandwidth ceiling, the default). XorDelta XORs each value’s bits with the previous and varint-codes the result — lossless and bit-exact (it operates on raw bits, so NaN/Inf/±0/subnormals are preserved), and far smaller for slowly-varying (time-series) columns. It is applied per-column only when it actually shrinks the column, so it never grows a message.
WireGoal
What the message_to_wire_best auto-tuner optimizes for.
WireIntegrity
Whether a message carries an integrity checksum.
WireNumerics
How integer arrays are laid out on the wire — the sender’s size↔speed dial. The decoder always handles every variant (each has its own tag), so this is purely a sender preference; mix freely on one relay.
WireSchemaMode
How a connection-scoped schema dictionary identifies a struct schema on the wire. All modes are corruption-free; they trade size against robustness.
WireStructure
Whether the encoder may replace a column with a closed-form generator when the data is mathematically structured — the Futamura move on the wire: if the values are described by a formula, ship the formula, not the values. Every form is lossless and gated by an exact-match proof, so it can never change the decoded value; the decoder always reconstructs (each form has its own tag). Off by default (detection is an O(n) scan the speed dials skip), opt-in per send.

Constants§

DEFAULT_RECEIVE_LIMITS
Generous-but-finite defaults: every real message passes (genuine nesting is almost always < 10 deep); only the pathological / adversarial ones are refused. max_depth sits BELOW [MAX_ENCODE_DEPTH] on purpose — the recursive DECODER’s stack frame is heavier than the encoder’s (one giant match), so the depth that is safe to recurse on a small (wasm ~1 MiB) stack is lower than what we allow ourselves to encode. A deployment tightens these per peer through the handshake.
FEAT_COMPUTED
The peer is willing to receive a shipped computation (subject to its acceptance contracts).
FEAT_DEFLATE
The peer understands DEFLATE-compressed frames.
FEAT_FEC
The peer can reconstruct FEC / erasure-coded redundant frames.
FEAT_LZ4
The peer understands LZ4-compressed frames.
FEAT_TYPE_ID
The peer can resolve type-id name elision against a shared type registry.
FEAT_ZSTD
The peer understands Zstd-compressed frames.

Functions§

best_compressed_len
The smallest body compresses to across the built-in compressors (deflate / lz4 / zstd), or its raw length when none helps — the “fair fight” size for an arbitrary byte string. This is the same shop-every-compressor rule message_to_wire_best’s Smallest goal applies to the LOGOS wire, exposed so a benchmark can grant a COMPETITOR codec the identical compression opportunity: then a size comparison is compressed-vs-compressed (fair), not compressed-LOGOS-vs-raw-competitor.
build_columnar_record
Build a columnar record message in place — Cap’n Proto’s home turf. The named columns are written DIRECTLY into the offset-table T_STRUCT_VIEW + T_*_ALIGNED wire layout from borrowed slices: no intermediate RuntimeValue, no second serialize pass over the data (each column is a single memcpy). The receiver opens it with view_message and reads ANY column in O(1) and zero-copy via WireView::struct_field + WireView::as_i64_slice/WireView::as_f64_slice.
decode_peer_profile
Parse a peer’s advertised PeerProfile. A version this build does not understand, or a truncated blob, yields None — the caller then falls back to the conservative defaults (never mis-decodes).
decode_value_raw
Decode a value produced by encode_value_raw (or by an AOT-generated wire_encode) back into a RuntimeValue. None on any malformed or trailing-byte input.
deframe_stream_message
Deframe a batch stream message into its values, in order. None if bytes is not a stream message; a frame that fails to decode is skipped (never a panic).
describe_columns
Name the structural encoding of each column in a native wire message — the codec explaining its own output, so “which dial won” is legible to a human. A single-column message (int / float / string / bool list, a set, an int-keyed map) yields one name; a record list (T_STRUCTS) yields one "field: encoding" per field. Empty for a shape it does not model (compressed, JSON, a bare scalar, or a malformed frame) — the caller then shows a generic label. It reuses the real decode dispatch to skip each column body, so it can never drift from the format it reports on.
encode_peer_profile
Serialize a PeerProfile for the handshake — a version byte (so a future layout is recognized, not mis-parsed) followed by the budget, epoch, and feature bits.
encode_value_raw
Encode ONE value as the plain, self-describing recursive wire form — no envelope, no framing, no columnar/compression/dedup transforms. This is the exact format the shared logicaffeine_data::wire core decodes, so a RuntimeValue encoded here round-trips through an AOT-generated type’s wire_decode (and vice versa). The speed-first form used to hand a program AST to a compile-once native partial evaluator.
frame_stream_message
Frame a sequence of values as one batch STREAM message: [magic][sender][framed value-message]*, each value length-delimited (via crate::concurrency::stream::frame_for_stream) so the receiver deframes them incrementally and reads each in place. ONE relay publish ships the whole batch — Kafka-style streaming that amortizes per-message overhead — and Await stream reassembles the list. Each value is encoded self-describingly so it round-trips without the type registry.
gen_eval
Evaluate a generator at index i. TOTAL: div/mod by zero is 0; all arithmetic wraps.
make_handshake_frame
Build a handshake frame advertising from’s PeerProfile: the magic prefix, the sender identity, then the serialized profile. Published like any message but recognized + absorbed (not delivered as data) by the receiver.
materialize
Move a value out of a task’s heap into a Send-able payload.
message_from_wire
Decode a wire message (from message_to_wire) into (sender, value), rebuilding the typed value in the local heap. Auto-detects the codec, integrity, and compression; a checksum mismatch, an unknown header, a bad inflate, trailing bytes, or any malformed input all return None — never a panic, never a half-rebuilt value.
message_from_wire_cached
As message_from_wire, but resolves schema references against cache and records schema definitions into it.
message_from_wire_view
message_to_wire
Encode a directed peer message for the relay wire: the sender’s inbox topic plus the FULL language value — scalars, collections, structs, inductives, nested, type tags and all — as compact bincode under the process default integrity ([default_integrity]). Closures, and channel/task handles (local to this process), cannot travel between machines and are reported with a clear error rather than silently dropped.
message_to_wire_auto
The genuine no-brainer — “just send it.” Runs the full WireGoal::Smallest bake-off ONLY when the payload is large enough for it to matter, and otherwise ships the plain default (so calling this on every message — including scalars and short strings — costs a single encode pass, not the N-pass search). The result is NEVER larger than the default, ALWAYS self-describing (so it interoperates with every peer, no hint), and round-trips exactly. This is the recommended default sender.
message_to_wire_best
The no-brainer encoder — “just use this.” Picks the Pareto-optimal dial combination for goal and ships it. Because every wire form is self-describing by its leading tag, this is purely an ENCODE-side decision: the decoder reconstructs via message_from_wire with no hint, so best interoperates with every existing peer.
message_to_wire_cached
As message_to_wire_with, but a known struct schema is sent by reference instead of inline (per the cache’s WireSchemaMode).
message_to_wire_negotiated
Encode a message TO a peer using EVERYTHING both sides support — the negotiated maximal crush. Applies all the self-describing dials (any peer decodes them) via the size bake-off, but restricts the receiver-capability knobs to the negotiated surface: only compression codecs the receiver can decode, and type-id NAME ELISION only when epochs matched (neg.use_type_id). Refuses to ship a computation the receiver declined. Stays MINIMAL in cost too: a tiny message that name-elision can’t help ships the plain default without paying for the search. Never larger than the default; always self-describing, so it round-trips on the receiver with no hint.
message_to_wire_with
As message_to_wire, with an explicit codec and integrity mode.
negotiate
Negotiate how to send TO a peer from my profile + the peer’s advertised one. CONSERVATIVE: a capability is used only when BOTH sides expose it. This is where “expose properly” pays off — the sender automatically restricts itself to exactly the surface the receiver published, so it never ships a form the receiver can’t decode, won’t run code the receiver declined, and stays under the receiver’s size budget.
parse_handshake_frame
Parse a handshake frame → (sender, advertised profile). None when data is not a handshake (no magic) or is malformed — so a data message is never mistaken for one, and an unknown/garbage profile is ignored rather than mis-applied.
peek_deferrable_sender
Decode a received message LAZILY when its top-level value is a self-describing record-list view (T_STRUCTS_VIEW): returns (sender, List(WireStructs)) holding the raw frame, so NO row is decoded until a field is touched — the production zero-copy receive (“no decode in production”, Cap’n Proto’s home). Any other shape (scalars, maps, single structs, cached/compressed bodies) falls back to a full message_from_wire decode, so every message still round-trips. The receiver opts in with the view knob; without it, the eager path is used exactly as before. Peek a frame: if its top-level value is a self-describing DEFERRABLE view — a record list (T_STRUCTS_VIEW) or an aligned numeric column (T_INTS_ALIGNED/T_FLOATS_ALIGNED), all of which have no schema-cache dependency — return the sender so its decode can be deferred to Await (lazy under view, eager otherwise). None for anything else (scalars, single structs, maps, cached, or compressed bodies), which must decode eagerly in arrival order. The drain loop uses this to split deferrable views from order-sensitive messages.
peek_stream_sender
Is bytes a batch stream message? If so, return its sender (so Await stream … from <peer> matches it). None for a normal message / FEC shard / anything else.
rebuild
Reconstruct a fresh Rc-based value in the receiving task’s heap.
view_message
Open a borrowed, zero-alloc view over bytes. None for a compressed or JSON message (those must be inflated/decoded first — the view is over raw native bytes) or a malformed frame. Reads any single field in place afterward.
with_compression
Back-compat convenience: compress with DEFLATE (what the bare Send compressed keyword selects).
with_compression_codec
Compress encoded bodies with codec (kept only if smaller) for the duration of f. Scoped so it never leaks.
with_compression_level
Set the compression effort for the duration of f. Scoped so it never leaks.
with_dedup
Encode f’s value with Rc-dedup ON: shared subtrees ship once + backrefs. Self-describing by tag, so the receiver rebuilds the sharing with no knob of its own. The default (OFF) is byte-unchanged.
with_fixed_numerics
Convenience for WireNumerics::Fixed (back-compat).
with_flat_lists
Run f with flat (columnar-free) list encoding forced on/off, restoring the prior value.
with_floats
Encode float arrays under mode for the duration of f. Scoped — never leaks.
with_integrity
The latency↔safety dial: run f with the checksum on (Checked) or off (Raw), overriding the process default for the duration. Scoped — never leaks. Raw is the fastest path (the FNV checksum is the bulk of small-message encode cost); Checked detects corruption. Pairs with with_numerics/with_compression_codec.
with_numerics
Encode integer arrays under n for the duration of f. Scoped — never leaks.
with_receive_limits
Decode under limits for the duration of f — the receiver’s admission gate. Restores the prior limits afterward (so it nests). Pair with message_from_wire.
with_struct_view
Encode structs in the offset-table T_STRUCT_VIEW layout for the duration of f, so a WireView reads any single field in O(1) (the Cap’n Proto-beating random-access mode). Larger than the packed forms — it is the speed end of the size↔speed dial.
with_structure
Enable structural (closed-form) integer encoding under s for the duration of f. Scoped — never leaks. See WireStructure.
with_type_registry
Install a shared type registry for the duration of f (consulted by BOTH encode and decode). Restores the previous registry on return or panic.