Skip to main content

moqtap_codec/draft23/
error_codes.rs

1//! Error, status and stream-reset code registries defined by
2//! draft-ietf-moq-transport-23.
3//!
4//! One enum per registry in the IANA Considerations section (Section 16.12),
5//! plus the Error Detail Types registry (Section 16.11). 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. Section
9//! 13: "Receipt of an unknown error code in any error context (Session
10//! Termination, REQUEST_ERROR, PUBLISH_DONE, or Data Stream Reset) MUST be
11//! treated as equivalent to INTERNAL_ERROR for that context."
12//!
13//! Each registry reserves `0x7f * N + 0x9D` for greasing (Section 13). That is
14//! a range rather than an assignment, so it gets no variant and `from_u64`
15//! reports it as unknown like any other unassigned value.
16//!
17//! Session termination codes do not fit a `u8`: 0x200 through 0x401 are
18//! assigned.
19
20/// Session termination error codes (draft-23 Section 16.12.1, Table 20).
21///
22/// Sent as the error code when closing the Transport Session. The per-code
23/// definitions are in Section 12.2, which also groups 0x200-0x4FF: "Codes from
24/// 0x200 to 0x4FF are organized into ranges by category". See
25/// [`SessionErrorCategory`].
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27#[repr(u64)]
28pub enum SessionErrorCode {
29    /// `NO_ERROR` — The session is being terminated without an error.
30    NoError = 0x0,
31
32    /// `INTERNAL_ERROR` — An implementation specific error occurred.
33    InternalError = 0x1,
34
35    /// `UNAUTHORIZED` — The client is not authorized to establish a session.
36    Unauthorized = 0x2,
37
38    /// `PROTOCOL_VIOLATION` — The remote endpoint performed an action that was
39    /// disallowed by the specification and no more specific code applies.
40    ProtocolViolation = 0x3,
41
42    /// `INVALID_REQUEST_ID` — The endpoint received a Request ID with an
43    /// incorrect least significant bit for the sender, or a duplicate Request
44    /// ID. See Section 6.4.2.1.
45    InvalidRequestId = 0x4,
46
47    /// `DUPLICATE_TRACK_ALIAS` — The endpoint attempted to use a Track Alias
48    /// that was already in use.
49    DuplicateTrackAlias = 0x5,
50
51    /// `MALFORMED_KEY_VALUE` — A Key-Value-Pair (Figure 4), such as a Setup
52    /// Option or a Property, has a Value that does not match the definition of
53    /// its Type.
54    MalformedKeyValue = 0x6,
55
56    /// `INVALID_PATH` — The PATH parameter was used by a server, on a
57    /// WebTransport session, or the server does not support the path.
58    InvalidPath = 0x8,
59
60    /// `MALFORMED_PATH` — The PATH parameter does not conform to the rules in
61    /// Section 9.1.2.
62    MalformedPath = 0x9,
63
64    /// `GOAWAY_TIMEOUT` — The session was closed because the peer took too
65    /// long to close the session in response to a GOAWAY (Section 9.2)
66    /// message. See session migration (Section 6.6.1).
67    GoawayTimeout = 0x10,
68
69    /// `CONTROL_MESSAGE_TIMEOUT` — The session was closed because the peer
70    /// took too long to respond to a control message.
71    ControlMessageTimeout = 0x11,
72
73    /// `DATA_STREAM_TIMEOUT` — The session was closed because the peer took
74    /// too long to send data expected on an open Data Stream (see Section 11).
75    DataStreamTimeout = 0x12,
76
77    /// `AUTH_TOKEN_CACHE_OVERFLOW` — The Session limit Section 9.1.3 of the
78    /// size of all registered Authorization tokens has been exceeded.
79    AuthTokenCacheOverflow = 0x13,
80
81    /// `DUPLICATE_AUTH_TOKEN_ALIAS` — Authorization Token attempted to
82    /// register an Alias that was in use (see Section 8.9).
83    DuplicateAuthTokenAlias = 0x14,
84
85    /// `MALFORMED_AUTH_TOKEN` — Invalid Auth Token serialization (see Section
86    /// 8.9).
87    MalformedAuthToken = 0x16,
88
89    /// `UNKNOWN_AUTH_TOKEN_ALIAS` — No registered token found for the
90    /// provided Alias (see Section 8.9).
91    UnknownAuthTokenAlias = 0x17,
92
93    /// `EXPIRED_AUTH_TOKEN` — Authorization token has expired (Section 8.9).
94    ExpiredAuthToken = 0x18,
95
96    /// `INVALID_AUTHORITY` — The specified AUTHORITY does not correspond to
97    /// this server or cannot be used in this context.
98    InvalidAuthority = 0x19,
99
100    /// `MALFORMED_AUTHORITY` — The AUTHORITY value is syntactically invalid.
101    MalformedAuthority = 0x1A,
102
103    /// `TOO_MANY_REQUEST_UPDATES` — The endpoint received a REQUEST_UPDATE
104    /// that exceeded the per-stream limit communicated via the
105    /// MAX_REQUEST_UPDATES Setup Option (Section 9.1.7).
106    TooManyRequestUpdates = 0x1B,
107
108    /// `INVALID_STREAM_HEADER` — A data stream or datagram has an unknown type
109    /// or invalid Type Flags.
110    InvalidStreamHeader = 0x200,
111
112    /// `MALFORMED_OBJECT` — The serialization of an Object on a data stream or
113    /// in a datagram cannot be decoded, for example a flag references a prior
114    /// Object that does not exist.
115    MalformedObject = 0x201,
116
117    /// `INVALID_OBJECT_STATUS` — An Object has an invalid Object Status, or
118    /// has Properties when its status is not Normal.
119    InvalidObjectStatus = 0x202,
120
121    /// `TRUNCATED_OBJECT` — A data stream ended with a FIN in the middle of an
122    /// Object.
123    TruncatedObject = 0x203,
124
125    /// `MALFORMED_MESSAGE` — A control message cannot be parsed or is missing
126    /// a required element, for example its length does not match its
127    /// contents.
128    MalformedMessage = 0x300,
129
130    /// `INVALID_FIELD` — A control message was parsed, but a field has a value
131    /// that is not allowed.
132    InvalidField = 0x301,
133
134    /// `INVALID_TRACK_NAMESPACE` — A Track Namespace does not conform to
135    /// Section 8.7.
136    InvalidTrackNamespace = 0x302,
137
138    /// `UNEXPECTED_MESSAGE` — A control message of an unknown type was
139    /// received, or a message was received on the wrong stream, in the wrong
140    /// order, or more times than allowed.
141    UnexpectedMessage = 0x303,
142
143    /// `ROLE_VIOLATION` — The peer sent a message or field that is not allowed
144    /// for its role, for example a server receiving a non-empty New Session
145    /// URI.
146    RoleViolation = 0x304,
147
148    /// `INVALID_PARAMETER` — A Message Parameter (Section 9.19) is unknown,
149    /// duplicated, not allowed in the message, or has a value outside its
150    /// allowed range.
151    InvalidParameter = 0x305,
152
153    /// `CLOSED_CONTROL_STREAM` — The peer closed the control stream (Section
154    /// 6.3).
155    ClosedControlStream = 0x306,
156
157    /// `DELTA_ENCODING_OVERFLOW` — A value decoded from a delta encoding is
158    /// less than 0 or greater than 2^64 - 1.
159    DeltaEncodingOverflow = 0x400,
160
161    /// `FIELD_LENGTH_EXCEEDED` — A field or structure is longer than its
162    /// maximum allowed length.
163    FieldLengthExceeded = 0x401,
164}
165
166/// The category Section 12.2 gives a session termination code in 0x200-0x4FF.
167///
168/// "0x200-0x2FF: Data stream and datagram errors", "0x300-0x3FF: Control
169/// stream and control message errors", "0x400-0x4FF: Errors that can occur in
170/// either". "The values reserved for greasing (Section 13) that fall within
171/// these ranges are not assigned to a category."
172#[derive(Debug, Clone, Copy, PartialEq, Eq)]
173pub enum SessionErrorCategory {
174    /// 0x200-0x2FF.
175    DataStream,
176    /// 0x300-0x3FF.
177    ControlStream,
178    /// 0x400-0x4FF.
179    Either,
180}
181
182impl SessionErrorCategory {
183    /// The category of `code`, assigned or not, or `None` outside 0x200-0x4FF
184    /// and for a grease value.
185    pub fn of(code: u64) -> Option<Self> {
186        if code >= 0x9D && (code - 0x9D).is_multiple_of(0x7F) {
187            return None;
188        }
189        match code {
190            0x200..=0x2FF => Some(Self::DataStream),
191            0x300..=0x3FF => Some(Self::ControlStream),
192            0x400..=0x4FF => Some(Self::Either),
193            _ => None,
194        }
195    }
196}
197
198/// REQUEST_ERROR codes (draft-23 Section 16.12.2, Table 21).
199///
200/// The per-code definitions are in Section 12.3.
201#[derive(Debug, Clone, Copy, PartialEq, Eq)]
202#[repr(u64)]
203pub enum RequestErrorCode {
204    /// `INTERNAL_ERROR` — An implementation specific or generic error
205    /// occurred.
206    InternalError = 0x0,
207
208    /// `UNAUTHORIZED` — The subscriber is not authorized to perform the
209    /// requested action on the given track.
210    Unauthorized = 0x1,
211
212    /// `TIMEOUT` — The subscription could not be completed before an
213    /// implementation specific timeout.
214    Timeout = 0x2,
215
216    /// `NOT_SUPPORTED` — The endpoint does not support the type of request.
217    NotSupported = 0x3,
218
219    /// `MALFORMED_AUTH_TOKEN` — Invalid Auth Token serialization during
220    /// registration (see Section 8.9).
221    MalformedAuthToken = 0x4,
222
223    /// `EXPIRED_AUTH_TOKEN` — Authorization token has expired (Section 8.9).
224    ExpiredAuthToken = 0x5,
225
226    /// `GOING_AWAY` — The endpoint has received a GOAWAY and MAY reject new
227    /// requests.
228    GoingAway = 0x6,
229
230    /// `EXCESSIVE_LOAD` — The responder is overloaded and cannot process the
231    /// request at this time.
232    ExcessiveLoad = 0x9,
233
234    /// `UNAVAILABLE` — The responder cannot fulfill this request at this
235    /// time, but might be able to later; for example, a relay lacks stream
236    /// credit to forward it upstream (see Section 7.4).
237    Unavailable = 0xA,
238
239    /// `DOES_NOT_EXIST` — The track or namespace is not available at the
240    /// publisher.
241    DoesNotExist = 0x10,
242
243    /// `INVALID_RANGE` — In response to SUBSCRIBE or FETCH, specified Filter
244    /// or range of Locations cannot be satisfied.
245    InvalidRange = 0x11,
246
247    /// `MALFORMED_TRACK` — In response to a FETCH, a relay publisher detected
248    /// the track was malformed (see Section 12.1).
249    MalformedTrack = 0x12,
250
251    /// `UNINTERESTED` — The subscriber is not interested in the track or
252    /// namespace.
253    Uninterested = 0x20,
254
255    /// `NAMESPACE_TOO_LARGE` — In response to SUBSCRIBE_NAMESPACE or
256    /// SUBSCRIBE_TRACKS, the namespace prefix matches more publishers than the
257    /// relay is willing to enumerate.
258    NamespaceTooLarge = 0x31,
259
260    /// `UNSUPPORTED_EXTENSION` — The track contains a Mandatory Track Property
261    /// (see Section 3.7) that the endpoint does not understand. The
262    /// UNSUPPORTED_PROPERTY Error Detail (Section 9.4.2.2) identifies which
263    /// property.
264    UnsupportedExtension = 0x33,
265
266    /// `REDIRECT` — The request cannot be fulfilled by this endpoint, but
267    /// could succeed at the location specified in the REDIRECT Error Detail
268    /// (Section 9.4.2.1).
269    Redirect = 0x34,
270
271    /// `CONFLICTING_FILTERS` — In response to SUBSCRIBE_TRACKS, the filter
272    /// parameters conflict among too many subscribers to aggregate the
273    /// subscription upstream or otherwise efficiently service it.
274    ConflictingFilters = 0x35,
275
276    /// `INVALID_FILTER` — A filter parameter is invalid.
277    InvalidFilter = 0x36,
278}
279
280/// PUBLISH_DONE codes (draft-23 Section 16.12.3, Table 22).
281///
282/// The per-code definitions are in Section 12.4. 0x3 is unassigned.
283#[derive(Debug, Clone, Copy, PartialEq, Eq)]
284#[repr(u64)]
285pub enum PublishDoneStatusCode {
286    /// `INTERNAL_ERROR` — An implementation specific or generic error
287    /// occurred.
288    InternalError = 0x0,
289
290    /// `UNAUTHORIZED` — The subscriber is no longer authorized to subscribe to
291    /// the given track.
292    Unauthorized = 0x1,
293
294    /// `TRACK_ENDED` — The track is no longer being published.
295    TrackEnded = 0x2,
296
297    /// `GOING_AWAY` — The subscriber or publisher issued a GOAWAY message.
298    GoingAway = 0x4,
299
300    /// `TOO_FAR_BEHIND` — The publisher's queue of objects to be sent to the
301    /// given subscriber exceeds its implementation defined limit.
302    TooFarBehind = 0x5,
303
304    /// `EXPIRED` — The publisher reached the timeout specified in
305    /// SUBSCRIBE_OK.
306    Expired = 0x6,
307
308    /// `EXPIRED_AUTH_TOKEN` — The authorization token that authorized the
309    /// subscription has expired (see Section 9.9).
310    ExpiredAuthToken = 0x7,
311
312    /// `UPDATE_FAILED` — REQUEST_UPDATE failed on this subscription (see
313    /// Section 9.5).
314    UpdateFailed = 0x8,
315
316    /// `EXCESSIVE_LOAD` — The publisher is overloaded and is terminating the
317    /// subscription.
318    ExcessiveLoad = 0x9,
319
320    /// `MALFORMED_TRACK` — A relay publisher detected that the track was
321    /// malformed (see Section 12.1).
322    MalformedTrack = 0x12,
323}
324
325/// Stream reset error codes (draft-23 Section 16.12.4, Table 23).
326///
327/// Section 12.5: "The application SHOULD use a relevant error code when
328/// resetting or sending STOP_SENDING on any stream." 0x6 is unassigned.
329#[derive(Debug, Clone, Copy, PartialEq, Eq)]
330#[repr(u64)]
331pub enum StreamResetErrorCode {
332    /// `INTERNAL_ERROR` — An implementation specific error.
333    InternalError = 0x0,
334
335    /// `CANCELLED` — The stream was cancelled by either endpoint. For
336    /// Subscriptions, PUBLISH_DONE (Section 9.9) may have a more detailed
337    /// status code.
338    Cancelled = 0x1,
339
340    /// `DELIVERY_TIMEOUT` — A delivery timeout (Section 5.2) was exceeded for
341    /// this stream.
342    DeliveryTimeout = 0x2,
343
344    /// `SESSION_CLOSED` — The session is being closed.
345    SessionClosed = 0x3,
346
347    /// `GOING_AWAY` — The endpoint is rejecting this request because it has
348    /// sent or received a GOAWAY.
349    GoingAway = 0x4,
350
351    /// `TOO_FAR_BEHIND` — The corresponding subscription has exceeded the
352    /// publisher's resource limits and is being terminated (see Section 5.2).
353    TooFarBehind = 0x5,
354
355    /// `EXPIRED_AUTH_TOKEN` — The authorization token for the request has
356    /// expired.
357    ExpiredAuthToken = 0x7,
358
359    /// `EXCESSIVE_LOAD` — The endpoint is overloaded and is resetting this
360    /// stream.
361    ExcessiveLoad = 0x9,
362
363    /// `MALFORMED_TRACK` — A relay publisher detected that the track was
364    /// malformed (see Section 12.1).
365    MalformedTrack = 0x12,
366}
367
368/// Error Detail types (draft-23 Section 16.11, Table 19).
369///
370/// Section 9.4.2: "Receivers MUST ignore unknown Error Detail types, and MUST
371/// ignore a known Error Detail type that accompanies an Error Code it is not
372/// defined for."
373#[derive(Debug, Clone, Copy, PartialEq, Eq)]
374#[repr(u64)]
375pub enum ErrorDetailType {
376    /// `REDIRECT` — directs the requester to retry a request at a different
377    /// URI and/or for a different Full Track Name (Section 9.4.2.1).
378    Redirect = 0x01,
379
380    /// `UNSUPPORTED_PROPERTY` — the Property Type of a Mandatory Track
381    /// Property that the sender does not understand (Section 9.4.2.2).
382    UnsupportedProperty = 0x02,
383}
384
385impl SessionErrorCode {
386    /// Every Session Error Code draft-23 assigns, in ascending wire order:
387    /// the set [`Self::from_u64`] accepts.
388    pub const ALL: &[SessionErrorCode] = &[
389        SessionErrorCode::NoError,
390        SessionErrorCode::InternalError,
391        SessionErrorCode::Unauthorized,
392        SessionErrorCode::ProtocolViolation,
393        SessionErrorCode::InvalidRequestId,
394        SessionErrorCode::DuplicateTrackAlias,
395        SessionErrorCode::MalformedKeyValue,
396        SessionErrorCode::InvalidPath,
397        SessionErrorCode::MalformedPath,
398        SessionErrorCode::GoawayTimeout,
399        SessionErrorCode::ControlMessageTimeout,
400        SessionErrorCode::DataStreamTimeout,
401        SessionErrorCode::AuthTokenCacheOverflow,
402        SessionErrorCode::DuplicateAuthTokenAlias,
403        SessionErrorCode::MalformedAuthToken,
404        SessionErrorCode::UnknownAuthTokenAlias,
405        SessionErrorCode::ExpiredAuthToken,
406        SessionErrorCode::InvalidAuthority,
407        SessionErrorCode::MalformedAuthority,
408        SessionErrorCode::TooManyRequestUpdates,
409        SessionErrorCode::InvalidStreamHeader,
410        SessionErrorCode::MalformedObject,
411        SessionErrorCode::InvalidObjectStatus,
412        SessionErrorCode::TruncatedObject,
413        SessionErrorCode::MalformedMessage,
414        SessionErrorCode::InvalidField,
415        SessionErrorCode::InvalidTrackNamespace,
416        SessionErrorCode::UnexpectedMessage,
417        SessionErrorCode::RoleViolation,
418        SessionErrorCode::InvalidParameter,
419        SessionErrorCode::ClosedControlStream,
420        SessionErrorCode::DeltaEncodingOverflow,
421        SessionErrorCode::FieldLengthExceeded,
422    ];
423
424    /// Convert a raw u64 to a `SessionErrorCode`, if the draft assigns that
425    /// code point. `None` for any unassigned value, including the greasing
426    /// range.
427    pub fn from_u64(v: u64) -> Option<Self> {
428        match v {
429            0x0 => Some(SessionErrorCode::NoError),
430            0x1 => Some(SessionErrorCode::InternalError),
431            0x2 => Some(SessionErrorCode::Unauthorized),
432            0x3 => Some(SessionErrorCode::ProtocolViolation),
433            0x4 => Some(SessionErrorCode::InvalidRequestId),
434            0x5 => Some(SessionErrorCode::DuplicateTrackAlias),
435            0x6 => Some(SessionErrorCode::MalformedKeyValue),
436            0x8 => Some(SessionErrorCode::InvalidPath),
437            0x9 => Some(SessionErrorCode::MalformedPath),
438            0x10 => Some(SessionErrorCode::GoawayTimeout),
439            0x11 => Some(SessionErrorCode::ControlMessageTimeout),
440            0x12 => Some(SessionErrorCode::DataStreamTimeout),
441            0x13 => Some(SessionErrorCode::AuthTokenCacheOverflow),
442            0x14 => Some(SessionErrorCode::DuplicateAuthTokenAlias),
443            0x16 => Some(SessionErrorCode::MalformedAuthToken),
444            0x17 => Some(SessionErrorCode::UnknownAuthTokenAlias),
445            0x18 => Some(SessionErrorCode::ExpiredAuthToken),
446            0x19 => Some(SessionErrorCode::InvalidAuthority),
447            0x1A => Some(SessionErrorCode::MalformedAuthority),
448            0x1B => Some(SessionErrorCode::TooManyRequestUpdates),
449            0x200 => Some(SessionErrorCode::InvalidStreamHeader),
450            0x201 => Some(SessionErrorCode::MalformedObject),
451            0x202 => Some(SessionErrorCode::InvalidObjectStatus),
452            0x203 => Some(SessionErrorCode::TruncatedObject),
453            0x300 => Some(SessionErrorCode::MalformedMessage),
454            0x301 => Some(SessionErrorCode::InvalidField),
455            0x302 => Some(SessionErrorCode::InvalidTrackNamespace),
456            0x303 => Some(SessionErrorCode::UnexpectedMessage),
457            0x304 => Some(SessionErrorCode::RoleViolation),
458            0x305 => Some(SessionErrorCode::InvalidParameter),
459            0x306 => Some(SessionErrorCode::ClosedControlStream),
460            0x400 => Some(SessionErrorCode::DeltaEncodingOverflow),
461            0x401 => Some(SessionErrorCode::FieldLengthExceeded),
462            _ => None,
463        }
464    }
465
466    /// Return the raw u64 value of this error code.
467    pub fn as_u64(self) -> u64 {
468        self as u64
469    }
470
471    /// The Section 12.2 category of this code, `None` below 0x200.
472    pub fn category(self) -> Option<SessionErrorCategory> {
473        SessionErrorCategory::of(self.as_u64())
474    }
475}
476
477impl RequestErrorCode {
478    /// Every Request Error Code draft-23 assigns, in ascending wire order:
479    /// the set [`Self::from_u64`] accepts.
480    pub const ALL: &[RequestErrorCode] = &[
481        RequestErrorCode::InternalError,
482        RequestErrorCode::Unauthorized,
483        RequestErrorCode::Timeout,
484        RequestErrorCode::NotSupported,
485        RequestErrorCode::MalformedAuthToken,
486        RequestErrorCode::ExpiredAuthToken,
487        RequestErrorCode::GoingAway,
488        RequestErrorCode::ExcessiveLoad,
489        RequestErrorCode::Unavailable,
490        RequestErrorCode::DoesNotExist,
491        RequestErrorCode::InvalidRange,
492        RequestErrorCode::MalformedTrack,
493        RequestErrorCode::Uninterested,
494        RequestErrorCode::NamespaceTooLarge,
495        RequestErrorCode::UnsupportedExtension,
496        RequestErrorCode::Redirect,
497        RequestErrorCode::ConflictingFilters,
498        RequestErrorCode::InvalidFilter,
499    ];
500
501    /// Convert a raw u64 to a `RequestErrorCode`, if the draft assigns that
502    /// code point. `None` for any unassigned value, including the greasing
503    /// range.
504    pub fn from_u64(v: u64) -> Option<Self> {
505        match v {
506            0x0 => Some(RequestErrorCode::InternalError),
507            0x1 => Some(RequestErrorCode::Unauthorized),
508            0x2 => Some(RequestErrorCode::Timeout),
509            0x3 => Some(RequestErrorCode::NotSupported),
510            0x4 => Some(RequestErrorCode::MalformedAuthToken),
511            0x5 => Some(RequestErrorCode::ExpiredAuthToken),
512            0x6 => Some(RequestErrorCode::GoingAway),
513            0x9 => Some(RequestErrorCode::ExcessiveLoad),
514            0xA => Some(RequestErrorCode::Unavailable),
515            0x10 => Some(RequestErrorCode::DoesNotExist),
516            0x11 => Some(RequestErrorCode::InvalidRange),
517            0x12 => Some(RequestErrorCode::MalformedTrack),
518            0x20 => Some(RequestErrorCode::Uninterested),
519            0x31 => Some(RequestErrorCode::NamespaceTooLarge),
520            0x33 => Some(RequestErrorCode::UnsupportedExtension),
521            0x34 => Some(RequestErrorCode::Redirect),
522            0x35 => Some(RequestErrorCode::ConflictingFilters),
523            0x36 => Some(RequestErrorCode::InvalidFilter),
524            _ => None,
525        }
526    }
527
528    /// Return the raw u64 value of this error code.
529    pub fn as_u64(self) -> u64 {
530        self as u64
531    }
532}
533
534impl PublishDoneStatusCode {
535    /// Every PUBLISH_DONE Status Code draft-23 assigns, in ascending wire
536    /// order: the set [`Self::from_u64`] accepts.
537    pub const ALL: &[PublishDoneStatusCode] = &[
538        PublishDoneStatusCode::InternalError,
539        PublishDoneStatusCode::Unauthorized,
540        PublishDoneStatusCode::TrackEnded,
541        PublishDoneStatusCode::GoingAway,
542        PublishDoneStatusCode::TooFarBehind,
543        PublishDoneStatusCode::Expired,
544        PublishDoneStatusCode::ExpiredAuthToken,
545        PublishDoneStatusCode::UpdateFailed,
546        PublishDoneStatusCode::ExcessiveLoad,
547        PublishDoneStatusCode::MalformedTrack,
548    ];
549
550    /// Convert a raw u64 to a `PublishDoneStatusCode`, if the draft assigns
551    /// that code point. `None` for any unassigned value, including the
552    /// greasing range.
553    pub fn from_u64(v: u64) -> Option<Self> {
554        match v {
555            0x0 => Some(PublishDoneStatusCode::InternalError),
556            0x1 => Some(PublishDoneStatusCode::Unauthorized),
557            0x2 => Some(PublishDoneStatusCode::TrackEnded),
558            0x4 => Some(PublishDoneStatusCode::GoingAway),
559            0x5 => Some(PublishDoneStatusCode::TooFarBehind),
560            0x6 => Some(PublishDoneStatusCode::Expired),
561            0x7 => Some(PublishDoneStatusCode::ExpiredAuthToken),
562            0x8 => Some(PublishDoneStatusCode::UpdateFailed),
563            0x9 => Some(PublishDoneStatusCode::ExcessiveLoad),
564            0x12 => Some(PublishDoneStatusCode::MalformedTrack),
565            _ => None,
566        }
567    }
568
569    /// Return the raw u64 value of this status code.
570    pub fn as_u64(self) -> u64 {
571        self as u64
572    }
573}
574
575impl StreamResetErrorCode {
576    /// Every Stream Reset Error Code draft-23 assigns, in ascending wire
577    /// order: the set [`Self::from_u64`] accepts.
578    pub const ALL: &[StreamResetErrorCode] = &[
579        StreamResetErrorCode::InternalError,
580        StreamResetErrorCode::Cancelled,
581        StreamResetErrorCode::DeliveryTimeout,
582        StreamResetErrorCode::SessionClosed,
583        StreamResetErrorCode::GoingAway,
584        StreamResetErrorCode::TooFarBehind,
585        StreamResetErrorCode::ExpiredAuthToken,
586        StreamResetErrorCode::ExcessiveLoad,
587        StreamResetErrorCode::MalformedTrack,
588    ];
589
590    /// Convert a raw u64 to a `StreamResetErrorCode`, if the draft assigns
591    /// that code point. `None` for any unassigned value, including the
592    /// greasing range.
593    pub fn from_u64(v: u64) -> Option<Self> {
594        match v {
595            0x0 => Some(StreamResetErrorCode::InternalError),
596            0x1 => Some(StreamResetErrorCode::Cancelled),
597            0x2 => Some(StreamResetErrorCode::DeliveryTimeout),
598            0x3 => Some(StreamResetErrorCode::SessionClosed),
599            0x4 => Some(StreamResetErrorCode::GoingAway),
600            0x5 => Some(StreamResetErrorCode::TooFarBehind),
601            0x7 => Some(StreamResetErrorCode::ExpiredAuthToken),
602            0x9 => Some(StreamResetErrorCode::ExcessiveLoad),
603            0x12 => Some(StreamResetErrorCode::MalformedTrack),
604            _ => None,
605        }
606    }
607
608    /// Return the raw u64 value of this error code.
609    pub fn as_u64(self) -> u64 {
610        self as u64
611    }
612}
613
614impl ErrorDetailType {
615    /// Every Error Detail type draft-23 assigns, in ascending wire order.
616    pub const ALL: &[ErrorDetailType] =
617        &[ErrorDetailType::Redirect, ErrorDetailType::UnsupportedProperty];
618
619    /// Convert a raw u64 to an `ErrorDetailType`, if the draft assigns it.
620    pub fn from_u64(v: u64) -> Option<Self> {
621        match v {
622            0x01 => Some(ErrorDetailType::Redirect),
623            0x02 => Some(ErrorDetailType::UnsupportedProperty),
624            _ => None,
625        }
626    }
627
628    /// Return the raw u64 value of this type.
629    pub fn as_u64(self) -> u64 {
630        self as u64
631    }
632}