How to compile mapping-based schemas

Build the field sequence

Use the low-level API when field declarations are generated at runtime or when the application wants dictionaries instead of typed rustruct.Struct instances.

Create one Field(name, kind, opts) tuple per wire field:

from rustruct import Field, compile

fields = (
    Field(name="kind", kind="u8", opts={}),
    Field(name="length", kind="u16", opts={}),
    Field(name="payload", kind="bytes", opts={"len": ("ref", "length")}),
)
codec = compile(fields, byteorder="big")

The reference from payload makes length a derived field during pack.

Pack and unpack mappings

wire = codec.pack({"kind": 3, "payload": b"hello"})
assert wire == b"\x03\x00\x05hello"

decoded = codec.unpack(wire)
assert decoded == {
    "kind": 3,
    "length": 5,
    "payload": b"hello",
}

Use pack_into() or unpack_from() when the value occupies part of an existing buffer. Use parse() when a short buffer should return rustruct.Incomplete instead of raising an invalid-data error.

Apply safety limits

Pass max_default to cap dynamic byte fields without a smaller field-specific maximum, and max_count to cap arrays:

limited_codec = compile(
    fields,
    byteorder="big",
    max_default=1024 * 1024,
    max_count=4096,
)
assert limited_codec.min_size == 3

See Low-level schema language for every field kind, expression form, operation, and size attribute.