Skip to main content

moqtap_codec/draft19/
error_codes.rs

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