moqtap_codec/draft22/mod.rs
1//! MoQT wire codec for draft-22.
2//!
3//! **Draft-22 is draft-21 with one wire change, to `LOCATION_FILTER` (0x21).**
4//! Every message keeps its code point, every field its width and its place,
5//! every registry its rows, and the ALPN follows the draft's number:
6//! `moqt-22`.
7//!
8//! The filter's value opens with a `Location Filter Type`, and the type names
9//! which of `StartGroup`, `StartObject`, `EndGroupDelta` and `EndObject`
10//! follow (Section 9.20.9, Table 6):
11//!
12//! | Type | Fields | Meaning |
13//! |---|---|---|
14//! | 0x00 | none | no filter |
15//! | 0x01 | `StartGroup` | relative start, open-ended |
16//! | 0x02 | `StartGroup`, `StartObject` | absolute start, open-ended |
17//! | 0x03 | the above and `EndGroupDelta` | absolute start, ends with a group |
18//! | 0x04 | all four | absolute range |
19//! | 0x05 | none | Next Object, open-ended |
20//!
21//! "Any other Location Filter Type is a PROTOCOL_VIOLATION." No length
22//! precedes the type, so the parameter is self-delimiting the way a Location
23//! is, and a reader that cannot name the type cannot find the end of it.
24//!
25//! **Small values encode to the same bytes in draft-21 and draft-22, and some
26//! of them mean different things.** With every field a one-byte `vi64`,
27//! draft-21's `Length` equals the field count, and so equals the draft-22 type
28//! that names that many fields: `21 01 03` is a three-groups-back relative
29//! start in both. They part company elsewhere: `21 02 00 00` is the Next Object
30//! in draft-21 and the absolute start of the track, `{0, 0}`, here, where Next
31//! Object is `21 05`; and a two-byte field turns a draft-21 `Length` into a
32//! type that names more fields than are present. A test built only from small
33//! values cannot tell the two decoders apart.
34//!
35//! The rest of draft-22 is editorial, and it moved enough that **every
36//! section, table and figure reference in this module is draft-22's own.**
37//! Message Parameter definitions sit one section lower than in draft-21,
38//! every figure one number higher, and every table from 6 on one higher. Some
39//! rules left their section for a new one — the FETCH behaviours for Section
40//! 3.2, the SUBSCRIBE_TRACKS parameter rule for Section 3.6.2 — and several
41//! normative sentences were reworded, most of them to name a response by its
42//! request (FETCH_ERROR rather than REQUEST_ERROR, Section 1.5). The sites
43//! that quote them quote draft-22's wording.
44//!
45//! PUBLISH_NAMESPACE's field is named `Track Namespace Prefix` here (Section
46//! 9.14, Figure 18). The bytes are the ones draft-21 calls `Track Namespace`,
47//! and the Rust field keeps that name, so a consumer keyed on it reads every
48//! draft the same way.
49//!
50//! The rest of this list is what a reader coming from draft-19 needs:
51//!
52//! - **FETCH (0x16) has no `Fetch Type`.** Track Namespace and Track Name are
53//! inline fields of FETCH itself, in the positions they occupied inside
54//! draft-19's Standalone Fetch, and the range travels in the
55//! `LOCATION_FILTER` message parameter. The codepoint is draft-19's, so a
56//! draft-19 decoder reads the Number of Track Namespace Fields count as a
57//! Fetch Type and mis-parses in silence; there is no in-band version signal
58//! to catch it (Section 9.11)
59//! - **PUBLISH_STATE_NOTIFY (0x22)** is a publisher-only, unilateral report
60//! that a subscription's state changed for a reason other than a
61//! subscriber-sent REQUEST_UPDATE. It has no Request ID field — the message
62//! is identified by the bidirectional request stream it arrives on, like
63//! SUBSCRIBE_OK, PUBLISH_DONE and FETCH_OK (Section 9.10)
64//! - **Ranges are inclusive at both ends**, on subscriptions and on fetches.
65//! Draft-19's fetch end was "the last Object, plus 1; or 0 to indicate the
66//! entire Group"; neither convention exists here, and a draft-19 encoder
67//! ported forward with its end-location arithmetic intact fetches one object
68//! too many (Sections 3.3.1, 9.12)
69//! - **`FILL_PARAMETERS` (0x23)** is a length-prefixed parameter whose value is
70//! a nested parameter block, and whose mere presence on a SUBSCRIBE or a
71//! REQUEST_UPDATE asks the publisher to open a fill fetch stream
72//! (Section 9.20.15). A `LOCATION_FILTER` nested inside it is the
73//! type-led form, with no length of its own
74//! - **`INCLUDE_PROPERTIES` (0x35)** is a uint8 opt-out from Track Properties
75//! on the responding OK, default 1 (Section 9.20.21)
76//! - `SUBSCRIPTION_ENDED` (PUBLISH_DONE 0x3), `VERSION_NEGOTIATION_FAILED`
77//! (session 0x15) and `INVALID_JOINING_REQUEST_ID` (REQUEST_ERROR 0x32) are
78//! unassigned, and there is no Fetch Type registry
79//! - `PUBLISH_DONE.Stream Count`'s "unknown" sentinel is `2^64 - 1`, and the
80//! count includes fill fetch streams (Section 9.9)
81//! - `EXPIRES` (0x08) is the only parameter whose definition names
82//! `PUBLISH_OK`; a subscriber changes anything else with a REQUEST_UPDATE
83//! after it (Section 9.20)
84//! - The data-plane headers call their leading field `Type Flags` and state
85//! the validity rules in prose after the figure. Sections 11.2.1 and 11.3.1
86//! give **different** rule sets — subgroup's reserved bit 4 must be 1,
87//! datagram's must be 0, and subgroup has no "unspecified bit" clause
88//! because bits 0-6 are all specified for it
89//! - A fetch stream has a third End of Range marker, `End of Timed-Out Range`
90//! (Serialization Flags `0x20C`), for the Objects a relay abandoned when its
91//! `FILL_TIMEOUT` budget ran out (Section 11.4.1, Table 8)
92//!
93//! # Where this codec had to choose
94//!
95//! Draft-22 leaves several wire questions open. Each decision is recorded at
96//! the encode or decode site that makes it, and each says that the draft does
97//! not state it. They are, with the site that carries the comment:
98//!
99//! - `FILL_PARAMETERS`'s value begins with a `Number of Parameters` count —
100//! [`message::decode_fill_parameters`]
101//! - the `Type Delta` chain restarts inside `FILL_PARAMETERS` and the outer
102//! chain is unaffected — [`message::decode_fill_parameters`]
103//! - SUBSCRIBE_TRACKS admits `LOCATION_FILTER` and `FILL_PARAMETERS`, as
104//! Section 3.6.2 says and Section 9.18's list and their own definitions do
105//! not — [`message::parameter_in_scope`]
106//! - a non-minimally encoded `Type Flags` is accepted on receive and never
107//! emitted — [`data_stream::SubgroupHeader::decode`](crate::draft22::data_stream::SubgroupHeader::decode) and
108//! [`data_stream::DatagramHeader::decode`](crate::draft22::data_stream::DatagramHeader::decode)
109//! - `PUBLISH_DONE.Stream Count`'s `2^64 - 1` sentinel is indistinguishable
110//! from a well-formed exact count —
111//! [`message::publish_done_codes::STREAM_COUNT_UNKNOWN`]
112//! - `Object Payload Length` is present on an End-of-Range marker record,
113//! encoded as 0, and the ordinary delta arithmetic applies to the marker's
114//! two fields — [`data_stream::FetchObjectHeader`]
115//!
116//! # What this codec does not enforce
117//!
118//! REQUEST_UPDATE (Section 9.5) and REQUEST_OK (Section 9.3) list their
119//! parameters per kind of request: an update to a FETCH may carry only
120//! `AUTHORIZATION_TOKEN` and `SUBSCRIBER_PRIORITY`, a PUBLISH_OK only
121//! `EXPIRES`, and so on. Which list applies depends on the request the frame
122//! answers or updates, which is session state and not in the frame, so
123//! [`message::parameter_in_scope`] holds each of the two messages to the
124//! union of its lists. A parameter inside the union and outside the list for
125//! its own request passes this codec; refusing it is the session's job, and
126//! nothing in this crate does it.
127
128#[allow(missing_docs)]
129pub mod data_stream;
130pub mod error_codes;
131/// This draft's field names for a decoded control message.
132pub mod fields;
133#[allow(missing_docs)]
134pub mod message;
135#[allow(missing_docs)]
136pub mod types;