Composite Fields
Composite fields combine multiple values or conditional logic.
Available Types
Array- Repeated field valuesEmbeddedStruct- Nested structConditional- Optional field based on conditionSwitch- Tagged union (variant type)
Array
Array of repeated field values:
from pystructs import Struct, UInt8, UInt16, Array, Ref
class ScoreBoard(Struct):
count = UInt8()
scores = Array(UInt16(), count=Ref("count"))
board = ScoreBoard.parse(b"\x03\x64\x00\xc8\x00\x2c\x01")
print(board.scores) # [100, 200, 300]
EmbeddedStruct
Nested struct within another struct:
from pystructs import Struct, UInt32, UInt8, EmbeddedStruct
class Header(Struct):
magic = UInt32(default=0xDEADBEEF)
version = UInt8(default=1)
class Packet(Struct):
header = EmbeddedStruct(Header)
payload_size = UInt16()
packet = Packet.parse(b"\xef\xbe\xad\xde\x01\x00\x10")
print(packet.header.magic) # 3735928559
Conditional
Field that only exists when a condition is met:
from pystructs import Struct, UInt8, UInt32, Conditional, Ref
class VersionedPacket(Struct):
version = UInt8()
# Only present in version 2+
extended_header = Conditional(
UInt32(),
when=Ref("version") >= 2,
)
data = UInt8()
# Version 1: no extended header
v1 = VersionedPacket.parse(b"\x01\x42")
print(v1.extended_header) # None
# Version 2: with extended header
v2 = VersionedPacket.parse(b"\x02\x00\x00\x00\x01\x42")
print(v2.extended_header) # 1
Switch
Tagged union - select struct based on discriminator:
from pystructs import Struct, UInt8, UInt16, Switch, Ref
class TextPayload(Struct):
length = UInt8()
class BinaryPayload(Struct):
size = UInt16()
class Message(Struct):
msg_type = UInt8()
payload = Switch(
discriminator=Ref("msg_type"),
cases={
1: TextPayload,
2: BinaryPayload,
},
)
text_msg = Message.parse(b"\x01\x05")
print(text_msg.payload.length) # 5
API Reference
- class pystructs.fields.composite.Array(item_field: BaseField, count: int | Ref, default: List | None = None, required: bool = True, validators: List[Callable] | None = None)[source]
Array of repeated fields.
Count can be specified as a fixed integer or as a Ref to another field.
- Examples:
>>> class Packet(Struct): ... count = UInt16() ... items = Array(UInt32(), count=Ref('count')) ... >>> class FixedArray(Struct): ... values = Array(UInt8(), count=10)
- get_count(instance: Struct) int[source]
Get the current count of items.
- Args:
instance: The struct instance
- Returns:
Number of items
- get_size(instance: Struct) int[source]
Get the total size of this array.
- Args:
instance: The struct instance
- Returns:
Total size in bytes
- class pystructs.fields.composite.EmbeddedStruct(struct_class: Type[Struct], default: Struct | None = None, required: bool = True, validators: List[Callable] | None = None)[source]
Embedded struct field.
Contains a nested Struct as a field value. The nested struct maintains a parent reference for Ref path resolution.
- Examples:
>>> class Header(Struct): ... magic = UInt32(default=0xDEADBEEF) ... version = UInt8(default=1) ... >>> class Packet(Struct): ... header = EmbeddedStruct(Header) ... data = Bytes(size=10)
- get_size(instance: Struct) int[source]
Get the size of the embedded struct.
- Args:
instance: The struct instance
- Returns:
Size in bytes
- class pystructs.fields.composite.Conditional(field: BaseField, when: Callable[[Struct], bool] | RefComparison | RefLogical, default: Any = None, required: bool = False, validators: List[Callable] | None = None)[source]
Conditional field that only exists when a condition is met.
The when parameter determines if the field exists. It can be: - A callable taking the instance and returning bool - A RefComparison (e.g., Ref(‘version’) >= 2) - A RefLogical (combined comparisons)
- Examples:
>>> class Packet(Struct): ... version = UInt8() ... # Only present in version 2+ ... extra_data = Conditional(UInt32(), when=Ref('version') >= 2) ... >>> class Message(Struct): ... flags = UInt8() ... # Present when flags bit 0 is set ... optional = Conditional(UInt16(), when=lambda s: s.flags & 1)
- get_size(instance: Struct) int[source]
Get the size of the conditional field.
- Args:
instance: The struct instance
- Returns:
Size in bytes (0 if condition not met)
- class pystructs.fields.composite.Switch(discriminator: Ref | Callable[[Struct], Any], cases: Dict[Any, BaseField | Type[Struct]], default: BaseField | Type[Struct] | None = None, required: bool = True, validators: List[Callable] | None = None)[source]
Field that can be one of multiple types based on a discriminator.
Switch selects between different field types based on the value of another field. This is useful for tagged unions and variant types.
- Examples:
>>> class Message(Struct): ... msg_type = UInt8() ... payload = Switch( ... discriminator=Ref('msg_type'), ... cases={ ... 1: TextPayload, ... 2: BinaryPayload, ... 3: StatusPayload, ... }, ... default=RawPayload, ... )
- get_size(instance: Struct) int[source]
Get the size of the selected field.
- Args:
instance: The struct instance
- Returns:
Size in bytes