Expand description
Hybrid serialization tail for #[hopper::state(dynamic_tail = T)].
Hybrid fixed-head and variable-tail storage keeps hot fields directly addressable while bounding variable data:
Lets Hopper own the fixed-layout hot path while still supporting a dynamic tail for vectors, strings, and optional metadata.
§Wire format
After the layout’s fixed body (offset TYPE_OFFSET + WIRE_SIZE), the
tail is encoded as:
[ len: u32 LE ] [ payload: len bytes ]The fixed-body fast path remains fully zero-copy. code that never
touches the tail pays zero overhead. Tail access is explicit
(tail_read::<T>() / tail_write::<T>()), which is why the tail
is not zero-copy: the typed representation is reconstructed on
read and serialized on write.
§Canonical tail encoding (TailCodec)
TailCodec is a minimal Borsh-subset serializer:
- integers: native little-endian
[u8; N]: raw bytes, fixed width- bounded byte/string payloads: program-defined length prefix + bytes
Option<T>: 1-byte tag (0 = None, 1 = Some) + inner payload
Programs that need richer types (bounded strings, bounded vectors,
custom structs) implement TailCodec themselves; the framework does not
force a derive or pull Vec / String into the no-alloc runtime surface.
Structs§
- Bounded
String - Bounded UTF-8 string for Hopper dynamic tails.
- Bounded
Vec - Bounded dynamic vector for Hopper dynamic tails.
- SeqTail
Read - Read guard over a
Seq<T>tail acquired through aContext: owns the shared account byte borrow (narrowed to the tail region) and the segment-registry lease, yielding aTailSeqcursor viaseq. - SeqTail
Write - Write guard over a
Seq<T>tail acquired through aContext: owns the exclusive account byte borrow (narrowed to the tail region) and the segment-registry lease, yielding aTailSeqMutcursor viaseq_mut. - Tail
Bytes - Borrowed final raw-byte tail.
- TailSeq
- Streaming read cursor over a
Seq<T>tail region. - Tail
SeqIter - Iterator over a
TailSeq, yielding one decoded element per step. - Tail
SeqMut - Streaming write cursor over a
Seq<T>tail region. - TailStr
- Borrowed final UTF-8 tail.
Constants§
- SEQ_
LEN_ PREFIX - Byte width of the
Seq<T>count prefix (u32LE element count).
Traits§
- SeqElement
- A
TailElementwhose encoding has a fixed stride: every value encodes to exactlySTRIDEbytes (STRIDE == MAX_ENCODED_LEN, andencodealways writesSTRIDE). - Tail
Codec - Canonical serializer for dynamic-tail payloads.
- Tail
Element - Element type accepted by
#[tail(vec<T, N>)]in#[hopper::dynamic_account].
Functions§
- borrow_
address_ slice - Borrow one bounded address vector from a compact dynamic-tail payload.
- borrow_
bounded_ str - Borrow one bounded UTF-8 string from a compact dynamic-tail payload.
- read_
tail - Decode the tail as
T: TailCodec, checking that the encoded length exactly matches the u32 prefix. Extra bytes beyondT’s decode are a malformed-encoding signal. - read_
tail_ len - Read the tail’s u32-LE length prefix.
- seq_
capacity_ for - Live capacity (max element count) of a
Seq<T>tail region ofregion_lenbytes:(region_len - 4) / STRIDE. Zero if the region cannot even hold the count prefix. - seq_
region_ bytes_ for - Account allocation (tail region bytes) needed for a
Seq<T>of capacityn:4 + n*STRIDE. - tail_
capacity - Return the account bytes available after the tail length prefix.
- tail_
payload - Return a slice referencing just the tail payload bytes (excluding the 4-byte length prefix). Length-bounded by the u32 prefix.
- write_
tail - Encode
tailinto the account’s tail slot, rewriting the u32 length prefix. ReturnsAccountDataTooSmallwhen the existing account byte buffer can’t fit the encoded payload. in that case the caller shouldreallocfirst. - write_
tail_ payload - Write an already-encoded dynamic-tail payload.
Type Aliases§
- Hopper
String - Short alias for bounded UTF-8 strings in dynamic tails.
- Hopper
Vec - Short alias for bounded vectors in dynamic tails.