Skip to main content

moqtap_codec/draft17/
error_codes.rs

1//! Error and status code registries defined by draft-17.
2//!
3//! One enum per IANA registry in Section 14.5 of the draft. Variant names are
4//! the draft's own ALLCAPS names rewritten in Rust convention; each variant's
5//! doc comment repeats the draft spelling so the mapping stays checkable.
6//!
7//! Codes are per-registry, not global, and the overlap is not benign: every
8//! value from `0x0` to `0x5` is assigned in all four registries, with a
9//! different meaning in nearly every cell.
10//!
11//! | code | session termination | REQUEST_ERROR | PUBLISH_DONE | data stream reset |
12//! |------|---------------------|---------------|--------------|-------------------|
13//! | 0x0  | `NO_ERROR` | `INTERNAL_ERROR` | `INTERNAL_ERROR` | `INTERNAL_ERROR` |
14//! | 0x1  | `INTERNAL_ERROR` | `UNAUTHORIZED` | `UNAUTHORIZED` | `CANCELLED` |
15//! | 0x2  | `UNAUTHORIZED` | `TIMEOUT` | `TRACK_ENDED` | `DELIVERY_TIMEOUT` |
16//! | 0x3  | `PROTOCOL_VIOLATION` | `NOT_SUPPORTED` | `SUBSCRIPTION_ENDED` | `SESSION_CLOSED` |
17//! | 0x4  | `INVALID_REQUEST_ID` | `MALFORMED_AUTH_TOKEN` | `GOING_AWAY` | `UNKNOWN_OBJECT_STATUS` |
18//! | 0x5  | `DUPLICATE_TRACK_ALIAS` | `EXPIRED_AUTH_TOKEN` | `EXPIRED` | `TOO_FAR_BEHIND` |
19//! | 0x9  | `MALFORMED_PATH` | `EXCESSIVE_LOAD` | `EXCESSIVE_LOAD` | `EXCESSIVE_LOAD` |
20//! | 0x12 | `DATA_STREAM_TIMEOUT` | `MALFORMED_TRACK` | `MALFORMED_TRACK` | `MALFORMED_TRACK` |
21//! | 0x19 | `INVALID_AUTHORITY` | `DUPLICATE_SUBSCRIPTION` | unassigned | unassigned |
22//!
23//! Carrying a value from one of these types to another is therefore always a
24//! bug, even where the two happen to share a variant name. These type names
25//! also recur in the sibling draft modules over different assignments, so an
26//! import repointed at another draft still compiles while changing meaning.
27//!
28//! Every table's last row reserves `0x7f * N + 0x9D` for greasing (Section 13).
29//! Those code points carry no semantics, get no variants here, and are rejected
30//! by `from_u64` like any other unassigned value. Note that Section 13 of this
31//! draft gives the formula as `0x7f * N + 0x9D` but illustrates it with the
32//! sequence `0x9D, 0xBC, ...`, whose step is `0x1f` rather than `0x7f`; drafts
33//! 18 and 19 keep the same formula and correct the illustration to
34//! `0x9D, 0x11C, ...`. The formula is treated as normative. Either reading
35//! leaves this module unchanged, since no greasing value gets a variant.
36
37/// Session Termination Error Codes (draft-17, Section 14.5.1).
38///
39/// The registry table is in Section 14.5.1; the per-code descriptions carried on
40/// the variants below are the ones given in Section 3.5 of the draft.
41///
42/// The table's last row reserves `0x7f * N + 0x9D` for greasing (Section 13).
43/// Greasing code points are not a contiguous range and carry no semantics a
44/// decoder can act on, so they get no variants and `from_u64` rejects them like
45/// any other unassigned value.
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47#[repr(u64)]
48pub enum SessionErrorCode {
49    /// `NO_ERROR` — The session is being terminated without an error.
50    NoError = 0x0,
51    /// `INTERNAL_ERROR` — An implementation specific error occurred.
52    InternalError = 0x1,
53    /// `UNAUTHORIZED` — The client is not authorized to establish a session.
54    Unauthorized = 0x2,
55    /// `PROTOCOL_VIOLATION` — The remote endpoint performed an action that was disallowed by the specification.
56    ProtocolViolation = 0x3,
57    /// `INVALID_REQUEST_ID` — The endpoint received a Request ID with an incorrect least significant bit for the sender, or a duplicate Request ID. See Section 9.1.
58    InvalidRequestId = 0x4,
59    /// `DUPLICATE_TRACK_ALIAS` — The endpoint attempted to use a Track Alias that was already in use.
60    DuplicateTrackAlias = 0x5,
61    /// `KEY_VALUE_FORMATTING_ERROR` — The key-value pair has a formatting error.
62    KeyValueFormattingError = 0x6,
63    /// `INVALID_REQUIRED_REQUEST_ID` — The endpoint received a Required Request ID Delta that results in an invalid Request ID. See Section 9.2.
64    InvalidRequiredRequestId = 0x7,
65    /// `INVALID_PATH` — The PATH parameter was used by a server, on a WebTransport session, or the server does not support the path.
66    InvalidPath = 0x8,
67    /// `MALFORMED_PATH` — The PATH parameter does not conform to the rules in Section 9.4.1.2.
68    MalformedPath = 0x9,
69    /// `GOAWAY_TIMEOUT` — The session was closed because the peer took too long to close the session in response to a GOAWAY (Section 9.5) message. See session migration (Section 3.6).
70    GoawayTimeout = 0x10,
71    /// `CONTROL_MESSAGE_TIMEOUT` — The session was closed because the peer took too long to respond to a control message.
72    ControlMessageTimeout = 0x11,
73    /// `DATA_STREAM_TIMEOUT` — The session was closed because the peer took too long to send data expected on an open Data Stream (see Section 10). This includes fields of a stream header or an object header within a data stream. If an endpoint times out waiting for a new object header on an open subgroup stream, it MAY send a STOP_SENDING on that stream or terminate the subscription.
74    DataStreamTimeout = 0x12,
75    /// `AUTH_TOKEN_CACHE_OVERFLOW` — The Session limit Section 9.4.1.3 of the size of all registered Authorization tokens has been exceeded.
76    AuthTokenCacheOverflow = 0x13,
77    /// `DUPLICATE_AUTH_TOKEN_ALIAS` — Authorization Token attempted to register an Alias that was in use (see Section 9.3.2).
78    DuplicateAuthTokenAlias = 0x14,
79    /// `VERSION_NEGOTIATION_FAILED` — The client didn't offer a version supported by the server.
80    VersionNegotiationFailed = 0x15,
81    /// `MALFORMED_AUTH_TOKEN` — Invalid Auth Token serialization during registration (see Section 9.3.2).
82    MalformedAuthToken = 0x16,
83    /// `UNKNOWN_AUTH_TOKEN_ALIAS` — No registered token found for the provided Alias (see Section 9.3.2).
84    UnknownAuthTokenAlias = 0x17,
85    /// `EXPIRED_AUTH_TOKEN` — Authorization token has expired (Section 9.3.2).
86    ExpiredAuthToken = 0x18,
87    /// `INVALID_AUTHORITY` — The specified AUTHORITY does not correspond to this server or cannot be used in this context.
88    InvalidAuthority = 0x19,
89    /// `MALFORMED_AUTHORITY` — The AUTHORITY value is syntactically invalid.
90    MalformedAuthority = 0x1A,
91}
92
93/// REQUEST_ERROR Codes (draft-17, Section 14.5.2).
94///
95/// The registry table is in Section 14.5.2; the per-code descriptions carried on
96/// the variants below are the ones given in Section 9.7 of the draft.
97///
98/// The table's last row reserves `0x7f * N + 0x9D` for greasing (Section 13).
99/// Greasing code points are not a contiguous range and carry no semantics a
100/// decoder can act on, so they get no variants and `from_u64` rejects them like
101/// any other unassigned value.
102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103#[repr(u64)]
104pub enum RequestErrorCode {
105    /// `INTERNAL_ERROR` — An implementation specific or generic error occurred.
106    InternalError = 0x0,
107    /// `UNAUTHORIZED` — The subscriber is not authorized to perform the requested action on the given track. This might be retryable if the authorization token is not yet valid.
108    Unauthorized = 0x1,
109    /// `TIMEOUT` — The subscription could not be completed before an implementation specific timeout. For example, a relay could not establish an upstream subscription within the timeout.
110    Timeout = 0x2,
111    /// `NOT_SUPPORTED` — The endpoint does not support the type of request.
112    NotSupported = 0x3,
113    /// `MALFORMED_AUTH_TOKEN` — Invalid Auth Token serialization during registration (see Section 9.3.2).
114    MalformedAuthToken = 0x4,
115    /// `EXPIRED_AUTH_TOKEN` — Authorization token has expired (Section 9.3.2).
116    ExpiredAuthToken = 0x5,
117    /// `GOING_AWAY` — The endpoint has received a GOAWAY and MAY reject new requests.
118    GoingAway = 0x6,
119    /// `EXCESSIVE_LOAD` — The responder is overloaded and cannot process the request at this time. The sender SHOULD use the Retry Interval to indicate when the request can be retried.
120    ExcessiveLoad = 0x9,
121    /// `DOES_NOT_EXIST` — The track or namespace is not available at the publisher.
122    DoesNotExist = 0x10,
123    /// `INVALID_RANGE` — In response to SUBSCRIBE or FETCH, specified Filter or range of Locations cannot be satisfied.
124    InvalidRange = 0x11,
125    /// `MALFORMED_TRACK` — In response to a FETCH, a relay publisher detected the track was malformed (see Section 2.4.2).
126    MalformedTrack = 0x12,
127    /// `DUPLICATE_SUBSCRIPTION` — The PUBLISH or SUBSCRIBE request attempted to create a subscription to a Track with the same role as an existing subscription.
128    DuplicateSubscription = 0x19,
129    /// `UNINTERESTED` — The subscriber is not interested in the track or namespace.
130    Uninterested = 0x20,
131    /// `PREFIX_OVERLAP` — In response to SUBSCRIBE_NAMESPACE, the namespace prefix overlaps with another SUBSCRIBE_NAMESPACE in the same session.
132    PrefixOverlap = 0x30,
133    /// `NAMESPACE_TOO_LARGE` — In response to SUBSCRIBE_NAMESPACE, the namespace prefix matches more publishers than the relay is willing to enumerate.
134    NamespaceTooLarge = 0x31,
135    /// `INVALID_JOINING_REQUEST_ID` — In response to a Joining FETCH, the referenced Request ID is not an Established Subscription.
136    InvalidJoiningRequestId = 0x32,
137}
138
139/// PUBLISH_DONE Codes (draft-17, Section 14.5.3).
140///
141/// The registry table is in Section 14.5.3; the per-code descriptions carried on
142/// the variants below are the ones given in Section 9.13 of the draft.
143///
144/// The table's last row reserves `0x7f * N + 0x9D` for greasing (Section 13).
145/// Greasing code points are not a contiguous range and carry no semantics a
146/// decoder can act on, so they get no variants and `from_u64` rejects them like
147/// any other unassigned value.
148#[derive(Debug, Clone, Copy, PartialEq, Eq)]
149#[repr(u64)]
150pub enum PublishDoneStatusCode {
151    /// `INTERNAL_ERROR` — An implementation specific or generic error occurred.
152    InternalError = 0x0,
153    /// `UNAUTHORIZED` — The subscriber is no longer authorized to subscribe to the given track.
154    Unauthorized = 0x1,
155    /// `TRACK_ENDED` — The track is no longer being published.
156    TrackEnded = 0x2,
157    /// `SUBSCRIPTION_ENDED` — The publisher reached the end of an associated subscription filter.
158    SubscriptionEnded = 0x3,
159    /// `GOING_AWAY` — The subscriber or publisher issued a GOAWAY message.
160    GoingAway = 0x4,
161    /// `EXPIRED` — The publisher reached the timeout specified in SUBSCRIBE_OK.
162    Expired = 0x5,
163    /// `TOO_FAR_BEHIND` — The publisher's queue of objects to be sent to the given subscriber exceeds its implementation defined limit.
164    TooFarBehind = 0x6,
165    /// `UPDATE_FAILED` — REQUEST_UPDATE failed on this subscription (see Section 9.10).
166    UpdateFailed = 0x8,
167    /// `EXCESSIVE_LOAD` — The publisher is overloaded and is terminating the subscription.
168    ExcessiveLoad = 0x9,
169    /// `MALFORMED_TRACK` — A relay publisher detected that the track was malformed (see Section 2.4.2).
170    MalformedTrack = 0x12,
171}
172
173/// Data Stream Reset Error Codes (draft-17, Section 14.5.4).
174///
175/// The registry table is in Section 14.5.4; the per-code descriptions carried on
176/// the variants below are the ones given in Section 10.4.3 of the draft.
177///
178/// The table's last row reserves `0x7f * N + 0x9D` for greasing (Section 13).
179/// Greasing code points are not a contiguous range and carry no semantics a
180/// decoder can act on, so they get no variants and `from_u64` rejects them like
181/// any other unassigned value.
182#[derive(Debug, Clone, Copy, PartialEq, Eq)]
183#[repr(u64)]
184pub enum DataStreamResetErrorCode {
185    /// `INTERNAL_ERROR` — An implementation specific error.
186    InternalError = 0x0,
187    /// `CANCELLED` — The subscriber or publisher cancelled the Request. For Subscriptions, PUBLISH_DONE (Section 9.13) will have a more detailed status code.
188    Cancelled = 0x1,
189    /// `DELIVERY_TIMEOUT` — The DELIVERY TIMEOUT Section 9.3.3 was exceeded for this stream.
190    DeliveryTimeout = 0x2,
191    /// `SESSION_CLOSED` — The publisher session is being closed.
192    SessionClosed = 0x3,
193    /// `UNKNOWN_OBJECT_STATUS` — In response to a FETCH, the publisher is unable to determine the Status of the next Object in the requested range.
194    UnknownObjectStatus = 0x4,
195    /// `TOO_FAR_BEHIND` — The corresponding subscription has exceeded the publisher's resource limits and is being terminated (see Section 9.3.3).
196    TooFarBehind = 0x5,
197    /// `EXCESSIVE_LOAD` — The publisher is overloaded and is resetting this stream.
198    ExcessiveLoad = 0x9,
199    /// `MALFORMED_TRACK` — A relay publisher detected that the track was malformed (see Section 2.4.2).
200    MalformedTrack = 0x12,
201}
202
203impl SessionErrorCode {
204    /// Every Session Error Code draft-17 assigns, in ascending wire order.
205    ///
206    /// This is the set [`Self::from_u64`] accepts, written out so that it can
207    /// be enumerated: nothing can iterate an enum's variants, so a caller that
208    /// wants the registry has to be handed it. Writing it down is also what
209    /// lets a test state its claims about the registry itself rather than about
210    /// the range some sweep happens to reach — that this is the set `from_u64`
211    /// answers to, and that none of it lands in the range the draft reserves
212    /// for greasing.
213    pub const ALL: &[SessionErrorCode] = &[
214        SessionErrorCode::NoError,
215        SessionErrorCode::InternalError,
216        SessionErrorCode::Unauthorized,
217        SessionErrorCode::ProtocolViolation,
218        SessionErrorCode::InvalidRequestId,
219        SessionErrorCode::DuplicateTrackAlias,
220        SessionErrorCode::KeyValueFormattingError,
221        SessionErrorCode::InvalidRequiredRequestId,
222        SessionErrorCode::InvalidPath,
223        SessionErrorCode::MalformedPath,
224        SessionErrorCode::GoawayTimeout,
225        SessionErrorCode::ControlMessageTimeout,
226        SessionErrorCode::DataStreamTimeout,
227        SessionErrorCode::AuthTokenCacheOverflow,
228        SessionErrorCode::DuplicateAuthTokenAlias,
229        SessionErrorCode::VersionNegotiationFailed,
230        SessionErrorCode::MalformedAuthToken,
231        SessionErrorCode::UnknownAuthTokenAlias,
232        SessionErrorCode::ExpiredAuthToken,
233        SessionErrorCode::InvalidAuthority,
234        SessionErrorCode::MalformedAuthority,
235    ];
236
237    /// Convert a raw u64 to a `SessionErrorCode`, if valid.
238    ///
239    /// Returns `None` for any code draft-17 does not define, including the
240    /// greasing range. Unknown codes arrive on the wire routinely and are not
241    /// an error for the decoder.
242    pub fn from_u64(v: u64) -> Option<Self> {
243        match v {
244            0x0 => Some(SessionErrorCode::NoError),
245            0x1 => Some(SessionErrorCode::InternalError),
246            0x2 => Some(SessionErrorCode::Unauthorized),
247            0x3 => Some(SessionErrorCode::ProtocolViolation),
248            0x4 => Some(SessionErrorCode::InvalidRequestId),
249            0x5 => Some(SessionErrorCode::DuplicateTrackAlias),
250            0x6 => Some(SessionErrorCode::KeyValueFormattingError),
251            0x7 => Some(SessionErrorCode::InvalidRequiredRequestId),
252            0x8 => Some(SessionErrorCode::InvalidPath),
253            0x9 => Some(SessionErrorCode::MalformedPath),
254            0x10 => Some(SessionErrorCode::GoawayTimeout),
255            0x11 => Some(SessionErrorCode::ControlMessageTimeout),
256            0x12 => Some(SessionErrorCode::DataStreamTimeout),
257            0x13 => Some(SessionErrorCode::AuthTokenCacheOverflow),
258            0x14 => Some(SessionErrorCode::DuplicateAuthTokenAlias),
259            0x15 => Some(SessionErrorCode::VersionNegotiationFailed),
260            0x16 => Some(SessionErrorCode::MalformedAuthToken),
261            0x17 => Some(SessionErrorCode::UnknownAuthTokenAlias),
262            0x18 => Some(SessionErrorCode::ExpiredAuthToken),
263            0x19 => Some(SessionErrorCode::InvalidAuthority),
264            0x1A => Some(SessionErrorCode::MalformedAuthority),
265            _ => None,
266        }
267    }
268
269    /// Return the raw u64 value of this error code.
270    pub fn as_u64(self) -> u64 {
271        self as u64
272    }
273}
274
275impl RequestErrorCode {
276    /// Every Request Error Code draft-17 assigns, in ascending wire order.
277    ///
278    /// This is the set [`Self::from_u64`] accepts, written out so that it can
279    /// be enumerated: nothing can iterate an enum's variants, so a caller that
280    /// wants the registry has to be handed it. Writing it down is also what
281    /// lets a test state its claims about the registry itself rather than about
282    /// the range some sweep happens to reach — that this is the set `from_u64`
283    /// answers to, and that none of it lands in the range the draft reserves
284    /// for greasing.
285    pub const ALL: &[RequestErrorCode] = &[
286        RequestErrorCode::InternalError,
287        RequestErrorCode::Unauthorized,
288        RequestErrorCode::Timeout,
289        RequestErrorCode::NotSupported,
290        RequestErrorCode::MalformedAuthToken,
291        RequestErrorCode::ExpiredAuthToken,
292        RequestErrorCode::GoingAway,
293        RequestErrorCode::ExcessiveLoad,
294        RequestErrorCode::DoesNotExist,
295        RequestErrorCode::InvalidRange,
296        RequestErrorCode::MalformedTrack,
297        RequestErrorCode::DuplicateSubscription,
298        RequestErrorCode::Uninterested,
299        RequestErrorCode::PrefixOverlap,
300        RequestErrorCode::NamespaceTooLarge,
301        RequestErrorCode::InvalidJoiningRequestId,
302    ];
303
304    /// Convert a raw u64 to a `RequestErrorCode`, if valid.
305    ///
306    /// Returns `None` for any code draft-17 does not define, including the
307    /// greasing range. Unknown codes arrive on the wire routinely and are not
308    /// an error for the decoder.
309    pub fn from_u64(v: u64) -> Option<Self> {
310        match v {
311            0x0 => Some(RequestErrorCode::InternalError),
312            0x1 => Some(RequestErrorCode::Unauthorized),
313            0x2 => Some(RequestErrorCode::Timeout),
314            0x3 => Some(RequestErrorCode::NotSupported),
315            0x4 => Some(RequestErrorCode::MalformedAuthToken),
316            0x5 => Some(RequestErrorCode::ExpiredAuthToken),
317            0x6 => Some(RequestErrorCode::GoingAway),
318            0x9 => Some(RequestErrorCode::ExcessiveLoad),
319            0x10 => Some(RequestErrorCode::DoesNotExist),
320            0x11 => Some(RequestErrorCode::InvalidRange),
321            0x12 => Some(RequestErrorCode::MalformedTrack),
322            0x19 => Some(RequestErrorCode::DuplicateSubscription),
323            0x20 => Some(RequestErrorCode::Uninterested),
324            0x30 => Some(RequestErrorCode::PrefixOverlap),
325            0x31 => Some(RequestErrorCode::NamespaceTooLarge),
326            0x32 => Some(RequestErrorCode::InvalidJoiningRequestId),
327            _ => None,
328        }
329    }
330
331    /// Return the raw u64 value of this error code.
332    pub fn as_u64(self) -> u64 {
333        self as u64
334    }
335}
336
337impl PublishDoneStatusCode {
338    /// Every PUBLISH_DONE Status Code draft-17 assigns, in ascending wire order.
339    ///
340    /// This is the set [`Self::from_u64`] accepts, written out so that it can
341    /// be enumerated: nothing can iterate an enum's variants, so a caller that
342    /// wants the registry has to be handed it. Writing it down is also what
343    /// lets a test state its claims about the registry itself rather than about
344    /// the range some sweep happens to reach — that this is the set `from_u64`
345    /// answers to, and that none of it lands in the range the draft reserves
346    /// for greasing.
347    pub const ALL: &[PublishDoneStatusCode] = &[
348        PublishDoneStatusCode::InternalError,
349        PublishDoneStatusCode::Unauthorized,
350        PublishDoneStatusCode::TrackEnded,
351        PublishDoneStatusCode::SubscriptionEnded,
352        PublishDoneStatusCode::GoingAway,
353        PublishDoneStatusCode::Expired,
354        PublishDoneStatusCode::TooFarBehind,
355        PublishDoneStatusCode::UpdateFailed,
356        PublishDoneStatusCode::ExcessiveLoad,
357        PublishDoneStatusCode::MalformedTrack,
358    ];
359
360    /// Convert a raw u64 to a `PublishDoneStatusCode`, if valid.
361    ///
362    /// Returns `None` for any code draft-17 does not define, including the
363    /// greasing range. Unknown codes arrive on the wire routinely and are not
364    /// an error for the decoder.
365    pub fn from_u64(v: u64) -> Option<Self> {
366        match v {
367            0x0 => Some(PublishDoneStatusCode::InternalError),
368            0x1 => Some(PublishDoneStatusCode::Unauthorized),
369            0x2 => Some(PublishDoneStatusCode::TrackEnded),
370            0x3 => Some(PublishDoneStatusCode::SubscriptionEnded),
371            0x4 => Some(PublishDoneStatusCode::GoingAway),
372            0x5 => Some(PublishDoneStatusCode::Expired),
373            0x6 => Some(PublishDoneStatusCode::TooFarBehind),
374            0x8 => Some(PublishDoneStatusCode::UpdateFailed),
375            0x9 => Some(PublishDoneStatusCode::ExcessiveLoad),
376            0x12 => Some(PublishDoneStatusCode::MalformedTrack),
377            _ => None,
378        }
379    }
380
381    /// Return the raw u64 value of this status code.
382    pub fn as_u64(self) -> u64 {
383        self as u64
384    }
385}
386
387impl DataStreamResetErrorCode {
388    /// Every Data Stream Reset Error Code draft-17 assigns, in ascending wire order.
389    ///
390    /// This is the set [`Self::from_u64`] accepts, written out so that it can
391    /// be enumerated: nothing can iterate an enum's variants, so a caller that
392    /// wants the registry has to be handed it. Writing it down is also what
393    /// lets a test state its claims about the registry itself rather than about
394    /// the range some sweep happens to reach — that this is the set `from_u64`
395    /// answers to, and that none of it lands in the range the draft reserves
396    /// for greasing.
397    pub const ALL: &[DataStreamResetErrorCode] = &[
398        DataStreamResetErrorCode::InternalError,
399        DataStreamResetErrorCode::Cancelled,
400        DataStreamResetErrorCode::DeliveryTimeout,
401        DataStreamResetErrorCode::SessionClosed,
402        DataStreamResetErrorCode::UnknownObjectStatus,
403        DataStreamResetErrorCode::TooFarBehind,
404        DataStreamResetErrorCode::ExcessiveLoad,
405        DataStreamResetErrorCode::MalformedTrack,
406    ];
407
408    /// Convert a raw u64 to a `DataStreamResetErrorCode`, if valid.
409    ///
410    /// Returns `None` for any code draft-17 does not define, including the
411    /// greasing range. Unknown codes arrive on the wire routinely and are not
412    /// an error for the decoder.
413    pub fn from_u64(v: u64) -> Option<Self> {
414        match v {
415            0x0 => Some(DataStreamResetErrorCode::InternalError),
416            0x1 => Some(DataStreamResetErrorCode::Cancelled),
417            0x2 => Some(DataStreamResetErrorCode::DeliveryTimeout),
418            0x3 => Some(DataStreamResetErrorCode::SessionClosed),
419            0x4 => Some(DataStreamResetErrorCode::UnknownObjectStatus),
420            0x5 => Some(DataStreamResetErrorCode::TooFarBehind),
421            0x9 => Some(DataStreamResetErrorCode::ExcessiveLoad),
422            0x12 => Some(DataStreamResetErrorCode::MalformedTrack),
423            _ => None,
424        }
425    }
426
427    /// Return the raw u64 value of this error code.
428    pub fn as_u64(self) -> u64 {
429        self as u64
430    }
431}