3.2.2.4. Struct-Like Objects#
The _StructLike protocol can be used to emulate struct types. Even though, pack()
and unpack() allow so-called partial struct-like objects, there won’t be a conversion
within struct class definitions. It is always recommended to implement all methods conforming
to the _StructLike protocol.
Special Methods for Struct-Like objects#
- object.__pack__(self, obj, context) None#
Invoked to serialize the given object into an output stream,
__pack__()is designed to implement the behavior necessary for packing a collection of elements or a single element. Accordingly, the input obj may be anIterableor a singular element.The absence of a standardized implementation for deserializing a collection of elements is deliberate. For example, all instances of the
PyStructFormattedFieldutilize the Python library struct internally to pack and unpack data. To optimize execution times, a collection of elements is packed and unpacked in a single call, rather than handling each element individually.The context must incorporate specific members, mentioned in Context. Any data input verification is implemented by the corresponding class.
__pack__()is invoked by thepack()method defined within this library. Its purpose is to dictate how input objects are written to the stream. It is crucial to note that the outcome of this function is ignored.Changed in version beta: The stream parameter has been removed and was instead moved into the context.
- object.__unpack__(self, context)#
Called to desersialize objects from an input stream (the stream is stored in the given context). The result of
__unpack__()is not going to be ignored.Every implementation is tasked with the decision of whether to support the deserialization of multiple elements concurrently. By default, the
Fieldclass stores all essential attributes required to determine the length of elements set for unpacking. The__unpack__()method is activated through theunpack()operation, integrated with the default struct classes — namely,Sequence,Struct, andField.Changed in version beta: The stream parameter has been removed and was instead moved into the context.
- object.__size__(self, context)#
This method serves the purpose of determining the space occupied by this struct, expressed in bytes. The availability of a context enables the execution of a
_ContextLambda, offering support for dynamically sized structs. Furthermore, for the explicit definition of dynamic structs, the option to raise aDynamicSizeErroris provided.
- object.__type__(self)#
The configuration of Structs incorporates type replacement before a dataclass is created. This feature was specifically introduced for documentation purposes. The optional
__type__()method allows for the specification of a type, with the default beingAnyif not explicitly defined.Note
The implementation of the
__type__()method is optional and, therefore, not mandatory as per the library’s specifications.The following example demonstrates the use of the sphinx-autodoc extension to document struct classes with the
S_REPLACE_TYPEoption enabled. Only documented members are displayed... autoclass:: examples.formats.nibarchive.NIBHeader() :members:
Will be displayed as:
- class NIBHeader#
Example class doc comment
- NIBHeader.magic: bytes#
example field doc comment
- NIBHeader.unknown_1: int#
second field doc comment
In this illustration, the extra parentheses at the end are included to prevent the automatic creation of constructors.
Struct containers#
- class.__struct__#
All models annotated with either
@structor@bitfieldfall into the category of struct containers. These containers store the additional class attribute__struct__().Internally, any types utilizing this attribute can be employed within a struct, bitfield, or sequence definition. The type of the stored value must be conforming to the
_StructLikeprotocol.
Template Containers#
- class.__template__#
All template classes store information about the used template type variables. Whether they are required or just positional. In addition, default inferred types are stored as well.
Protocols for Struct-like objects#
To represent a _StructLike object, all previously described methods must be implemented:
- class _StructLike[_IT, _OT]#
- __pack__(self, obj: _IT, context: _ContextLike) None#
- __unpack__(self, context: _ContextLike) _OT#
- __size__(self, context: _ContextLike) int#
- class _ContainsStruct[_IT, _OT]#
- __struct__: _StructLike[_IT, _OT]#
- class _SupportsPack[_IT]#
- __pack__(self, obj: _IT, context: _ContextLike) None#
- class _SupportsUnpack[_OT]#
- __unpack__(self, context: _ContextLike) _OT#
- class _SupportsSize#
- __size__(self, context: _ContextLike) int#