diff --git a/pcapkit/corekit/fields/collections.py b/pcapkit/corekit/fields/collections.py index ae0c7ec202..cbe2e06def 100644 --- a/pcapkit/corekit/fields/collections.py +++ b/pcapkit/corekit/fields/collections.py @@ -6,6 +6,7 @@ from typing import TYPE_CHECKING, Generic, TypeVar, cast from pcapkit.corekit.fields.field import FieldBase +from pcapkit.corekit.fields.numbers import NumberField from pcapkit.corekit.multidict import OrderedMultiDict from pcapkit.utilities.compat import List from pcapkit.utilities.exceptions import FieldValueError @@ -178,6 +179,29 @@ class OptionField(ListField, Generic[_TS]): This field is used to represent a list of fields, as in the case of lists of options and/or parameters in a protocol. + Note: + :meth:`self.unpack ` selects an option's schema by reading the + ``type_name`` field of ``base_schema`` **alone** off the front of the + option, instead of unpacking the whole base schema and keeping only that + one value. That is only the same read when three things hold of the type + field: + + 1. it is the base schema's **first** field, so that it is what sits at the + front of the option; + 2. it is a :class:`~pcapkit.corekit.fields.numbers.NumberField`, so that + :meth:`Schema.unpack ` + reads it through its ordinary per-field branch; + 3. its length is a fixed integer rather than a callable, so that its width + does not depend on packet data the shortcut has not read. + + All of that is true of every ``OptionField`` declared in this package. A + base schema registered from outside it -- c.f. + :mod:`pcapkit.foundation.registry` -- need not satisfy it, and is **not** + rejected: such a base schema is unpacked in full, exactly as it was before + the shortcut existed. It parses correctly and pays the cost of the second + parse. Only the shortcut is withheld, so a base schema whose type field + comes second cannot be silently misread. + """ @property @@ -228,6 +252,34 @@ def __init__(self, length: 'int | Callable[[dict[str, Any]], int]' = lambda _: - raise FieldValueError('Field