Named constants¶
The core recognises a closed set of field kinds, digest algorithms, byte
orders, text encodings and error kinds. Each of these has a name you can
import, so a schema does not have to spell them as bare strings and a typo
is visible to a type checker and an editor rather than only to compile().
Every one of them is an enum.StrEnum, so a member is the
string it replaces. Naming a value never changes what gets compiled, and
plain strings keep working everywhere they worked before:
from rustruct import Algo, ByteOrder, Kind, compile
named = compile(
(
("tag", Kind.U8, {}),
("crc", Kind.DIGEST, {"algo": Algo.CRC32, "over": "*"}),
),
byteorder=ByteOrder.BIG,
)
plain = compile(
(
("tag", "u8", {}),
("crc", "digest", {"algo": "crc32", "over": "*"}),
),
byteorder="big",
)
assert named.pack({"tag": 7}) == plain.pack({"tag": 7})
assert Kind.U8 == "u8"
Field kinds¶
rustruct.Kind names every kind compile() accepts: the fixed
scalars U8/I8 through U64/I64, F32, F64 and BOOL; the byte and
text kinds RAW, BYTES, STR and CSTR; BITS and FLAGS; the
composites STRUCT, ARRAY, SWITCH and COND; and DIGEST.
Annotate a position that accepts one as rustruct.vocab.KindArg, not as
Kind — plain strings are part of the contract, and a bare Kind
annotation would reject them.
Digest algorithms¶
rustruct.Algo names what rustruct.digest() can compute.
CRCs and the Internet checksum produce an integer field; the hashes produce
bytes of their natural width.
Member |
Wire name |
Field width |
Notes |
|---|---|---|---|
|
|
2 bytes |
CRC-16/IBM-3740, also known as CCITT-FALSE |
|
|
2 bytes |
CRC-16/ARC |
|
|
4 bytes |
the usual zlib/PNG polynomial |
|
|
4 bytes |
Castagnoli |
|
|
8 bytes |
|
|
|
2 bytes |
RFC 1071 Internet checksum (IPv4 headers) |
|
|
16 bytes |
|
|
|
20 bytes |
|
|
|
32 bytes |
|
Pass poly=, init=, xorout=, refin= or refout= to vary a CRC model
away from its preset.
Byte order¶
rustruct.ByteOrder has BIG, LITTLE and NETWORK. NETWORK
compiles to exactly what BIG does, and documents intent the way the
standard library’s struct format character ! does. It is a member in its
own right rather than an enum alias, so it carries the value "network"
and does not compare equal to BIG.
There is deliberately no NATIVE: the core refuses it, because it would
make the wire format depend on whichever machine happened to do the
encoding.
Text encodings¶
rustruct.Encoding has UTF8, ASCII and LATIN1 — a much
smaller set than Python’s own codec registry, because these three are what
the core implements. Spellings are normalised exactly as the core normalises
them, so "UTF-8", "utf8" and "utf_8" all resolve to Encoding.UTF8,
and "us-ascii" and "iso-8859-1" resolve to Encoding.ASCII and
Encoding.LATIN1.
errors= is not an enum: the core implements exactly one policy,
"strict".
Flag rest policy¶
rustruct.RestPolicy decides what a flags field does with bits
that no name in it covers: KEEP reports them under the
rustruct.REST_KEY key ("_rest") and accepts one back on pack,
STRICT rejects any uncovered set bit, and IGNORE drops them on read and
writes zeros.
Error kinds¶
rustruct.ErrorKind names every value that can appear as
InvalidDataError.kind or
PackError.kind, so branching on one does not
depend on retyping a string correctly:
from rustruct import ErrorKind, InvalidDataError, compile
codec = compile((("x", "u32", {}),))
try:
codec.unpack(b"\x00")
except InvalidDataError as exc:
assert exc.kind == ErrorKind.TRUNCATED
Unpack can report TRUNCATED, TRAILING, RANGE, NEGATIVE_LEN,
OVERFLOW, DIV_ZERO, UNTERMINATED, NUL_IN_CSTR, NO_CASE, DECODE,
LIMIT, DEPTH, CHECKSUM, CONST and RESERVED_BITS. Pack can report
MISSING, LENGTH, INDIVISIBLE, INCONSISTENT, BUFFER,
UNKNOWN_FLAG, TYPE and ENCODE.
DEPTH is the one a schema from rustruct.compile() cannot produce:
unpacking allows 64 nested structures, and a schema needing more is refused
at compile time rather than left to fail on every input.
Expression operators¶
rustruct.BinOp names the heads an expression tuple can carry:
ADD, SUB, MUL, DIV, SHL, SHR, AND, OR, XOR, EQ, NE,
LT, LE, GT and GE. Ordinary Python operators on a field reference
build these, so it is mainly of interest when writing expression tuples by
hand — see Low-level schema language.
Signatures¶
- class rustruct.Kind(*values)[source]¶
Every field kind
rustruct.compile()recognises.tests/test_vocabulary.pycompiles a minimal schema for each member, so a kind that stops being accepted fails a test rather than drifting silently.- U8 = 'u8'¶
- I8 = 'i8'¶
- U16 = 'u16'¶
- I16 = 'i16'¶
- U32 = 'u32'¶
- I32 = 'i32'¶
- U64 = 'u64'¶
- I64 = 'i64'¶
- F32 = 'f32'¶
- F64 = 'f64'¶
- BOOL = 'bool'¶
- RAW = 'raw'¶
- BYTES = 'bytes'¶
- STR = 'str'¶
- CSTR = 'cstr'¶
- BITS = 'bits'¶
- FLAGS = 'flags'¶
- STRUCT = 'struct'¶
- ARRAY = 'array'¶
- SWITCH = 'switch'¶
- COND = 'cond'¶
- DIGEST = 'digest'¶
- class rustruct.Algo(*values)[source]¶
Digest algorithms
rustruct.digest()can compute.The CRC members name Rocksoft models; pass
poly=/init=/xorout=/refin=/refout=to vary one. CRCs andIPproduce an integer field; the hashes producebytesof their natural width (16, 20 and 32 bytes respectively).- CRC16_CCITT = 'crc16_ccitt'¶
CRC-16/IBM-3740, also known as CCITT-FALSE.
- CRC16_IBM = 'crc16_ibm'¶
CRC-16/ARC.
- CRC32 = 'crc32'¶
- CRC32C = 'crc32c'¶
Castagnoli.
- CRC64_XZ = 'crc64_xz'¶
- IP = 'ip'¶
RFC 1071 Internet checksum (IPv4 headers).
- MD5 = 'md5'¶
- SHA1 = 'sha1'¶
- SHA256 = 'sha256'¶
- class rustruct.ByteOrder(*values)[source]¶
Wire byte order.
NETWORKcompiles to exactly whatBIGdoes – same program, same bytes – and exists as its own spelling because it documents intent the way thestructmodule’s!does. It is not an alias in theenumsense: it is a distinct member with the value"network", soByteOrder.NETWORK == ByteOrder.BIGis false. Compare what a codec produces, not the member you passed.There is deliberately no
NATIVE: the core refuses it, since it would make the wire format depend on the machine doing the encoding.- BIG = 'big'¶
- LITTLE = 'little'¶
- NETWORK = 'network'¶
- class rustruct.Encoding(*values)[source]¶
Text encodings
str/cstrfields can use.A much smaller set than Python’s own codec registry – the core implements exactly these three. The only set here whose wire spellings are not
name.lower(), and the only one that accepts aliases, so it stays a written-out class:"UTF-8","utf8"and"utf_8"all resolve toUTF8, and"us-ascii"/"iso-8859-1"resolve toASCII/LATIN1.- UTF8 = 'utf-8'¶
- ASCII = 'ascii'¶
- LATIN1 = 'latin-1'¶
- class rustruct.RestPolicy(*values)[source]¶
What a
flagsfield does with bits no name in it covers.- STRICT = 'strict'¶
Reject any set bit that no name covers.
- IGNORE = 'ignore'¶
Drop them on read, write zeros on pack.
- class rustruct.ErrorKind(*values)[source]¶
The
kindattribute ofrustruct.InvalidDataErrorandrustruct.PackError.A closed set (
crates/rustruct/src/error.rs, “closed list, v1”) that until now reached Python as an unnamed string, soif exc.kind == "truncated"was a typo away from a branch that could never be taken. Members compare equal to those strings, so existing comparisons keep working unchanged.- TRUNCATED = 'truncated'¶
The buffer ended before the schema did.
- RANGE = 'range'¶
- NEGATIVE_LEN = 'negative_len'¶
- OVERFLOW = 'overflow'¶
- DIV_ZERO = 'div_zero'¶
- UNTERMINATED = 'unterminated'¶
A
cstrran to the end of its region without a NUL.
- NUL_IN_CSTR = 'nul_in_cstr'¶
- NO_CASE = 'no_case'¶
A
switchtag matched no case and there was no default.
- DECODE = 'decode'¶
Bytes that are not valid text in the field’s encoding.
- LIMIT = 'limit'¶
A length or count exceeded its
max.
- DEPTH = 'depth'¶
Nesting exceeded the 64-frame limit.
Not reachable from
rustruct.compile(), which refuses a schema that deep rather than letting it fail on every input.
- CHECKSUM = 'checksum'¶
- CONST = 'const'¶
- RESERVED_BITS = 'reserved_bits'¶
- MISSING = 'missing'¶
No value supplied for a field that needs one.
- LENGTH = 'length'¶
- INDIVISIBLE = 'indivisible'¶
- INCONSISTENT = 'inconsistent'¶
A supplied value contradicts what the schema derives.
- BUFFER = 'buffer'¶
The destination buffer is too small or not writable.
- UNKNOWN_FLAG = 'unknown_flag'¶
- TYPE = 'type'¶
A value of the wrong Python type for the field.
- ENCODE = 'encode'¶
- class rustruct.BinOp(*values)[source]¶
Operations an expression tuple’s head can name.
Ordinary Python operators on a field reference build these, so this is mostly of interest when writing expression tuples by hand.
- ADD = 'add'¶
- SUB = 'sub'¶
- MUL = 'mul'¶
- DIV = 'div'¶
- SHL = 'shl'¶
- SHR = 'shr'¶
- AND = 'and'¶
- OR = 'or'¶
- XOR = 'xor'¶
- EQ = 'eq'¶
- NE = 'ne'¶
- LT = 'lt'¶
- LE = 'le'¶
- GT = 'gt'¶
- GE = 'ge'¶
- rustruct.REST_KEY¶
The key
RestPolicy.KEEPreports uncovered flag bits under:"_rest".