pub(crate) fn kvp_entries<F>(params: &[KeyValuePair], render: F) -> FieldValueExpand description
Render a Key-Value-Pair list as entries, in the order the wire carried them.
§Why a list and not a map keyed by name
Every draft models a parameter block as an ordered list of (Type, Value), with types ascending. Rendering it as a map keyed by the draft’s name for each type reads better and loses three things:
- Repeats. Two parameter definitions permit a message to carry their type more than once — AUTHORIZATION_TOKEN, and on drafts 19 and 20 the five Range Filters. A map has one slot per name, so two SUBGROUP_FILTERs under different SetIDs became the second one alone: the frame said “Subgroup 1-3 in set 0, or 10-12 in set 1” and the record said “10-12”, which is not a narrower reading of the request but a different one.
- Order. Drafts 16 and later require that “Parameters MUST be serialized in ascending order by Type” and answer a descending pair with a session close. A map has no order, so no vector could state that rule at all.
- Unknown types. A map has no name to key them under, so each draft
invented something: 11 through 14 dropped them, and the later ones parked
them in a second, differently-shaped
unknownarray beside the named ones. Two containers for one wire field.
An entry list has none of those problems and needs no special case for any
of them: a repeat is two entries, order is the list’s, and an unknown type
is an entry without a name.
§The entry
type is always present, as the lowercase hex of the Parameter Type. name
is present when the draft names that type. Then exactly one of:
value— the decoded value, when this codec models it. A varint renders as its number, a structure as a nested map.raw_hex— the value’s bytes, when it does not.
An unnamed varint parameter gets value rather than raw_hex, because a
varint’s value is its content and there are no bytes to show. That case
used to be written as length, which was the varint’s value under a key
naming something else entirely.