serializer
stdlib/core/serializer.hk: the Serializer format abstraction and the built-in binary serializer.
Serializer is the write side of the format-generic serialization framework (HANKI.md §16): the set of structural events an Encode walk emits, scalars, the presence of an Option, and the framing of sequences, maps, structs, and sum variants. A concrete serializer translates those events into one wire format; Encode impls name the events and remain format-agnostic, and a single @derive(Encode) serves every format.
BinarySerializer is the built-in format: the framework's own compact, fixed-width encoding (the layout that the pre-abstraction Encode produced). It wraps a BytesBuilder sink. Per-width integer methods keep it fixed-width; a self-describing format (cbor) ignores the declared width and encodes minimally. begin_struct! writes nothing (a struct's field count is static, recovered from the type on decode) and begin_variant! writes only the tag byte; a framed format uses the counts to emit an array/map header instead.
Every method is an action (!) with an empty effect row, like the BytesBuilder it drives (HANKI.md §4): it mutates the sink but commits no OS capability.
Serializer
trait Serializer
put_bool!
def put_bool!(self, b: bool) -> ()
Writes one bool into the output.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_u8!
def put_u8!(self, n: u8) -> ()
Writes one u8 into the output.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_u16!
def put_u16!(self, n: u16) -> ()
Writes one u16 into the output.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_u32!
def put_u32!(self, n: u32) -> ()
Writes one u32 into the output.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_u64!
def put_u64!(self, n: u64) -> ()
Writes one u64 into the output.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_i32!
def put_i32!(self, n: i32) -> ()
Writes one i32 into the output.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_i64!
def put_i64!(self, n: i64) -> ()
Writes one i64 into the output.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_f64!
def put_f64!(self, x: f64) -> ()
Writes one f64 into the output.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_string!
def put_string!(self, s: string) -> ()
Writes one string into the output.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_bytes!
def put_bytes!(self, b: bytes) -> ()
Writes one bytes into the output.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_none!
def put_none!(self) -> ()
Option: a None marker, or a Some marker followed by the payload's own encode!. @no-doctest: structural encode op; the round-trip tests below exercise it
put_some!
def put_some!(self) -> ()
Marks a present optional; the wrapped value follows.
@no-doctest: structural encode op; the round-trip tests below exercise it
begin_seq!
def begin_seq!(self, len: int) -> ()
Sequences and maps carry their element/pair count up front, then that many element encode!s (a map alternates key, value). @no-doctest: structural encode op; the round-trip tests below exercise it
begin_map!
def begin_map!(self, len: int) -> ()
Opens a map of the given length; entries follow pairwise.
@no-doctest: structural encode op; the round-trip tests below exercise it
begin_struct!
def begin_struct!(self, fields: int) -> ()
@derive composites: a struct's fields in declaration order, and a sum's variant tag with that variant's payload count, then the payload encode!s. @no-doctest: structural encode op; the round-trip tests below exercise it
begin_variant!
def begin_variant!(self, tag: u8, payloads: int) -> ()
Opens a sum variant by tag; its payload follows.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_int!
def put_int!(self, n: int) -> ()
-- the exact tier ------------------------------------------------------
int, decimal, rational and f32 are the four types @derive(Encode) used to refuse, and both language defaults are among them: an unsuffixed integer literal is int, an unsuffixed float is decimal. Each of these four events has a default body written over the twelve above, and a third-party Serializer written before they existed goes on compiling and gains a correct, if not compact, encoding at no cost. A self-describing format overrides them with its own numeric forms.
put_int! is the only ground case. The other two reduce to it through the exact decomposition (HANKI.md §3), which is also where their in-band sentinels are handled: a sentinel rides out in the first component, so put_int! handling inf/-inf/undefined covers all three types. Writes one arbitrary-precision int: a class byte (0 finite, 1 inf, 2 -inf, 3 undefined) and, when finite, the decimal digits as a string.
Digits and not magnitude bytes, int being unbounded and pure Hanki having no byte view of a bignum; extracting one would be a division loop per byte. The class byte is not optional: the sentinels have no digit spelling at all, and int.parse refuses "inf", and a digits-only encoding would lose the values division produces.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_decimal!
def put_decimal!(self, d: decimal) -> ()
Writes one decimal as its exact unscaled/scale pair (HANKI.md §3), each through put_int!. Lossless where put_f64! would round, and the sentinel travels in unscaled.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_rational!
def put_rational!(self, r: rational) -> ()
Writes one rational as its reduced numerator/denominator pair (HANKI.md §3), each through put_int!. The sentinel travels in numerator.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_f32!
def put_f32!(self, x: f32) -> ()
Writes one f32 as its IEEE bit pattern. Exact, and the only way in or out: no other name in core converts into f32, and the pattern is the value.
@no-doctest: structural encode op; the round-trip tests below exercise it
intclass
def _int_class(n: int) -> u8
The class byte put_int! writes ahead of an int, and _int_sentinel its inverse. 0 is finite (digits follow); the rest are the in-band sentinels, which have no digit spelling. Written as nested ifs in place of one elif chain: three ==-against-a-constant tests in one chain is H0618, and match has no pattern for a computed constant.
BinarySerializer
struct BinarySerializer
out: BytesBuilder
end
The built-in fixed-width binary format over a BytesBuilder sink.
BytesBuilder
BytesBuilder, or bytes.BytesBuilder, is a runtime-managed native resource handle (HANKI.md §4): live native state the per-actor memory manager owns, released when the last handle drops. It is single-owner - never copied, moved across a send - and has no fields of its own, so its methods are its whole surface. A handle is minted by an API that opens one; it is never constructed.
seru16_be!
def _ser_u16_be!(out: BytesBuilder, n: u16) -> ()
seru32_be!
def _ser_u32_be!(out: BytesBuilder, n: u32) -> ()
seru64_be!
def _ser_u64_be!(out: BytesBuilder, n: u64) -> ()
impl Serializer<BinarySerializer>
put_bool!
def put_bool!(self, b: bool) -> ()
Writes one bool into the output.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_u8!
def put_u8!(self, n: u8) -> ()
Writes one u8 into the output.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_u16!
def put_u16!(self, n: u16) -> ()
Writes one u16 into the output.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_u32!
def put_u32!(self, n: u32) -> ()
Writes one u32 into the output.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_u64!
def put_u64!(self, n: u64) -> ()
Writes one u64 into the output.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_i32!
def put_i32!(self, n: i32) -> ()
Writes one i32 into the output.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_i64!
def put_i64!(self, n: i64) -> ()
Writes one i64 into the output.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_f64!
def put_f64!(self, x: f64) -> ()
Writes one f64 into the output.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_string!
def put_string!(self, s: string) -> ()
Writes one string into the output.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_bytes!
def put_bytes!(self, b: bytes) -> ()
Writes one bytes into the output.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_none!
def put_none!(self) -> ()
Writes one none into the output.
@no-doctest: structural encode op; the round-trip tests below exercise it
put_some!
def put_some!(self) -> ()
Marks a present optional; the wrapped value follows.
@no-doctest: structural encode op; the round-trip tests below exercise it
begin_seq!
def begin_seq!(self, len: int) -> ()
Opens a sequence of the given length; elements follow.
@no-doctest: structural encode op; the round-trip tests below exercise it
begin_map!
def begin_map!(self, len: int) -> ()
Opens a map of the given length; entries follow pairwise.
@no-doctest: structural encode op; the round-trip tests below exercise it
begin_struct!
def begin_struct!(self, fields: int) -> ()
A struct's field count is static, and the binary format writes no framing. @no-doctest: structural encode op; the round-trip tests below exercise it
begin_variant!
def begin_variant!(self, tag: u8, payloads: int) -> ()
Only the variant tag is written; the payload count is static per variant. @no-doctest: structural encode op; the round-trip tests below exercise it