hanki

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