decode
stdlib/core/decode.hk: the Decode trait and its builtin impls.
Decode is the read half of the format-generic serialization framework (HANKI.md §16), the exact inverse of Encode. A type is Decode when it can read itself from any Deserializer (§ core deserializer): decode! pulls the structural events the matching Encode emitted and rebuilds the value, or returns a DecodeError on malformed input.
decode! is a static, no-self, trait method with its own bounded generic <D: Deserializer> (§10): a type is named in receiver position (i32.decode!(d, 0)) or reached through a bounded type parameter (T.decode!(d, 0)). The deserializer is a cursor that advances in place, so nothing threads a byte offset by hand. It is an action (!) with an empty effect row: it reads, and so mutates, the cursor, and commits no real-world capability. Every read is total, and malformed input yields an Err.
Decode
trait Decode
decode!
def decode!<D: Deserializer>(d: D, depth: int) -> Result<Self, DecodeError>
Reads a value of Self from the deserializer d, nested depth levels deep in the enclosing decode. codec.from_bytes seeds depth at 0; every recursive container / @derive(Decode) body reads its children at depth + 1 and rejects past max_decode_depth with TooDeep, and a hostile deeply-nested value cannot grow the decode call stack without bound. Leaf impls ignore depth (they never recurse). @no-doctest: reads structural events from a deserializer; a concise example needs non-printable wire bytes, and the round-trip behaviour is covered by the test blocks below
impl Decode<bool>
decode!
def decode!<D: Deserializer>(d: D, depth: int) -> Result<bool, DecodeError>
Decodes a bool from the deserializer.
@no-doctest: see the trait method
impl Decode<u8>
decode!
def decode!<D: Deserializer>(d: D, depth: int) -> Result<u8, DecodeError>
Decodes a u8 from the deserializer.
@no-doctest: see the trait method
impl Decode<u16>
decode!
def decode!<D: Deserializer>(d: D, depth: int) -> Result<u16, DecodeError>
Decodes a u16 from the deserializer.
@no-doctest: see the trait method
impl Decode<u32>
decode!
def decode!<D: Deserializer>(d: D, depth: int) -> Result<u32, DecodeError>
Decodes a u32 from the deserializer.
@no-doctest: see the trait method
impl Decode<u64>
decode!
def decode!<D: Deserializer>(d: D, depth: int) -> Result<u64, DecodeError>
Decodes a u64 from the deserializer.
@no-doctest: see the trait method
impl Decode<i32>
decode!
def decode!<D: Deserializer>(d: D, depth: int) -> Result<i32, DecodeError>
Decodes a i32 from the deserializer.
@no-doctest: see the trait method
impl Decode<i64>
decode!
def decode!<D: Deserializer>(d: D, depth: int) -> Result<i64, DecodeError>
Decodes a i64 from the deserializer.
@no-doctest: see the trait method
impl Decode<f64>
decode!
def decode!<D: Deserializer>(d: D, depth: int) -> Result<f64, DecodeError>
Decodes a f64 from the deserializer.
@no-doctest: see the trait method
impl Decode<int>
decode!
def decode!<D: Deserializer>(d: D, depth: int) -> Result<int, DecodeError>
Decodes an int from the deserializer.
@no-doctest: see the trait method
impl Decode<decimal>
decode!
def decode!<D: Deserializer>(d: D, depth: int) -> Result<decimal, DecodeError>
Decodes a decimal from the deserializer.
@no-doctest: see the trait method
impl Decode<rational>
decode!
def decode!<D: Deserializer>(d: D, depth: int) -> Result<rational, DecodeError>
Decodes a rational from the deserializer.
@no-doctest: see the trait method
impl Decode<f32>
decode!
def decode!<D: Deserializer>(d: D, depth: int) -> Result<f32, DecodeError>
Decodes an f32 from the deserializer.
@no-doctest: see the trait method
impl Decode<string>
decode!
def decode!<D: Deserializer>(d: D, depth: int) -> Result<string, DecodeError>
Decodes a string from the deserializer.
@no-doctest: see the trait method
impl Decode<bytes>
decode!
def decode!<D: Deserializer>(d: D, depth: int) -> Result<bytes, DecodeError>
Decodes a bytes from the deserializer.
@no-doctest: see the trait method
maxdecodedepth
def max_decode_depth() -> int
Recursion-depth ceiling for the generic Decode path, matching json.parse's _max_depth, the parser's MAX_PARSE_DEPTH, and the .hanki_manifest decoder's MAX_TYPE_DEPTH (all 128). Each recursive container / derived decode! bumps the depth and rejects past this with TooDeep, and hostile deeply-nested bytes cannot overflow the decode call stack (a native stack overflow on the fuel-less AOT tier). The @derive(Decode) macro inlines the same 128; keep the two in sync.
Public because the ceiling is shared: core/map's Decode impl guards against the same number, and a second copy of it is a number that drifts.
max_decode_depth() => 128
listdecode!
def _list_decode!<T: Decode, D: Deserializer>(d: D, remaining: int, depth: int) -> Result<List<T>, DecodeError>
A counting loop. Per-element recursion would consume call stack proportional to the sequence on the AOT tier. depth is the element depth (the list bumped it once); each element decodes at it, and a nested sequence reaches the ceiling through the per-element decode!.
impl<T: Decode> Decode<List<T>>
decode!
def decode!<D: Deserializer>(d: D, depth: int) -> Result<List<T>, DecodeError>
Decodes a sequence back into a list.
@no-doctest: see the trait method
optiondecode_some!
def _option_decode_some!<T: Decode, D: Deserializer>(d: D, depth: int) -> Result<Option<T>, DecodeError>
impl<T: Decode> Decode<Option<T>>
decode!
def decode!<D: Deserializer>(d: D, depth: int) -> Result<Option<T>, DecodeError>
Decodes an absent value as None, a present one as Some.
@no-doctest: see the trait method