Bounded RFC 8941 / RFC 9651 parsing and canonical serialization.
All entry points require a RequestSeal.StructuredFields.Schema. Values retain
dictionary and parameter order; duplicates follow the RFC's last-value,
first-position rule. No type is authorized by recognizing its syntax. Errors
contain only bounded reasons and never return a partially parsed value.
Limits (keyword options) may only lower these ceilings: :max_bytes 65,536
(input or output), :max_members 1,024 (top-level encounters, including
duplicates), :max_inner_items 256 (per inner list), :max_parameters 256
(per item/list, including duplicates), :max_key_bytes 256,
:max_value_bytes 16,384 (decoded strings/bytes or token bytes), and
:max_nodes 4,096 (containers, items, and parameter encounters combined).
These are library resource ceilings, not protocol maximums.
All limits are positive integers. Grammar depth is fixed: top-level container,
optional inner list, item; inner lists cannot nest. Numeric syntax has the
RFC's 15-digit integer and 12+3-digit decimal bounds, including leading zeros.
parse_field/5 consumes the existing lossless RequestSeal.Message model,
combining matching occurrences in one explicitly selected section in order
with comma-space. It never merges headers with trailers or reads a body.
Its optional limits apply to both the combined bytes and the complete parse.
Missing fields and unavailable sections remain explicit failures.
Serializing an empty list or dictionary returns {:ok, ""}. The empty binary
means the caller must omit both the field name and field value from the HTTP
message, as specified by RFC 9651 Section 4.1.
It must not be emitted as an empty HTTP field. This keeps the serialization
result binary while leaving field emission to the caller.
iex> alias RequestSeal.StructuredFields, as: SF
iex> {:ok, schema} = SF.Schema.new(%{revision: :rfc8941, type: :item, item_types: [:integer]})
iex> {:ok, value} = SF.parse("42", schema)
iex> SF.serialize(value, schema)
{:ok, "42"}
iex> SF.parse("@42", schema)
{:error, %RequestSeal.StructuredFields.Error{reason: :revision_type}}The example integer is RFC 8941 Section 2's Foo-Example. This module performs no network, storage, cryptographic, authentication, or authorization operation.
Summary
Functions
Parse complete ASCII field bytes under an explicit schema and bounded work.
Combine ordered header or trailer occurrences and parse under optional lowered limits.
Serialize canonically; an empty binary means omit the field. Invalid values reject.
Functions
@spec parse(binary(), RequestSeal.StructuredFields.Schema.t(), keyword()) :: {:ok, RequestSeal.StructuredFields.Value.t()} | {:error, RequestSeal.StructuredFields.Error.t()}
Parse complete ASCII field bytes under an explicit schema and bounded work.
@spec parse_field( RequestSeal.Message.t(), binary(), RequestSeal.StructuredFields.Schema.t(), :headers | :trailers, keyword() ) :: {:ok, RequestSeal.StructuredFields.Value.t()} | {:error, RequestSeal.StructuredFields.Error.t()}
Combine ordered header or trailer occurrences and parse under optional lowered limits.
:unique_keys optionally lists dictionary keys (or :all) whose repeats reject with
:duplicate_key before deduplication, including across field occurrences.
It defaults to []; keys must use valid dictionary-key syntax, fit the key
byte ceiling, and number no more than :max_members. Other keys retain the
last-value, first-position rule. :unique_parameters defaults to false; true
rejects repeated parameter names on any member or inner item with
:duplicate_parameter, after the bounded parse completes.
@spec serialize( RequestSeal.StructuredFields.Value.t(), RequestSeal.StructuredFields.Schema.t(), keyword() ) :: {:ok, binary()} | {:error, RequestSeal.StructuredFields.Error.t()}
Serialize canonically; an empty binary means omit the field. Invalid values reject.