How to choose field types

Choose a field according to the value your application should receive and how its wire width is determined:

Encode fixed-width values

Annotation

Python value

Width

rustruct.I8 / rustruct.U8

int

1 byte

rustruct.I16 / rustruct.U16

int

2 bytes

rustruct.I32 / rustruct.U32

int

4 bytes

rustruct.I64 / rustruct.U64

int

8 bytes

rustruct.F32 / rustruct.F64

float

4 / 8 bytes

rustruct.Bool

bool

1 byte

Integer values are range-checked. Scalars use the containing structure’s byte order unless a nested structure declares its own.

Store fixed bytes

rustruct.raw()(length) reads and writes exactly length bytes:

from rustruct import Struct, U16, raw


class EthernetName(Struct):
    kind: U16
    address: bytes = raw(6)


value = EthernetName(kind=1, address=bytes.fromhex("001122334455"))
assert value.pack() == bytes.fromhex("0001 001122334455")

Offset

Bytes

Field

Value

0

2

kind

0x0001

2

6

address

00 11 22 33 44 55

Use const= for signatures and magic bytes. A const field is verified on unpack and does not need to be supplied on pack.

Store runtime-sized bytes

rustruct.slice() represents an owned bytes value:

from rustruct import Struct, U8, slice


class Blob(Struct):
    length: U8
    data: bytes = slice(len="length")

len can be a constant, "*", a field name, or an expression lambda. max adds a schema-specific allocation limit.

Decode text

rustruct.string() uses the same byte-length rules and decodes to str. Supported encodings are UTF-8, ASCII, and Latin-1; errors are strict.

from rustruct import Struct, U8, string


class Label(Struct):
    size: U8
    text: str = string(len="size")

Lengths count encoded bytes, not Unicode code points. rustruct.cstring() reads a NUL-terminated string and should normally specify max=.

Convert a wire value

rustruct.convert() wraps a scalar or descriptor with Python-level decode and encode functions:

import ipaddress

from rustruct import Struct, U32, convert


class Endpoint(Struct):
    address: object = convert(
        U32,
        decode=ipaddress.IPv4Address,
        encode=int,
    )

The core still handles the base wire value; conversion happens at the typed frontend boundary.

Add defaults and descriptions

rustruct.described() attaches a default, default factory, and help text to a plain scalar or nested-structure annotation:

from rustruct import Struct, U8, described


class Header(Struct):
    version: U8 = described(1, help="wire format version")

Help is schema metadata intended for inspection and generated documentation.