2.1.2. Extended Syntax#
Added in version 2.8.0.
The extended syntax introduces a declarative and type-checker-friendly way to define structs using ordinary Python classes. Instead of constructing structures through procedural builder calls, you describe the format directly through type annotations, decorators, and a small set of expressive field descriptors.
At the heart of this design is the idea that a structure definition should be
understandable at a glance, statically analyzable by tools such as Pyright or
MyPy, and immediately usable for packing and unpacking without auxiliary
boilerplate. A class defined with @struct or @bitfield is not merely
a container for data; it is the authoritative specification of how that data
exists in binary form.
2.1.2.1. The role of the field descriptor#
The generic descriptor f[PythonType, FieldSpec] is central to the extended
syntax. It decouples the Python representation of a field from the way it is
encoded in memory or on the wire.
When you write
value : f[str, CString(10)]
you are declaring that the user of the class interacts with a Python str, while
the underlying binary representation is a c-string occupying 10 characters. This
separation allows very expressive layouts without sacrificing clarity or type safety.
This becomes particularly powerful when fields depend on other fields:
length : uint8_t
name : f[str, String(this.length)]
2.1.2.2. Invisible Fields#
An important concept introduced by the extended syntax is the Invisible() field. Some parts
of a binary layout are required for correctness but should not appear in the constructor
or the public interface of the class. Examples include magic constants, padding, alignment
helpers, and Actions.
By assigning such fields using Invisible(), they remain part of the layout while disappearing from the type checker’s perspective:
magic : f[bytes, b"ABCDEF"] = Invisible()
This field is always present in the binary representation. It is written automatically when packing and verified automatically when unpacking, yet it does not appear as a constructor parameter and is ignored by type checkers when instantiating the class.