Skip to main content

moqtap_codec/draft20/
error_codes.rs

1//! Error, status and stream-reset code registries defined by
2//! draft-ietf-moq-transport-20.
3//!
4//! One enum per registry in the IANA Considerations section (Section 15.11). The
5//! registry tables list only Name, Code and Specification; the per-code prose in
6//! the variant docs is taken from the section each row cites.
7//!
8//! `from_u64` returns `None` for any value the draft does not assign. A peer may
9//! legitimately send a code from a later draft or a private extension, and an
10//! unrecognized code must not be a decode failure at this layer.
11//!
12//! Each of these four registries reserves `0x7f * N + 0x9D` for greasing
13//! (Section 14). That is a range rather than an assignment, so it gets no
14//! variant and `from_u64` reports it as unknown like any other unassigned value.
15//!
16//! Code points inside a registry are not contiguous; the gaps are the draft's.
17//!
18//! # What draft-20 took out
19//!
20//! Three code points that draft-19 assigned are unassigned here, and each is a
21//! hole rather than a renumbering — nothing moved into the space:
22//!
23//! * `VERSION_NEGOTIATION_FAILED` (session termination `0x15`), draft-19: "The
24//!   client didn't offer a version supported by the server." Version selection
25//!   has happened in the ALPN since draft-15, so there is no in-band
26//!   negotiation left to fail.
27//! * `INVALID_JOINING_REQUEST_ID` (REQUEST_ERROR `0x32`), draft-19: "In response
28//!   to a Joining FETCH, the referenced Request ID is not an Established
29//!   Subscription." Joining fetches went with the FETCH rewrite (Section 10.13).
30//! * `SUBSCRIPTION_ENDED` (PUBLISH_DONE `0x3`), draft-19: "The publisher reached
31//!   the end of an associated location filter." Draft-20 Section 5.1.2 removed
32//!   the behaviour with the code: "A publisher does not end a subscription
33//!   solely because the Largest Object advances past the end of the current
34//!   Location Filter."
35//!
36//! No code point was renumbered in any registry.
37
38/// Session termination error codes (draft-20 Section 15.11.1).
39///
40/// Sent as the error code when closing the Transport Session: the QUIC `CONNECTION_CLOSE` frame
41/// over native QUIC, or the `CLOSE_WEBTRANSPORT_SESSION` capsule over WebTransport. The per-code
42/// definitions are in Section 3.5 of the draft. Note that this draft assigns no code point 0x7,
43/// none in 0xA-0xF, and none at 0x15. 0x7 was last assigned by draft-17, as
44/// `INVALID_REQUIRED_REQUEST_ID`; drafts 14 through 16 used it for `TOO_MANY_REQUESTS`. Draft-18
45/// vacated it and draft-20 leaves it vacant. 0x15 is draft-20's own vacancy: draft-19 assigned it
46/// to `VERSION_NEGOTIATION_FAILED` and draft-20 removed the row.
47///
48/// The registry also reserves the code points `0x7f * N + 0x9D` for greasing (draft-20 Section
49/// 14). That is a range rather than an assignment, so it has no variant here and `from_u64`
50/// reports it as unknown.
51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52#[repr(u64)]
53pub enum SessionErrorCode {
54    /// `NO_ERROR` — The session is being terminated without an error.
55    NoError = 0x0,
56
57    /// `INTERNAL_ERROR` — An implementation specific error occurred.
58    InternalError = 0x1,
59
60    /// `UNAUTHORIZED` — The client is not authorized to establish a session.
61    Unauthorized = 0x2,
62
63    /// `PROTOCOL_VIOLATION` — The remote endpoint performed an action that was disallowed by the
64    /// specification.
65    ProtocolViolation = 0x3,
66
67    /// `INVALID_REQUEST_ID` — The endpoint received a Request ID with an incorrect least
68    /// significant bit for the sender, or a duplicate Request ID. See Section 10.1.
69    InvalidRequestId = 0x4,
70
71    /// `DUPLICATE_TRACK_ALIAS` — The endpoint attempted to use a Track Alias that was already in
72    /// use.
73    DuplicateTrackAlias = 0x5,
74
75    /// `KEY_VALUE_FORMATTING_ERROR` — The key-value pair has a formatting error.
76    KeyValueFormattingError = 0x6,
77
78    /// `INVALID_PATH` — The PATH parameter was used by a server, on a WebTransport session, or
79    /// the server does not support the path.
80    InvalidPath = 0x8,
81
82    /// `MALFORMED_PATH` — The PATH parameter does not conform to the rules in Section 10.3.1.2.
83    MalformedPath = 0x9,
84
85    /// `GOAWAY_TIMEOUT` — The session was closed because the peer took too long to close the
86    /// session in response to a GOAWAY (Section 10.4) message. See session migration (Section
87    /// 3.6).
88    GoawayTimeout = 0x10,
89
90    /// `CONTROL_MESSAGE_TIMEOUT` — The session was closed because the peer took too long to
91    /// respond to a control message.
92    ControlMessageTimeout = 0x11,
93
94    /// `DATA_STREAM_TIMEOUT` — The session was closed because the peer took too long to send data
95    /// expected on an open Data Stream (see Section 11). This includes fields of a stream header
96    /// or an object header within a data stream. If an endpoint times out waiting for a new
97    /// object header on an open subgroup stream, it MAY send a STOP_SENDING on that stream or
98    /// terminate the subscription.
99    DataStreamTimeout = 0x12,
100
101    /// `AUTH_TOKEN_CACHE_OVERFLOW` — The Session limit Section 10.3.1.3 of the size of all
102    /// registered Authorization tokens has been exceeded.
103    AuthTokenCacheOverflow = 0x13,
104
105    /// `DUPLICATE_AUTH_TOKEN_ALIAS` — Authorization Token attempted to register an Alias that was
106    /// in use (see Section 10.2.2).
107    DuplicateAuthTokenAlias = 0x14,
108
109    /// `MALFORMED_AUTH_TOKEN` — Invalid Auth Token serialization during registration (see Section
110    /// 10.2.2).
111    MalformedAuthToken = 0x16,
112
113    /// `UNKNOWN_AUTH_TOKEN_ALIAS` — No registered token found for the provided Alias (see Section
114    /// 10.2.2).
115    UnknownAuthTokenAlias = 0x17,
116
117    /// `EXPIRED_AUTH_TOKEN` — Authorization token has expired (Section 10.2.2).
118    ExpiredAuthToken = 0x18,
119
120    /// `INVALID_AUTHORITY` — The specified AUTHORITY does not correspond to this server or cannot
121    /// be used in this context.
122    InvalidAuthority = 0x19,
123
124    /// `MALFORMED_AUTHORITY` — The AUTHORITY value is syntactically invalid.
125    MalformedAuthority = 0x1A,
126
127    /// `TOO_MANY_REQUEST_UPDATES` — The endpoint received a REQUEST_UPDATE that exceeded the
128    /// per-stream limit communicated via the MAX_REQUEST_UPDATES Setup Option (Section 10.3.1.7).
129    TooManyRequestUpdates = 0x1B,
130}
131
132/// REQUEST_ERROR codes (draft-20 Section 15.11.2).
133///
134/// 0x32 is unassigned. Draft-19 gave it to `INVALID_JOINING_REQUEST_ID`, which answered a Joining
135/// FETCH; draft-20 deleted the joining mechanism along with the Fetch Type field it travelled in.
136///
137/// Section 10.6 states that REQUEST_ERROR is sent in response to any request: SUBSCRIBE, FETCH,
138/// PUBLISH, SUBSCRIBE_NAMESPACE, SUBSCRIBE_TRACKS, PUBLISH_NAMESPACE, TRACK_STATUS and
139/// REQUEST_UPDATE. The per-code definitions are in Section 10.6.2, which the registry table cites
140/// as Section 10.6.
141///
142/// Note that the shorter list naming only the first seven of those messages belongs to the
143/// `REDIRECT` code specifically, not to the registry as a whole.
144///
145/// The registry also reserves the code points `0x7f * N + 0x9D` for greasing (draft-20 Section
146/// 14). That is a range rather than an assignment, so it has no variant here and `from_u64`
147/// reports it as unknown.
148#[derive(Debug, Clone, Copy, PartialEq, Eq)]
149#[repr(u64)]
150pub enum RequestErrorCode {
151    /// `INTERNAL_ERROR` — An implementation specific or generic error occurred.
152    InternalError = 0x0,
153
154    /// `UNAUTHORIZED` — The subscriber is not authorized to perform the requested action on the
155    /// given track. This might be retryable if the authorization token is not yet valid.
156    Unauthorized = 0x1,
157
158    /// `TIMEOUT` — The subscription could not be completed before an implementation specific
159    /// timeout. For example, a relay could not establish an upstream subscription within the
160    /// timeout.
161    Timeout = 0x2,
162
163    /// `NOT_SUPPORTED` — The endpoint does not support the type of request.
164    NotSupported = 0x3,
165
166    /// `MALFORMED_AUTH_TOKEN` — Invalid Auth Token serialization during registration (see Section
167    /// 10.2.2).
168    MalformedAuthToken = 0x4,
169
170    /// `EXPIRED_AUTH_TOKEN` — Authorization token has expired (Section 10.2.2).
171    ExpiredAuthToken = 0x5,
172
173    /// `GOING_AWAY` — The endpoint has received a GOAWAY and MAY reject new requests.
174    GoingAway = 0x6,
175
176    /// `EXCESSIVE_LOAD` — The responder is overloaded and cannot process the request at this
177    /// time. The sender SHOULD use the Retry Interval to indicate when the request can be
178    /// retried.
179    ExcessiveLoad = 0x9,
180
181    /// `DOES_NOT_EXIST` — The track or namespace is not available at the publisher.
182    DoesNotExist = 0x10,
183
184    /// `INVALID_RANGE` — In response to SUBSCRIBE or FETCH, specified Filter or range of
185    /// Locations cannot be satisfied.
186    InvalidRange = 0x11,
187
188    /// `MALFORMED_TRACK` — In response to a FETCH, a relay publisher detected the track was
189    /// malformed (see Section 2.4.2).
190    MalformedTrack = 0x12,
191
192    /// `UNINTERESTED` — The subscriber is not interested in the track or namespace.
193    Uninterested = 0x20,
194
195    /// `PREFIX_OVERLAP` — In response to SUBSCRIBE_NAMESPACE or SUBSCRIBE_TRACKS, the namespace
196    /// prefix shares a common prefix with another subscription of the same type in the same
197    /// session. SUBSCRIBE_NAMESPACE and SUBSCRIBE_TRACKS have independent overlap spaces, so a
198    /// SUBSCRIBE_NAMESPACE and a SUBSCRIBE_TRACKS may share the same prefix.
199    PrefixOverlap = 0x30,
200
201    /// `NAMESPACE_TOO_LARGE` — In response to SUBSCRIBE_NAMESPACE or SUBSCRIBE_TRACKS, the
202    /// namespace prefix matches more publishers than the relay is willing to enumerate.
203    NamespaceTooLarge = 0x31,
204
205    /// `UNSUPPORTED_EXTENSION` — The track contains a Mandatory Track Property (see Section
206    /// 2.5.1) that the endpoint does not understand.
207    UnsupportedExtension = 0x33,
208
209    /// `REDIRECT` — The request cannot be fulfilled by this endpoint, but could succeed at the
210    /// location specified in the Redirect structure. The requester SHOULD establish a new session
211    /// to the provided URI (if present) and retry the request using the Full Track Name from the
212    /// Redirect (if present). This error code can appear in response to SUBSCRIBE, FETCH,
213    /// TRACK_STATUS, PUBLISH, PUBLISH_NAMESPACE, SUBSCRIBE_NAMESPACE, and SUBSCRIBE_TRACKS.
214    /// Relays are not required to follow redirects from upstream and MAY forward a REDIRECT
215    /// response to matching downstream requests. A relay MAY cache a REDIRECT response for a Full
216    /// Track Name for up to Retry Interval milliseconds and use it to respond to subsequent
217    /// matching requests without forwarding them upstream.
218    Redirect = 0x34,
219
220    /// `CONFLICTING_FILTERS` — In response to SUBSCRIBE_TRACKS, the filter parameters conflict
221    /// among too many subscribers to aggregate the subscription upstream or otherwise efficiently
222    /// service it.
223    ConflictingFilters = 0x35,
224
225    /// `INVALID_FILTER` — A filter parameter is invalid.
226    InvalidFilter = 0x36,
227}
228
229/// PUBLISH_DONE codes (draft-20 Section 15.11.3).
230///
231/// Carried in the Status Code field of PUBLISH_DONE. The per-code definitions are in Section
232/// 10.12 of the draft, which is Section 10.11 renumbered — PUBLISH_STATE_NOTIFY took 10.10 and
233/// pushed everything after it down by one.
234///
235/// 0x3 is unassigned. Draft-19 gave it to `SUBSCRIPTION_ENDED`; see this module's own
236/// documentation for why the code and the behaviour went together.
237///
238/// The registry also reserves the code points `0x7f * N + 0x9D` for greasing (draft-20 Section
239/// 14). That is a range rather than an assignment, so it has no variant here and `from_u64`
240/// reports it as unknown.
241#[derive(Debug, Clone, Copy, PartialEq, Eq)]
242#[repr(u64)]
243pub enum PublishDoneStatusCode {
244    /// `INTERNAL_ERROR` — An implementation specific or generic error occurred.
245    InternalError = 0x0,
246
247    /// `UNAUTHORIZED` — The subscriber is no longer authorized to subscribe to the given track.
248    Unauthorized = 0x1,
249
250    /// `TRACK_ENDED` — The track is no longer being published.
251    TrackEnded = 0x2,
252
253    /// `GOING_AWAY` — The subscriber or publisher issued a GOAWAY message.
254    GoingAway = 0x4,
255
256    /// `TOO_FAR_BEHIND` — The publisher's queue of objects to be sent to the given subscriber
257    /// exceeds its implementation defined limit.
258    TooFarBehind = 0x5,
259
260    /// `EXPIRED` — The publisher reached the timeout specified in SUBSCRIBE_OK.
261    Expired = 0x6,
262
263    /// `UPDATE_FAILED` — REQUEST_UPDATE failed on this subscription (see Section 10.9).
264    UpdateFailed = 0x8,
265
266    /// `EXCESSIVE_LOAD` — The publisher is overloaded and is terminating the subscription.
267    ExcessiveLoad = 0x9,
268
269    /// `MALFORMED_TRACK` — A relay publisher detected that the track was malformed (see Section
270    /// 2.4.2).
271    MalformedTrack = 0x12,
272}
273
274/// Stream reset error codes (draft-20 Section 15.11.4).
275///
276/// Section 3.3.4 says the application SHOULD use a relevant code from this registry when
277/// resetting, or sending STOP_SENDING on, any stream — data streams and request streams alike.
278/// The per-code definitions are in that same section.
279///
280/// Drafts 14 through 17, draft-17 Section 14.5.4 among them, titled this
281/// registry "Data Stream Reset Error Codes" and this crate names those drafts'
282/// enums `DataStreamResetErrorCode`. Draft-18 renamed it and widened it beyond
283/// data streams; draft-20 keeps both the name and the wider scope, so this enum
284/// takes that title.
285///
286/// The registry also reserves the code points `0x7f * N + 0x9D` for greasing (draft-20 Section
287/// 14). That is a range rather than an assignment, so it has no variant here and `from_u64`
288/// reports it as unknown.
289#[derive(Debug, Clone, Copy, PartialEq, Eq)]
290#[repr(u64)]
291pub enum StreamResetErrorCode {
292    /// `INTERNAL_ERROR` — An implementation specific error.
293    InternalError = 0x0,
294
295    /// `CANCELLED` — The stream was cancelled by either endpoint. For Subscriptions, PUBLISH_DONE
296    /// (Section 10.12) may have a more detailed status code.
297    Cancelled = 0x1,
298
299    /// `DELIVERY_TIMEOUT` — A delivery timeout (Section 8) was exceeded for this stream.
300    DeliveryTimeout = 0x2,
301
302    /// `SESSION_CLOSED` — The session is being closed.
303    SessionClosed = 0x3,
304
305    /// `GOING_AWAY` — The endpoint is rejecting this request because it has sent or received a
306    /// GOAWAY.
307    GoingAway = 0x4,
308
309    /// `TOO_FAR_BEHIND` — The corresponding subscription has exceeded the publisher's resource
310    /// limits and is being terminated (see Section 8).
311    TooFarBehind = 0x5,
312
313    /// `UNKNOWN_OBJECT_STATUS` — In response to a FETCH, the publisher is unable to determine the
314    /// status of the next Object in the requested range.
315    UnknownObjectStatus = 0x6,
316
317    /// `EXPIRED_AUTH_TOKEN` — The authorization token for the request has expired.
318    ExpiredAuthToken = 0x7,
319
320    /// `EXCESSIVE_LOAD` — The endpoint is overloaded and is resetting this stream.
321    ExcessiveLoad = 0x9,
322
323    /// `MALFORMED_TRACK` — A relay publisher detected that the track was malformed (see Section
324    /// 2.4.2).
325    MalformedTrack = 0x12,
326}
327
328impl SessionErrorCode {
329    /// Every Session Error Code draft-20 assigns, in ascending wire order.
330    ///
331    /// This is the set [`Self::from_u64`] accepts, written out so that it can
332    /// be enumerated: nothing can iterate an enum's variants, so a caller that
333    /// wants the registry has to be handed it. Writing it down is also what
334    /// lets a test state its claims about the registry itself rather than about
335    /// the range some sweep happens to reach — that this is the set `from_u64`
336    /// answers to, and that none of it lands in the range the draft reserves
337    /// for greasing.
338    pub const ALL: &[SessionErrorCode] = &[
339        SessionErrorCode::NoError,
340        SessionErrorCode::InternalError,
341        SessionErrorCode::Unauthorized,
342        SessionErrorCode::ProtocolViolation,
343        SessionErrorCode::InvalidRequestId,
344        SessionErrorCode::DuplicateTrackAlias,
345        SessionErrorCode::KeyValueFormattingError,
346        SessionErrorCode::InvalidPath,
347        SessionErrorCode::MalformedPath,
348        SessionErrorCode::GoawayTimeout,
349        SessionErrorCode::ControlMessageTimeout,
350        SessionErrorCode::DataStreamTimeout,
351        SessionErrorCode::AuthTokenCacheOverflow,
352        SessionErrorCode::DuplicateAuthTokenAlias,
353        SessionErrorCode::MalformedAuthToken,
354        SessionErrorCode::UnknownAuthTokenAlias,
355        SessionErrorCode::ExpiredAuthToken,
356        SessionErrorCode::InvalidAuthority,
357        SessionErrorCode::MalformedAuthority,
358        SessionErrorCode::TooManyRequestUpdates,
359    ];
360
361    /// Convert a raw u64 to a `SessionErrorCode`, if the draft assigns that code point.
362    ///
363    /// Returns `None` for any unassigned value, including the greasing range, so
364    /// that a peer sending a code this draft does not define cannot break decoding.
365    pub fn from_u64(v: u64) -> Option<Self> {
366        match v {
367            0x0 => Some(SessionErrorCode::NoError),
368            0x1 => Some(SessionErrorCode::InternalError),
369            0x2 => Some(SessionErrorCode::Unauthorized),
370            0x3 => Some(SessionErrorCode::ProtocolViolation),
371            0x4 => Some(SessionErrorCode::InvalidRequestId),
372            0x5 => Some(SessionErrorCode::DuplicateTrackAlias),
373            0x6 => Some(SessionErrorCode::KeyValueFormattingError),
374            0x8 => Some(SessionErrorCode::InvalidPath),
375            0x9 => Some(SessionErrorCode::MalformedPath),
376            0x10 => Some(SessionErrorCode::GoawayTimeout),
377            0x11 => Some(SessionErrorCode::ControlMessageTimeout),
378            0x12 => Some(SessionErrorCode::DataStreamTimeout),
379            0x13 => Some(SessionErrorCode::AuthTokenCacheOverflow),
380            0x14 => Some(SessionErrorCode::DuplicateAuthTokenAlias),
381            0x16 => Some(SessionErrorCode::MalformedAuthToken),
382            0x17 => Some(SessionErrorCode::UnknownAuthTokenAlias),
383            0x18 => Some(SessionErrorCode::ExpiredAuthToken),
384            0x19 => Some(SessionErrorCode::InvalidAuthority),
385            0x1A => Some(SessionErrorCode::MalformedAuthority),
386            0x1B => Some(SessionErrorCode::TooManyRequestUpdates),
387            _ => None,
388        }
389    }
390
391    /// Return the raw u64 value of this error code.
392    pub fn as_u64(self) -> u64 {
393        self as u64
394    }
395}
396
397impl RequestErrorCode {
398    /// Every Request Error Code draft-20 assigns, in ascending wire order.
399    ///
400    /// This is the set [`Self::from_u64`] accepts, written out so that it can
401    /// be enumerated: nothing can iterate an enum's variants, so a caller that
402    /// wants the registry has to be handed it. Writing it down is also what
403    /// lets a test state its claims about the registry itself rather than about
404    /// the range some sweep happens to reach — that this is the set `from_u64`
405    /// answers to, and that none of it lands in the range the draft reserves
406    /// for greasing.
407    pub const ALL: &[RequestErrorCode] = &[
408        RequestErrorCode::InternalError,
409        RequestErrorCode::Unauthorized,
410        RequestErrorCode::Timeout,
411        RequestErrorCode::NotSupported,
412        RequestErrorCode::MalformedAuthToken,
413        RequestErrorCode::ExpiredAuthToken,
414        RequestErrorCode::GoingAway,
415        RequestErrorCode::ExcessiveLoad,
416        RequestErrorCode::DoesNotExist,
417        RequestErrorCode::InvalidRange,
418        RequestErrorCode::MalformedTrack,
419        RequestErrorCode::Uninterested,
420        RequestErrorCode::PrefixOverlap,
421        RequestErrorCode::NamespaceTooLarge,
422        RequestErrorCode::UnsupportedExtension,
423        RequestErrorCode::Redirect,
424        RequestErrorCode::ConflictingFilters,
425        RequestErrorCode::InvalidFilter,
426    ];
427
428    /// Convert a raw u64 to a `RequestErrorCode`, if the draft assigns that code point.
429    ///
430    /// Returns `None` for any unassigned value, including the greasing range, so
431    /// that a peer sending a code this draft does not define cannot break decoding.
432    pub fn from_u64(v: u64) -> Option<Self> {
433        match v {
434            0x0 => Some(RequestErrorCode::InternalError),
435            0x1 => Some(RequestErrorCode::Unauthorized),
436            0x2 => Some(RequestErrorCode::Timeout),
437            0x3 => Some(RequestErrorCode::NotSupported),
438            0x4 => Some(RequestErrorCode::MalformedAuthToken),
439            0x5 => Some(RequestErrorCode::ExpiredAuthToken),
440            0x6 => Some(RequestErrorCode::GoingAway),
441            0x9 => Some(RequestErrorCode::ExcessiveLoad),
442            0x10 => Some(RequestErrorCode::DoesNotExist),
443            0x11 => Some(RequestErrorCode::InvalidRange),
444            0x12 => Some(RequestErrorCode::MalformedTrack),
445            0x20 => Some(RequestErrorCode::Uninterested),
446            0x30 => Some(RequestErrorCode::PrefixOverlap),
447            0x31 => Some(RequestErrorCode::NamespaceTooLarge),
448            0x33 => Some(RequestErrorCode::UnsupportedExtension),
449            0x34 => Some(RequestErrorCode::Redirect),
450            0x35 => Some(RequestErrorCode::ConflictingFilters),
451            0x36 => Some(RequestErrorCode::InvalidFilter),
452            _ => None,
453        }
454    }
455
456    /// Return the raw u64 value of this error code.
457    pub fn as_u64(self) -> u64 {
458        self as u64
459    }
460}
461
462impl PublishDoneStatusCode {
463    /// Every PUBLISH_DONE Status Code draft-20 assigns, in ascending wire order.
464    ///
465    /// This is the set [`Self::from_u64`] accepts, written out so that it can
466    /// be enumerated: nothing can iterate an enum's variants, so a caller that
467    /// wants the registry has to be handed it. Writing it down is also what
468    /// lets a test state its claims about the registry itself rather than about
469    /// the range some sweep happens to reach — that this is the set `from_u64`
470    /// answers to, and that none of it lands in the range the draft reserves
471    /// for greasing.
472    pub const ALL: &[PublishDoneStatusCode] = &[
473        PublishDoneStatusCode::InternalError,
474        PublishDoneStatusCode::Unauthorized,
475        PublishDoneStatusCode::TrackEnded,
476        PublishDoneStatusCode::GoingAway,
477        PublishDoneStatusCode::TooFarBehind,
478        PublishDoneStatusCode::Expired,
479        PublishDoneStatusCode::UpdateFailed,
480        PublishDoneStatusCode::ExcessiveLoad,
481        PublishDoneStatusCode::MalformedTrack,
482    ];
483
484    /// Convert a raw u64 to a `PublishDoneStatusCode`, if the draft assigns that code point.
485    ///
486    /// Returns `None` for any unassigned value, including the greasing range, so
487    /// that a peer sending a code this draft does not define cannot break decoding.
488    pub fn from_u64(v: u64) -> Option<Self> {
489        match v {
490            0x0 => Some(PublishDoneStatusCode::InternalError),
491            0x1 => Some(PublishDoneStatusCode::Unauthorized),
492            0x2 => Some(PublishDoneStatusCode::TrackEnded),
493            0x4 => Some(PublishDoneStatusCode::GoingAway),
494            0x5 => Some(PublishDoneStatusCode::TooFarBehind),
495            0x6 => Some(PublishDoneStatusCode::Expired),
496            0x8 => Some(PublishDoneStatusCode::UpdateFailed),
497            0x9 => Some(PublishDoneStatusCode::ExcessiveLoad),
498            0x12 => Some(PublishDoneStatusCode::MalformedTrack),
499            _ => None,
500        }
501    }
502
503    /// Return the raw u64 value of this status code.
504    pub fn as_u64(self) -> u64 {
505        self as u64
506    }
507}
508
509impl StreamResetErrorCode {
510    /// Every Stream Reset Error Code draft-20 assigns, in ascending wire order.
511    ///
512    /// This is the set [`Self::from_u64`] accepts, written out so that it can
513    /// be enumerated: nothing can iterate an enum's variants, so a caller that
514    /// wants the registry has to be handed it. Writing it down is also what
515    /// lets a test state its claims about the registry itself rather than about
516    /// the range some sweep happens to reach — that this is the set `from_u64`
517    /// answers to, and that none of it lands in the range the draft reserves
518    /// for greasing.
519    pub const ALL: &[StreamResetErrorCode] = &[
520        StreamResetErrorCode::InternalError,
521        StreamResetErrorCode::Cancelled,
522        StreamResetErrorCode::DeliveryTimeout,
523        StreamResetErrorCode::SessionClosed,
524        StreamResetErrorCode::GoingAway,
525        StreamResetErrorCode::TooFarBehind,
526        StreamResetErrorCode::UnknownObjectStatus,
527        StreamResetErrorCode::ExpiredAuthToken,
528        StreamResetErrorCode::ExcessiveLoad,
529        StreamResetErrorCode::MalformedTrack,
530    ];
531
532    /// Convert a raw u64 to a `StreamResetErrorCode`, if the draft assigns that code point.
533    ///
534    /// Returns `None` for any unassigned value, including the greasing range, so
535    /// that a peer sending a code this draft does not define cannot break decoding.
536    pub fn from_u64(v: u64) -> Option<Self> {
537        match v {
538            0x0 => Some(StreamResetErrorCode::InternalError),
539            0x1 => Some(StreamResetErrorCode::Cancelled),
540            0x2 => Some(StreamResetErrorCode::DeliveryTimeout),
541            0x3 => Some(StreamResetErrorCode::SessionClosed),
542            0x4 => Some(StreamResetErrorCode::GoingAway),
543            0x5 => Some(StreamResetErrorCode::TooFarBehind),
544            0x6 => Some(StreamResetErrorCode::UnknownObjectStatus),
545            0x7 => Some(StreamResetErrorCode::ExpiredAuthToken),
546            0x9 => Some(StreamResetErrorCode::ExcessiveLoad),
547            0x12 => Some(StreamResetErrorCode::MalformedTrack),
548            _ => None,
549        }
550    }
551
552    /// Return the raw u64 value of this error code.
553    pub fn as_u64(self) -> u64 {
554        self as u64
555    }
556}