.. _reference_core_operations: Core Operations =============== All public parsing and building helpers follow the same model: resolve a struct-like object, create a root :class:`~caterpillar.context.Context`, and delegate to the relevant protocol method. The most commonly used helpers are available from :mod:`caterpillar.py` and :mod:`caterpillar.model`. Packing ------- .. function:: pack(obj, struct=None, /, *, use_tempfile=False, as_field=False, order=None, arch=None, fill=None, **kwargs) Builds ``obj`` and returns the generated bytes. If ``struct`` is omitted, Caterpillar tries to infer it from ``obj`` via the ``__struct__`` container attribute. If ``struct`` is supplied and ``as_field=True`` is used, the value is wrapped in :class:`~caterpillar.fields.Field` before packing. Additional keyword arguments are copied into the root context and can be read with :data:`~caterpillar.context.ctx` or custom context paths. ``order`` and ``arch`` temporarily override the default byte order and architecture for the whole packing operation. This includes dynamic byte-order and pointer-size decisions that consult the root context. ``fill`` controls bytes inserted for holes created by offset fields. It may be ``None`` (the default ``b"\x00"``), ``bytes``, ``str`` or a single-byte integer. The fill pattern must evenly divide the gap it fills. .. function:: pack_into(obj, buffer, struct=None, /, *, use_tempfile=False, as_field=False, order=None, arch=None, fill=None, **kwargs) Builds ``obj`` and writes the result into ``buffer``. ``buffer`` must be a writable stream. When no offset fields are involved and the struct can safely write directly, Caterpillar writes to the target stream without the intermediate buffer used for offset reconciliation. If offset fields are encountered, packing falls back to the buffered path and applies the collected offset writes in order. ``use_tempfile=True`` forces the buffered path to use a temporary file rather than an in-memory buffer. This is mainly useful for very large outputs with offset writes. .. function:: pack_file(obj, filename, struct=None, /, *, use_tempfile=False, as_field=False, order=None, arch=None, fill=None, **kwargs) Opens ``filename`` in binary write mode and delegates to :func:`pack_into`. Unpacking --------- .. function:: unpack(struct, buffer, /, as_field=False, order=None, arch=None, **kwargs) Parses ``buffer`` with ``struct`` and returns the unpacked value. ``buffer`` can be bytes-like data or a readable stream. If ``as_field=True`` is used, Caterpillar wraps ``struct`` in :class:`~caterpillar.fields.Field` before unpacking. As with packing, ``order`` and ``arch`` temporarily override the operation defaults and ``kwargs`` are copied into the root context. Fixed-size primitive reads are exact: if the stream provides fewer bytes than required, unpacking raises :class:`~caterpillar.exception.ValidationError` instead of silently accepting a short value. .. function:: unpack_file(struct, filename, /, *, as_field=False, order=None, arch=None, **kwargs) Opens ``filename`` in binary read mode and delegates to :func:`unpack`. Size and type helpers --------------------- .. function:: sizeof(obj, **kwargs) Returns the static size of ``obj`` in bytes. ``obj`` may be a struct-like object, a class or instance that contains ``__struct__``, or any object implementing ``__size__(context)``. Keyword arguments are copied into the context before size calculation, which allows context-dependent static sizes to be evaluated. If the struct cannot determine an integer size, Caterpillar raises :class:`~caterpillar.exception.DynamicSizeError`. Dynamic or greedy layouts should therefore either be measured with enough context to make their size static or handled during actual packing/unpacking. .. function:: typeof(obj) Returns the Python type represented by ``obj``. If ``obj`` is a struct container, Caterpillar first resolves its ``__struct__`` value. It then calls ``__type__()`` when present. Missing, unimplemented or ``NotImplemented`` type hooks resolve to :class:`object`. .. function:: getbits(obj) Returns the number of bits represented by a bitfield-compatible object. ``__bits__`` may be either an integer attribute or a zero-argument callable. .. function:: issigned(obj) Returns whether ``obj`` declares signed integer semantics with ``__signed__``. Context created by operations ----------------------------- Top-level pack and unpack operations create a root context containing at least these operation-specific values: .. list-table:: :header-rows: 1 * - Key - Meaning * - ``_io`` - Active input or output stream. * - ``_path`` - Current logical path; the root path is ``""``. * - ``_parent`` - Parent context, ``None`` for the root context. * - ``_order`` - Effective byte order. * - ``_arch`` - Effective architecture. * - ``mode`` - Either pack or unpack mode. * - ``_offsets`` - Pack-only map used for deferred offset writes. Nested fields and models add field, object, index, and path information while they delegate to their child structs.