Skip to main content

moqtap_codec/draft12/
error_codes.rs

1//! Error, status and termination code registries defined by MoQ Transport draft-12.
2//!
3//! Draft-12 predates the IANA registries introduced in draft-14. Its code tables have
4//! exactly two columns, `Code` and `Reason`, and the `Reason` cell is a human-readable
5//! phrase rather than an ALLCAPS symbolic name — draft-12 gives its error, status and
6//! termination codes no symbolic names. (It does name other things that way, such as the
7//! control message types in section 8 and the authorization token operations in section
8//! 8.2.1.1, but not these.) Each variant name here is therefore derived mechanically from
9//! the `Reason` phrase.
10//!
11//! Each table is followed in the draft by a definition list giving one sentence per code.
12//! Every variant below carries its `Reason` phrase, so the mapping back to the table stays
13//! checkable, followed by that sentence. All 71 codes in these eight tables are described
14//! this way in the draft; nothing here is invented. Cross-references that the draft renders
15//! as hyperlinks appear as plain section numbers. One entry is repunctuated: the draft
16//! writes the `Expired Auth Token` sentence as "Authorization token has expired Section
17//! 8.2.1.1 )." with an unbalanced parenthesis, and it appears here in the "(see section
18//! 8.2.1.1)" form its neighbours use.
19//!
20//! Every `from_u64` returns `None` for a code the draft does not assign. Peers do send
21//! codes from other drafts and from private extensions, so an unrecognised code is a
22//! value to pass through, not a decoding failure.
23//!
24//! The eight registries transcribed here, with their draft-12 sections:
25//!
26//! - 3.4 Termination — [`SessionErrorCode`]
27//! - 8.9 SUBSCRIBE_ERROR — [`SubscribeErrorCode`]
28//! - 8.12 SUBSCRIBE_DONE — [`SubscribeDoneStatusCode`]
29//! - 8.15 PUBLISH_ERROR — [`PublishErrorCode`]
30//! - 8.18 FETCH_ERROR — [`FetchErrorCode`]
31//! - 8.24 ANNOUNCE_ERROR — [`AnnounceErrorCode`]
32//! - 8.29 SUBSCRIBE_ANNOUNCES_ERROR — [`SubscribeAnnouncesErrorCode`]
33//! - 9.4.3 Closing Subgroup Streams — [`StreamResetErrorCode`]
34//!
35//! [`SessionErrorCode`]: crate::draft12::error_codes::SessionErrorCode
36//! [`SubscribeErrorCode`]: crate::draft12::error_codes::SubscribeErrorCode
37//! [`SubscribeDoneStatusCode`]: crate::draft12::error_codes::SubscribeDoneStatusCode
38//! [`PublishErrorCode`]: crate::draft12::error_codes::PublishErrorCode
39//! [`FetchErrorCode`]: crate::draft12::error_codes::FetchErrorCode
40//! [`AnnounceErrorCode`]: crate::draft12::error_codes::AnnounceErrorCode
41//! [`SubscribeAnnouncesErrorCode`]: crate::draft12::error_codes::SubscribeAnnouncesErrorCode
42//! [`StreamResetErrorCode`]: crate::draft12::error_codes::StreamResetErrorCode
43//!
44//! Draft-12 reserves no code ranges for greasing in any of these tables.
45
46/// Session termination error codes (draft-12 section 3.4, Termination).
47///
48/// Sent when closing the session: "When terminating the Session, the application MAY use
49/// any error message and SHOULD use a relevant code, as defined below".
50///
51/// The table jumps from 0x9 to 0x10; 0xA through 0xF are unassigned.
52#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53#[repr(u64)]
54pub enum SessionErrorCode {
55    /// `No Error` — The session is being terminated without an error.
56    NoError = 0x0,
57    /// `Internal Error` — An implementation specific error occurred.
58    InternalError = 0x1,
59    /// `Unauthorized` — The client is not authorized to establish a session.
60    Unauthorized = 0x2,
61    /// `Protocol Violation` — The remote endpoint performed an action that was disallowed
62    /// by the specification.
63    ProtocolViolation = 0x3,
64    /// `Invalid Request ID` — The session was closed because the endpoint used a Request ID
65    /// that was smaller than or equal to a previously received request ID, or the
66    /// least-significant bit of the request ID was incorrect for the endpoint.
67    InvalidRequestId = 0x4,
68    /// `Duplicate Track Alias` — The endpoint attempted to use a Track Alias that was
69    /// already in use.
70    DuplicateTrackAlias = 0x5,
71    /// `Key-Value Formatting Error` — The key-value pair has a formatting error.
72    KeyValueFormattingError = 0x6,
73    /// `Too Many Requests` — The session was closed because the endpoint used a Request ID
74    /// equal to or larger than the current Maximum Request ID.
75    TooManyRequests = 0x7,
76    /// `Invalid Path` — The PATH parameter was used by a server, on a WebTransport session,
77    /// or the server does not support the path.
78    InvalidPath = 0x8,
79    /// `Malformed Path` — The PATH parameter does not conform to the rules in section
80    /// 8.3.2.1.
81    MalformedPath = 0x9,
82    /// `GOAWAY Timeout` — The session was closed because the peer took too long to close
83    /// the session in response to a GOAWAY (section 8.4) message. See session migration
84    /// (section 3.5).
85    GoawayTimeout = 0x10,
86    /// `Control Message Timeout` — The session was closed because the peer took too long to
87    /// respond to a control message.
88    ControlMessageTimeout = 0x11,
89    /// `Data Stream Timeout` — The session was closed because the peer took too long to
90    /// send data expected on an open Data Stream (see section 9). This includes fields of a
91    /// stream header or an object header within a data stream. If an endpoint times out
92    /// waiting for a new object header on an open subgroup stream, it MAY send a
93    /// STOP_SENDING on that stream or terminate the subscription.
94    DataStreamTimeout = 0x12,
95    /// `Auth Token Cache Overflow` — The Session limit (section 8.3.2.3) of the size of all
96    /// registered Authorization tokens has been exceeded.
97    AuthTokenCacheOverflow = 0x13,
98    /// `Duplicate Auth Token Alias` — Authorization Token attempted to register an Alias
99    /// that was in use (see section 8.2.1.1).
100    DuplicateAuthTokenAlias = 0x14,
101    /// `Version Negotiation Failed` — The client didn't offer a version supported by the
102    /// server.
103    VersionNegotiationFailed = 0x15,
104    /// `Malformed Auth Token` — Invalid Auth Token serialization during registration (see
105    /// section 8.2.1.1).
106    MalformedAuthToken = 0x16,
107    /// `Unknown Auth Token Alias` — No registered token found for the provided Alias (see
108    /// section 8.2.1.1).
109    UnknownAuthTokenAlias = 0x17,
110    /// `Expired Auth Token` — Authorization token has expired (see section 8.2.1.1).
111    ExpiredAuthToken = 0x18,
112}
113
114/// SUBSCRIBE_ERROR codes (draft-12 section 8.9).
115///
116/// The table assigns 0x0 through 0x5, then 0x10 and 0x12; 0x11 is unassigned. The session
117/// termination table carries three auth-token codes at 0x16, 0x17 and 0x18, exactly 6 above
118/// 0x10, 0x11 and 0x12, so the unassigned slot lines up with `Unknown Auth Token Alias`,
119/// which has no request-level counterpart. The draft does not say this is why the gap is
120/// there.
121#[derive(Debug, Clone, Copy, PartialEq, Eq)]
122#[repr(u64)]
123pub enum SubscribeErrorCode {
124    /// `Internal Error` — An implementation specific or generic error occurred.
125    InternalError = 0x0,
126    /// `Unauthorized` — The subscriber is not authorized to subscribe to the given track.
127    Unauthorized = 0x1,
128    /// `Timeout` — The subscription could not be completed before an implementation
129    /// specific timeout. For example, a relay could not establish an upstream subscription
130    /// within the timeout.
131    Timeout = 0x2,
132    /// `Not Supported` — The endpoint does not support the SUBSCRIBE method.
133    NotSupported = 0x3,
134    /// `Track Does Not Exist` — The requested track is not available at the publisher.
135    TrackDoesNotExist = 0x4,
136    /// `Invalid Range` — The end of the SUBSCRIBE range is earlier than the beginning, or
137    /// the end of the range has already been published.
138    InvalidRange = 0x5,
139    /// `Malformed Auth Token` — Invalid Auth Token serialization during registration (see
140    /// section 8.2.1.1).
141    MalformedAuthToken = 0x10,
142    /// `Expired Auth Token` — Authorization token has expired (see section 8.2.1.1).
143    ExpiredAuthToken = 0x12,
144}
145
146/// SUBSCRIBE_DONE status codes (draft-12 section 8.12).
147///
148/// The SUBSCRIBE_DONE message carries a Status Code field, described by the draft as "an
149/// integer status code indicating why the subscription ended". The draft does not divide
150/// these codes into successes and failures.
151#[derive(Debug, Clone, Copy, PartialEq, Eq)]
152#[repr(u64)]
153pub enum SubscribeDoneStatusCode {
154    /// `Internal Error` — An implementation specific or generic error occurred.
155    InternalError = 0x0,
156    /// `Unauthorized` — The subscriber is no longer authorized to subscribe to the given
157    /// track.
158    Unauthorized = 0x1,
159    /// `Track Ended` — The track is no longer being published.
160    TrackEnded = 0x2,
161    /// `Subscription Ended` — The publisher reached the end of an associated Subscribe
162    /// filter.
163    SubscriptionEnded = 0x3,
164    /// `Going Away` — The subscriber or publisher issued a GOAWAY message.
165    GoingAway = 0x4,
166    /// `Expired` — The publisher reached the timeout specified in SUBSCRIBE_OK.
167    Expired = 0x5,
168    /// `Too Far Behind` — The publisher's queue of objects to be sent to the given
169    /// subscriber exceeds its implementation defined limit.
170    TooFarBehind = 0x6,
171    /// `Malformed Track` — A relay publisher detected the track was malformed (see section
172    /// 2.5).
173    MalformedTrack = 0x7,
174}
175
176/// PUBLISH_ERROR codes (draft-12 section 8.15).
177///
178/// PUBLISH, PUBLISH_OK and PUBLISH_ERROR are new in draft-12; draft-11's control message
179/// table has no PUBLISH entries. Unlike the other request-error tables this one assigns no
180/// auth-token codes at 0x10 or 0x12; its five entries are contiguous from 0x0.
181#[derive(Debug, Clone, Copy, PartialEq, Eq)]
182#[repr(u64)]
183pub enum PublishErrorCode {
184    /// `Internal Error` — An implementation specific or generic error occurred.
185    InternalError = 0x0,
186    /// `Unauthorized` — The publisher is not authorized to publish the given namespace or
187    /// track.
188    Unauthorized = 0x1,
189    /// `Timeout` — The subscription could not be established before an implementation
190    /// specific timeout.
191    Timeout = 0x2,
192    /// `Not Supported` — The endpoint does not support the PUBLISH method.
193    NotSupported = 0x3,
194    /// `Uninterested` — The namespace or track is not of interest to the endpoint.
195    Uninterested = 0x4,
196}
197
198/// FETCH_ERROR codes (draft-12 section 8.18).
199///
200/// Assigns 0x0 through 0x9, then 0x10 and 0x12; 0x11 is unassigned.
201///
202/// The draft names 0x7 inconsistently: the table cell reads "Invalid Joining Request ID"
203/// while the definition list below it reads "Invalid Joining Subscribe ID". The table is
204/// the code point assignment and is followed here; draft-14 settles the question by naming
205/// the same code INVALID_JOINING_REQUEST_ID.
206#[derive(Debug, Clone, Copy, PartialEq, Eq)]
207#[repr(u64)]
208pub enum FetchErrorCode {
209    /// `Internal Error` — An implementation specific or generic error occurred.
210    InternalError = 0x0,
211    /// `Unauthorized` — The subscriber is not authorized to fetch from the given track.
212    Unauthorized = 0x1,
213    /// `Timeout` — The fetch could not be completed before an implementation specific
214    /// timeout. For example, a relay could not FETCH missing objects within the timeout.
215    Timeout = 0x2,
216    /// `Not Supported` — The endpoint does not support the FETCH method.
217    NotSupported = 0x3,
218    /// `Track Does Not Exist` — The requested track is not available at the publisher.
219    TrackDoesNotExist = 0x4,
220    /// `Invalid Range` — The end of the requested range is earlier than the beginning, the
221    /// start of the requested range is beyond the Largest Location, or the track has not
222    /// published any Objects yet.
223    InvalidRange = 0x5,
224    /// `No Objects` — No Objects exist between the requested Start and End Locations.
225    NoObjects = 0x6,
226    /// `Invalid Joining Request ID` — The joining Fetch referenced a Request ID that did not
227    /// belong to an active Subscription.
228    InvalidJoiningRequestId = 0x7,
229    /// `Unknown Status in Range` — The requested range contains objects with unknown status.
230    UnknownStatusInRange = 0x8,
231    /// `Malformed Track` — A relay publisher detected the track was malformed (see section
232    /// 2.5).
233    MalformedTrack = 0x9,
234    /// `Malformed Auth Token` — Invalid Auth Token serialization during registration (see
235    /// section 8.2.1.1).
236    MalformedAuthToken = 0x10,
237    /// `Expired Auth Token` — Authorization token has expired (see section 8.2.1.1).
238    ExpiredAuthToken = 0x12,
239}
240
241/// ANNOUNCE_ERROR codes (draft-12 section 8.24).
242///
243/// Assigns 0x0 through 0x4, then 0x10 and 0x12; 0x11 is unassigned.
244#[derive(Debug, Clone, Copy, PartialEq, Eq)]
245#[repr(u64)]
246pub enum AnnounceErrorCode {
247    /// `Internal Error` — An implementation specific or generic error occurred.
248    InternalError = 0x0,
249    /// `Unauthorized` — The subscriber is not authorized to announce the given namespace.
250    Unauthorized = 0x1,
251    /// `Timeout` — The announce could not be completed before an implementation specific
252    /// timeout.
253    Timeout = 0x2,
254    /// `Not Supported` — The endpoint does not support the ANNOUNCE method.
255    NotSupported = 0x3,
256    /// `Uninterested` — The namespace is not of interest to the endpoint.
257    Uninterested = 0x4,
258    /// `Malformed Auth Token` — Invalid Auth Token serialization during registration (see
259    /// section 8.2.1.1).
260    MalformedAuthToken = 0x10,
261    /// `Expired Auth Token` — Authorization token has expired (see section 8.2.1.1).
262    ExpiredAuthToken = 0x12,
263}
264
265/// SUBSCRIBE_ANNOUNCES_ERROR codes (draft-12 section 8.29).
266///
267/// Assigns 0x0 through 0x5, then 0x10 and 0x12; 0x11 is unassigned.
268#[derive(Debug, Clone, Copy, PartialEq, Eq)]
269#[repr(u64)]
270pub enum SubscribeAnnouncesErrorCode {
271    /// `Internal Error` — An implementation specific or generic error occurred.
272    InternalError = 0x0,
273    /// `Unauthorized` — The subscriber is not authorized to subscribe to the given namespace
274    /// prefix.
275    Unauthorized = 0x1,
276    /// `Timeout` — The operation could not be completed before an implementation specific
277    /// timeout.
278    Timeout = 0x2,
279    /// `Not Supported` — The endpoint does not support the SUBSCRIBE_ANNOUNCES method.
280    NotSupported = 0x3,
281    /// `Namespace Prefix Unknown` — The namespace prefix is not available for subscription.
282    NamespacePrefixUnknown = 0x4,
283    /// `Namespace Prefix Overlap` — The namespace prefix overlaps with another
284    /// SUBSCRIBE_ANNOUNCES in the same session.
285    NamespacePrefixOverlap = 0x5,
286    /// `Malformed Auth Token` — Invalid Auth Token serialization during registration (see
287    /// section 8.2.1.1).
288    MalformedAuthToken = 0x10,
289    /// `Expired Auth Token` — Authorization token has expired (see section 8.2.1.1).
290    ExpiredAuthToken = 0x12,
291}
292
293/// Data stream reset error codes (draft-12 section 9.4.3, Closing Subgroup Streams).
294///
295/// Carried in the RESET_STREAM or RESET_STREAM_AT frame that tears down a subgroup stream:
296/// "The application SHOULD use a relevant error code in RESET_STREAM or RESET_STREAM_AT, as
297/// defined below"
298#[derive(Debug, Clone, Copy, PartialEq, Eq)]
299#[repr(u64)]
300pub enum StreamResetErrorCode {
301    /// `Internal Error` — An implementation specific error.
302    InternalError = 0x0,
303    /// `Cancelled` — The subscriber requested cancellation via UNSUBSCRIBE, FETCH_CANCEL or
304    /// STOP_SENDING, or the publisher ended the subscription, in which case SUBSCRIBE_DONE
305    /// (section 8.12) will have a more detailed status code.
306    Cancelled = 0x1,
307    /// `Delivery Timeout` — The DELIVERY TIMEOUT (section 8.2.1.2) was exceeded for this
308    /// stream.
309    DeliveryTimeout = 0x2,
310    /// `Session Closed` — The publisher session is being closed.
311    SessionClosed = 0x3,
312}
313
314impl SessionErrorCode {
315    /// Every session termination code draft-12 assigns, in ascending wire order.
316    ///
317    /// This is the set [`Self::from_u64`] accepts, written out so that it can
318    /// be enumerated: nothing can iterate an enum's variants, so a caller that
319    /// wants the registry has to be handed it. Writing it down is also what
320    /// lets a test state its claims about the registry itself rather than about
321    /// the range some sweep happens to reach.
322    pub const ALL: &[SessionErrorCode] = &[
323        SessionErrorCode::NoError,
324        SessionErrorCode::InternalError,
325        SessionErrorCode::Unauthorized,
326        SessionErrorCode::ProtocolViolation,
327        SessionErrorCode::InvalidRequestId,
328        SessionErrorCode::DuplicateTrackAlias,
329        SessionErrorCode::KeyValueFormattingError,
330        SessionErrorCode::TooManyRequests,
331        SessionErrorCode::InvalidPath,
332        SessionErrorCode::MalformedPath,
333        SessionErrorCode::GoawayTimeout,
334        SessionErrorCode::ControlMessageTimeout,
335        SessionErrorCode::DataStreamTimeout,
336        SessionErrorCode::AuthTokenCacheOverflow,
337        SessionErrorCode::DuplicateAuthTokenAlias,
338        SessionErrorCode::VersionNegotiationFailed,
339        SessionErrorCode::MalformedAuthToken,
340        SessionErrorCode::UnknownAuthTokenAlias,
341        SessionErrorCode::ExpiredAuthToken,
342    ];
343
344    /// Convert a raw u64 to a `SessionErrorCode`, if valid.
345    pub fn from_u64(v: u64) -> Option<Self> {
346        match v {
347            0x0 => Some(SessionErrorCode::NoError),
348            0x1 => Some(SessionErrorCode::InternalError),
349            0x2 => Some(SessionErrorCode::Unauthorized),
350            0x3 => Some(SessionErrorCode::ProtocolViolation),
351            0x4 => Some(SessionErrorCode::InvalidRequestId),
352            0x5 => Some(SessionErrorCode::DuplicateTrackAlias),
353            0x6 => Some(SessionErrorCode::KeyValueFormattingError),
354            0x7 => Some(SessionErrorCode::TooManyRequests),
355            0x8 => Some(SessionErrorCode::InvalidPath),
356            0x9 => Some(SessionErrorCode::MalformedPath),
357            0x10 => Some(SessionErrorCode::GoawayTimeout),
358            0x11 => Some(SessionErrorCode::ControlMessageTimeout),
359            0x12 => Some(SessionErrorCode::DataStreamTimeout),
360            0x13 => Some(SessionErrorCode::AuthTokenCacheOverflow),
361            0x14 => Some(SessionErrorCode::DuplicateAuthTokenAlias),
362            0x15 => Some(SessionErrorCode::VersionNegotiationFailed),
363            0x16 => Some(SessionErrorCode::MalformedAuthToken),
364            0x17 => Some(SessionErrorCode::UnknownAuthTokenAlias),
365            0x18 => Some(SessionErrorCode::ExpiredAuthToken),
366            _ => None,
367        }
368    }
369
370    /// Return the raw u64 value of this error code.
371    pub fn as_u64(self) -> u64 {
372        self as u64
373    }
374}
375
376impl SubscribeErrorCode {
377    /// Every SUBSCRIBE_ERROR code draft-12 assigns, in ascending wire order.
378    ///
379    /// This is the set [`Self::from_u64`] accepts, written out so that it can
380    /// be enumerated: nothing can iterate an enum's variants, so a caller that
381    /// wants the registry has to be handed it. Writing it down is also what
382    /// lets a test state its claims about the registry itself rather than about
383    /// the range some sweep happens to reach.
384    pub const ALL: &[SubscribeErrorCode] = &[
385        SubscribeErrorCode::InternalError,
386        SubscribeErrorCode::Unauthorized,
387        SubscribeErrorCode::Timeout,
388        SubscribeErrorCode::NotSupported,
389        SubscribeErrorCode::TrackDoesNotExist,
390        SubscribeErrorCode::InvalidRange,
391        SubscribeErrorCode::MalformedAuthToken,
392        SubscribeErrorCode::ExpiredAuthToken,
393    ];
394
395    /// Convert a raw u64 to a `SubscribeErrorCode`, if valid.
396    pub fn from_u64(v: u64) -> Option<Self> {
397        match v {
398            0x0 => Some(SubscribeErrorCode::InternalError),
399            0x1 => Some(SubscribeErrorCode::Unauthorized),
400            0x2 => Some(SubscribeErrorCode::Timeout),
401            0x3 => Some(SubscribeErrorCode::NotSupported),
402            0x4 => Some(SubscribeErrorCode::TrackDoesNotExist),
403            0x5 => Some(SubscribeErrorCode::InvalidRange),
404            0x10 => Some(SubscribeErrorCode::MalformedAuthToken),
405            0x12 => Some(SubscribeErrorCode::ExpiredAuthToken),
406            _ => None,
407        }
408    }
409
410    /// Return the raw u64 value of this error code.
411    pub fn as_u64(self) -> u64 {
412        self as u64
413    }
414}
415
416impl SubscribeDoneStatusCode {
417    /// Every SUBSCRIBE_DONE status code draft-12 assigns, in ascending wire order.
418    ///
419    /// This is the set [`Self::from_u64`] accepts, written out so that it can
420    /// be enumerated: nothing can iterate an enum's variants, so a caller that
421    /// wants the registry has to be handed it. Writing it down is also what
422    /// lets a test state its claims about the registry itself rather than about
423    /// the range some sweep happens to reach.
424    pub const ALL: &[SubscribeDoneStatusCode] = &[
425        SubscribeDoneStatusCode::InternalError,
426        SubscribeDoneStatusCode::Unauthorized,
427        SubscribeDoneStatusCode::TrackEnded,
428        SubscribeDoneStatusCode::SubscriptionEnded,
429        SubscribeDoneStatusCode::GoingAway,
430        SubscribeDoneStatusCode::Expired,
431        SubscribeDoneStatusCode::TooFarBehind,
432        SubscribeDoneStatusCode::MalformedTrack,
433    ];
434
435    /// Convert a raw u64 to a `SubscribeDoneStatusCode`, if valid.
436    pub fn from_u64(v: u64) -> Option<Self> {
437        match v {
438            0x0 => Some(SubscribeDoneStatusCode::InternalError),
439            0x1 => Some(SubscribeDoneStatusCode::Unauthorized),
440            0x2 => Some(SubscribeDoneStatusCode::TrackEnded),
441            0x3 => Some(SubscribeDoneStatusCode::SubscriptionEnded),
442            0x4 => Some(SubscribeDoneStatusCode::GoingAway),
443            0x5 => Some(SubscribeDoneStatusCode::Expired),
444            0x6 => Some(SubscribeDoneStatusCode::TooFarBehind),
445            0x7 => Some(SubscribeDoneStatusCode::MalformedTrack),
446            _ => None,
447        }
448    }
449
450    /// Return the raw u64 value of this status code.
451    pub fn as_u64(self) -> u64 {
452        self as u64
453    }
454}
455
456impl PublishErrorCode {
457    /// Every PUBLISH_ERROR code draft-12 assigns, in ascending wire order.
458    ///
459    /// This is the set [`Self::from_u64`] accepts, written out so that it can
460    /// be enumerated: nothing can iterate an enum's variants, so a caller that
461    /// wants the registry has to be handed it. Writing it down is also what
462    /// lets a test state its claims about the registry itself rather than about
463    /// the range some sweep happens to reach.
464    pub const ALL: &[PublishErrorCode] = &[
465        PublishErrorCode::InternalError,
466        PublishErrorCode::Unauthorized,
467        PublishErrorCode::Timeout,
468        PublishErrorCode::NotSupported,
469        PublishErrorCode::Uninterested,
470    ];
471
472    /// Convert a raw u64 to a `PublishErrorCode`, if valid.
473    pub fn from_u64(v: u64) -> Option<Self> {
474        match v {
475            0x0 => Some(PublishErrorCode::InternalError),
476            0x1 => Some(PublishErrorCode::Unauthorized),
477            0x2 => Some(PublishErrorCode::Timeout),
478            0x3 => Some(PublishErrorCode::NotSupported),
479            0x4 => Some(PublishErrorCode::Uninterested),
480            _ => None,
481        }
482    }
483
484    /// Return the raw u64 value of this error code.
485    pub fn as_u64(self) -> u64 {
486        self as u64
487    }
488}
489
490impl FetchErrorCode {
491    /// Every FETCH_ERROR code draft-12 assigns, in ascending wire order.
492    ///
493    /// This is the set [`Self::from_u64`] accepts, written out so that it can
494    /// be enumerated: nothing can iterate an enum's variants, so a caller that
495    /// wants the registry has to be handed it. Writing it down is also what
496    /// lets a test state its claims about the registry itself rather than about
497    /// the range some sweep happens to reach.
498    pub const ALL: &[FetchErrorCode] = &[
499        FetchErrorCode::InternalError,
500        FetchErrorCode::Unauthorized,
501        FetchErrorCode::Timeout,
502        FetchErrorCode::NotSupported,
503        FetchErrorCode::TrackDoesNotExist,
504        FetchErrorCode::InvalidRange,
505        FetchErrorCode::NoObjects,
506        FetchErrorCode::InvalidJoiningRequestId,
507        FetchErrorCode::UnknownStatusInRange,
508        FetchErrorCode::MalformedTrack,
509        FetchErrorCode::MalformedAuthToken,
510        FetchErrorCode::ExpiredAuthToken,
511    ];
512
513    /// Convert a raw u64 to a `FetchErrorCode`, if valid.
514    pub fn from_u64(v: u64) -> Option<Self> {
515        match v {
516            0x0 => Some(FetchErrorCode::InternalError),
517            0x1 => Some(FetchErrorCode::Unauthorized),
518            0x2 => Some(FetchErrorCode::Timeout),
519            0x3 => Some(FetchErrorCode::NotSupported),
520            0x4 => Some(FetchErrorCode::TrackDoesNotExist),
521            0x5 => Some(FetchErrorCode::InvalidRange),
522            0x6 => Some(FetchErrorCode::NoObjects),
523            0x7 => Some(FetchErrorCode::InvalidJoiningRequestId),
524            0x8 => Some(FetchErrorCode::UnknownStatusInRange),
525            0x9 => Some(FetchErrorCode::MalformedTrack),
526            0x10 => Some(FetchErrorCode::MalformedAuthToken),
527            0x12 => Some(FetchErrorCode::ExpiredAuthToken),
528            _ => None,
529        }
530    }
531
532    /// Return the raw u64 value of this error code.
533    pub fn as_u64(self) -> u64 {
534        self as u64
535    }
536}
537
538impl AnnounceErrorCode {
539    /// Every ANNOUNCE_ERROR code draft-12 assigns, in ascending wire order.
540    ///
541    /// This is the set [`Self::from_u64`] accepts, written out so that it can
542    /// be enumerated: nothing can iterate an enum's variants, so a caller that
543    /// wants the registry has to be handed it. Writing it down is also what
544    /// lets a test state its claims about the registry itself rather than about
545    /// the range some sweep happens to reach.
546    pub const ALL: &[AnnounceErrorCode] = &[
547        AnnounceErrorCode::InternalError,
548        AnnounceErrorCode::Unauthorized,
549        AnnounceErrorCode::Timeout,
550        AnnounceErrorCode::NotSupported,
551        AnnounceErrorCode::Uninterested,
552        AnnounceErrorCode::MalformedAuthToken,
553        AnnounceErrorCode::ExpiredAuthToken,
554    ];
555
556    /// Convert a raw u64 to an `AnnounceErrorCode`, if valid.
557    pub fn from_u64(v: u64) -> Option<Self> {
558        match v {
559            0x0 => Some(AnnounceErrorCode::InternalError),
560            0x1 => Some(AnnounceErrorCode::Unauthorized),
561            0x2 => Some(AnnounceErrorCode::Timeout),
562            0x3 => Some(AnnounceErrorCode::NotSupported),
563            0x4 => Some(AnnounceErrorCode::Uninterested),
564            0x10 => Some(AnnounceErrorCode::MalformedAuthToken),
565            0x12 => Some(AnnounceErrorCode::ExpiredAuthToken),
566            _ => None,
567        }
568    }
569
570    /// Return the raw u64 value of this error code.
571    pub fn as_u64(self) -> u64 {
572        self as u64
573    }
574}
575
576impl SubscribeAnnouncesErrorCode {
577    /// Every SUBSCRIBE_ANNOUNCES_ERROR code draft-12 assigns, in ascending wire order.
578    ///
579    /// This is the set [`Self::from_u64`] accepts, written out so that it can
580    /// be enumerated: nothing can iterate an enum's variants, so a caller that
581    /// wants the registry has to be handed it. Writing it down is also what
582    /// lets a test state its claims about the registry itself rather than about
583    /// the range some sweep happens to reach.
584    pub const ALL: &[SubscribeAnnouncesErrorCode] = &[
585        SubscribeAnnouncesErrorCode::InternalError,
586        SubscribeAnnouncesErrorCode::Unauthorized,
587        SubscribeAnnouncesErrorCode::Timeout,
588        SubscribeAnnouncesErrorCode::NotSupported,
589        SubscribeAnnouncesErrorCode::NamespacePrefixUnknown,
590        SubscribeAnnouncesErrorCode::NamespacePrefixOverlap,
591        SubscribeAnnouncesErrorCode::MalformedAuthToken,
592        SubscribeAnnouncesErrorCode::ExpiredAuthToken,
593    ];
594
595    /// Convert a raw u64 to a `SubscribeAnnouncesErrorCode`, if valid.
596    pub fn from_u64(v: u64) -> Option<Self> {
597        match v {
598            0x0 => Some(SubscribeAnnouncesErrorCode::InternalError),
599            0x1 => Some(SubscribeAnnouncesErrorCode::Unauthorized),
600            0x2 => Some(SubscribeAnnouncesErrorCode::Timeout),
601            0x3 => Some(SubscribeAnnouncesErrorCode::NotSupported),
602            0x4 => Some(SubscribeAnnouncesErrorCode::NamespacePrefixUnknown),
603            0x5 => Some(SubscribeAnnouncesErrorCode::NamespacePrefixOverlap),
604            0x10 => Some(SubscribeAnnouncesErrorCode::MalformedAuthToken),
605            0x12 => Some(SubscribeAnnouncesErrorCode::ExpiredAuthToken),
606            _ => None,
607        }
608    }
609
610    /// Return the raw u64 value of this error code.
611    pub fn as_u64(self) -> u64 {
612        self as u64
613    }
614}
615
616impl StreamResetErrorCode {
617    /// Every subgroup stream reset code draft-12 assigns, in ascending wire order.
618    ///
619    /// This is the set [`Self::from_u64`] accepts, written out so that it can
620    /// be enumerated: nothing can iterate an enum's variants, so a caller that
621    /// wants the registry has to be handed it. Writing it down is also what
622    /// lets a test state its claims about the registry itself rather than about
623    /// the range some sweep happens to reach.
624    pub const ALL: &[StreamResetErrorCode] = &[
625        StreamResetErrorCode::InternalError,
626        StreamResetErrorCode::Cancelled,
627        StreamResetErrorCode::DeliveryTimeout,
628        StreamResetErrorCode::SessionClosed,
629    ];
630
631    /// Convert a raw u64 to a `StreamResetErrorCode`, if valid.
632    pub fn from_u64(v: u64) -> Option<Self> {
633        match v {
634            0x0 => Some(StreamResetErrorCode::InternalError),
635            0x1 => Some(StreamResetErrorCode::Cancelled),
636            0x2 => Some(StreamResetErrorCode::DeliveryTimeout),
637            0x3 => Some(StreamResetErrorCode::SessionClosed),
638            _ => None,
639        }
640    }
641
642    /// Return the raw u64 value of this error code.
643    pub fn as_u64(self) -> u64 {
644        self as u64
645    }
646}
647
648/// TRACK_STATUS Status Code values (draft-12, Section 8.21).
649///
650/// The draft defines these as a prose list rather than as a `Code`/`Reason`
651/// table, so they are named from the prose. It is stricter about this field
652/// than about the error registries above: the Status Code "MUST hold one of the
653/// following values" and "Any other value in the Status Code field is a
654/// malformed message", so [`TrackStatusCode::from_u64`] answering `None` is a
655/// decode failure rather than a merely unrecognised code.
656#[derive(Debug, Clone, Copy, PartialEq, Eq)]
657#[repr(u64)]
658pub enum TrackStatusCode {
659    /// The track is in progress, and subsequent fields contain the highest
660    /// group and object ID for that track.
661    InProgress = 0x00,
662    /// The track does not exist. Subsequent fields MUST be zero, and any other
663    /// value is a malformed message.
664    TrackDoesNotExist = 0x01,
665    /// The track has not yet begun. Subsequent fields MUST be zero, and any
666    /// other value is a malformed message.
667    NotYetBegun = 0x02,
668    /// The track has finished, so there is no live edge. Subsequent fields
669    /// contain the highest group and object ID known.
670    Finished = 0x03,
671    /// The publisher is a relay that cannot obtain the current track status
672    /// from upstream. Subsequent fields contain the largest group and object
673    /// ID known.
674    RelayStatusUnavailable = 0x04,
675}
676
677impl TrackStatusCode {
678    /// Convert a raw u64 to a `TrackStatusCode`, if this draft assigns it.
679    pub fn from_u64(v: u64) -> Option<Self> {
680        match v {
681            0x00 => Some(TrackStatusCode::InProgress),
682            0x01 => Some(TrackStatusCode::TrackDoesNotExist),
683            0x02 => Some(TrackStatusCode::NotYetBegun),
684            0x03 => Some(TrackStatusCode::Finished),
685            0x04 => Some(TrackStatusCode::RelayStatusUnavailable),
686            _ => None,
687        }
688    }
689
690    /// Whether this code requires the fields after it to be zero.
691    ///
692    /// Section 8.21 says of 0x01 "Subsequent fields MUST be zero, and any other
693    /// value is a malformed message", and the same of 0x02. The other three
694    /// codes describe those fields as carrying a real location, so they place
695    /// no requirement on them.
696    pub fn requires_zero_location(self) -> bool {
697        matches!(self, TrackStatusCode::TrackDoesNotExist | TrackStatusCode::NotYetBegun)
698    }
699
700    /// Return the raw u64 value of this status code.
701    pub fn as_u64(self) -> u64 {
702        self as u64
703    }
704}