moqtap_codec/draft09/error_codes.rs
1//! The error, status and termination code registries that MoQ Transport
2//! draft-09 publishes as `Code`/`Reason` tables.
3//!
4//! Draft-09 predates the IANA registries introduced in later drafts. Every
5//! registry here is an inline two-column table with a `Code` column and a
6//! `Reason` column, and the draft assigns no ALLCAPS symbolic names to the code
7//! points. Each variant's doc comment therefore quotes the draft's `Reason`
8//! text verbatim so the mapping from the table to the Rust name is checkable by
9//! eye; where the draft explains a code in prose, that explanation follows.
10//!
11//! # Scope
12//!
13//! Draft-09 has six such tables and all six are transcribed here: Section 3.5
14//! (Termination), Section 7.10 (ANNOUNCE_ERROR), Section 7.16
15//! (SUBSCRIBE_ERROR), Section 7.18 (FETCH_ERROR), Section 7.19 (SUBSCRIBE_DONE)
16//! and Section 7.26 (SUBSCRIBE_ANNOUNCES_ERROR). Draft-09 assigns code points
17//! in two further places, neither of which is a `Code`/`Reason` table and
18//! neither of which belongs here:
19//!
20//! - Section 7.24 assigns TRACK_STATUS Status Codes 0x00 through 0x04 in a
21//! prose list. That registry is closed — the draft says the field "MUST hold
22//! one of the following values. Any other value is a malformed message" —
23//! which is the opposite of the open registries below, so folding it in would
24//! misrepresent it. [`super::message::TrackStatus`] carries the field as a
25//! raw `VarInt`.
26//! - Section 8.1.1.1 assigns Object Status 0x0, 0x1, 0x3, 0x4 and 0x5 (0x2 is
27//! not assigned). That registry is [`super::types::ObjectStatus`], next to
28//! the data-stream code that reads it.
29//!
30//! ANNOUNCE_CANCEL carries an Error Code field with no table of its own, and
31//! Section 7.11 says why: "ANNOUNCE_CANCEL uses the same error codes as
32//! ANNOUNCE_ERROR". So its codes are [`AnnounceErrorCode`], and there is no
33//! separate registry to transcribe.
34//!
35//! # Unrecognised codes
36//!
37//! All six registries here are open: the draft says only that an application
38//! "SHOULD use a relevant error code", so a peer may send a code this draft
39//! does not define. `from_u64` returns `None` for an unrecognised value rather
40//! than failing or widening the enum.
41//!
42//! # These are six separate number spaces
43//!
44//! The registries are deliberately six distinct types because the same number
45//! means different things in each, and the differences are not intuitive:
46//!
47//! - The termination registry is offset by one against the other five.
48//! `Internal Error` is 0x1 in Section 3.5 but 0x0 in all five message-scoped
49//! registries, and `Unauthorized` is 0x2 in Section 3.5 but 0x1 in all five.
50//! Reusing a session code as a message code therefore shifts its meaning by a
51//! whole row rather than producing an obviously wrong value.
52//! - 0x2 is `Timeout` in ANNOUNCE_ERROR, SUBSCRIBE_ERROR, FETCH_ERROR and
53//! SUBSCRIBE_ANNOUNCES_ERROR, but `Track Ended` in SUBSCRIBE_DONE and
54//! `Unauthorized` in the termination registry.
55//! - 0x4 carries five distinct meanings across the six registries:
56//! `Duplicate Track Alias`, `Uninterested`, `Track Does Not Exist` (in both
57//! SUBSCRIBE_ERROR and FETCH_ERROR), `Going Away` and
58//! `Namespace Prefix Unknown`.
59//!
60//! `Unauthorized` also differs in meaning as well as in number: in
61//! [`SessionErrorCode`] it reports a breached agreement, which the
62//! message-scoped registries do not say.
63
64/// Session termination codes, from draft-09 Section 3.5 (Termination).
65///
66/// The draft introduces the table with "The application MAY use any error
67/// message and SHOULD use a relevant code, as defined below". These codes
68/// travel in the QUIC `CONNECTION_CLOSE` frame or the WebTransport
69/// `CLOSE_WEBTRANSPORT_SESSION` capsule.
70///
71/// Section 3.5 assigns 0x0 through 0x6 and then jumps to 0x10 through 0x12 for
72/// the three timeouts; 0x7 through 0xF are unassigned. The gap is the draft's
73/// own, so `GOAWAY Timeout` is 0x10 and not 0x7.
74#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75#[repr(u64)]
76pub enum SessionErrorCode {
77 /// `No Error` — The session is being terminated without an error.
78 NoError = 0x0,
79 /// `Internal Error` — An implementation specific error occurred.
80 InternalError = 0x1,
81 /// `Unauthorized` — The endpoint breached an agreement, which MAY have been
82 /// pre-negotiated by the application.
83 Unauthorized = 0x2,
84 /// `Protocol Violation` — The remote endpoint performed an action that was
85 /// disallowed by the specification.
86 ProtocolViolation = 0x3,
87 /// `Duplicate Track Alias` — The endpoint attempted to use a Track Alias
88 /// that was already in use.
89 DuplicateTrackAlias = 0x4,
90 /// `Parameter Length Mismatch` — the Section 3.5 table assigns this code but
91 /// the list of descriptions that follows the table skips it. Section 7.1
92 /// supplies the meaning: if a receiver understands a parameter type, and the
93 /// parameter length implied by that type does not match the Parameter Length
94 /// field, the receiver MUST terminate the session with this code.
95 ParameterLengthMismatch = 0x5,
96 /// `Too Many Subscribes` — The session was closed because the subscriber
97 /// used a Subscribe ID equal or larger than the current Maximum Subscribe
98 /// ID.
99 TooManySubscribes = 0x6,
100 /// `GOAWAY Timeout` — The session was closed because the peer took too long
101 /// to close the session in response to a GOAWAY (Section 7.3) message. See
102 /// session migration (Section 3.6).
103 GoawayTimeout = 0x10,
104 /// `Control Message Timeout` — The session was closed because the peer took
105 /// too long to respond to a control message.
106 ControlMessageTimeout = 0x11,
107 /// `Data Stream Timeout` — The session was closed because the peer took too
108 /// long to send data expected on an open Data Stream (Section 8). This
109 /// includes fields of a stream header or an object header within a data
110 /// stream. If an endpoint times out waiting for a new object header on an
111 /// open subgroup stream, it MAY send a STOP_SENDING on that stream,
112 /// terminate the subscription, or close the session with an error.
113 DataStreamTimeout = 0x12,
114}
115
116/// ANNOUNCE_ERROR codes, from draft-09 Section 7.10 (ANNOUNCE_ERROR).
117///
118/// The draft introduces the table with "The application SHOULD use a relevant
119/// error code in ANNOUNCE_ERROR, as defined below" and gives no prose beyond the
120/// `Reason` column for any of these codes.
121#[derive(Debug, Clone, Copy, PartialEq, Eq)]
122#[repr(u64)]
123pub enum AnnounceErrorCode {
124 /// `Internal Error`.
125 InternalError = 0x0,
126 /// `Unauthorized`.
127 Unauthorized = 0x1,
128 /// `Timeout`.
129 Timeout = 0x2,
130 /// `Not Supported`.
131 NotSupported = 0x3,
132 /// `Uninterested`.
133 Uninterested = 0x4,
134}
135
136/// SUBSCRIBE_ERROR codes, from draft-09 Section 7.16 (SUBSCRIBE_ERROR).
137///
138/// The draft introduces the table with "The application SHOULD use a relevant
139/// error code in SUBSCRIBE_ERROR, as defined below".
140#[derive(Debug, Clone, Copy, PartialEq, Eq)]
141#[repr(u64)]
142pub enum SubscribeErrorCode {
143 /// `Internal Error`.
144 InternalError = 0x0,
145 /// `Unauthorized`.
146 Unauthorized = 0x1,
147 /// `Timeout`.
148 Timeout = 0x2,
149 /// `Not Supported`.
150 NotSupported = 0x3,
151 /// `Track Does Not Exist`.
152 TrackDoesNotExist = 0x4,
153 /// `Invalid Range` — Section 7.4 adds that if a publisher cannot satisfy
154 /// the requested start or end, or if the end has already been published, it
155 /// SHOULD send a SUBSCRIBE_ERROR with this code.
156 InvalidRange = 0x5,
157 /// `Retry Track Alias` — Section 7.16 adds that the subscriber SHOULD
158 /// re-issue the SUBSCRIBE with the Track Alias carried in the
159 /// SUBSCRIBE_ERROR message instead. If that Track Alias is already in use,
160 /// the subscriber MUST close the connection with a Duplicate Track Alias
161 /// error (Section 3.5).
162 RetryTrackAlias = 0x6,
163}
164
165/// FETCH_ERROR codes, from draft-09 Section 7.18 (FETCH_ERROR).
166///
167/// The draft introduces the table with "The application SHOULD use a relevant
168/// error code in FETCH_ERROR, as defined below" and gives no prose beyond the
169/// `Reason` column for any of these codes. The table stops at `Invalid Range`:
170/// unlike SUBSCRIBE_ERROR, FETCH_ERROR has no `Retry Track Alias` code in this
171/// draft.
172#[derive(Debug, Clone, Copy, PartialEq, Eq)]
173#[repr(u64)]
174pub enum FetchErrorCode {
175 /// `Internal Error`.
176 InternalError = 0x0,
177 /// `Unauthorized`.
178 Unauthorized = 0x1,
179 /// `Timeout`.
180 Timeout = 0x2,
181 /// `Not Supported`.
182 NotSupported = 0x3,
183 /// `Track Does Not Exist`.
184 TrackDoesNotExist = 0x4,
185 /// `Invalid Range`.
186 InvalidRange = 0x5,
187}
188
189/// SUBSCRIBE_DONE status codes, from draft-09 Section 7.19 (SUBSCRIBE_DONE).
190///
191/// The draft introduces the table with "The application SHOULD use a relevant
192/// status code in SUBSCRIBE_DONE, as defined below"; the table's second column
193/// is still headed `Reason`. The Status Code indicates why the subscription
194/// ended, and whether it was an error.
195#[derive(Debug, Clone, Copy, PartialEq, Eq)]
196#[repr(u64)]
197pub enum SubscribeDoneStatusCode {
198 /// `Internal Error`.
199 InternalError = 0x0,
200 /// `Unauthorized`.
201 Unauthorized = 0x1,
202 /// `Track Ended`.
203 TrackEnded = 0x2,
204 /// `Subscription Ended`.
205 SubscriptionEnded = 0x3,
206 /// `Going Away`.
207 GoingAway = 0x4,
208 /// `Expired`.
209 Expired = 0x5,
210 /// `Too Far Behind` — Section 7.1.1.2 adds that if a subscriber exceeds the
211 /// publisher's resource limits by failing to consume objects at a sufficient
212 /// rate, the publisher MAY terminate the subscription with this code.
213 TooFarBehind = 0x6,
214}
215
216/// SUBSCRIBE_ANNOUNCES_ERROR codes, from draft-09 Section 7.26
217/// (SUBSCRIBE_ANNOUNCES_ERROR).
218///
219/// The draft introduces the table with "The application SHOULD use a relevant
220/// error code in SUBSCRIBE_ANNOUNCES_ERROR, as defined below" and gives no prose
221/// beyond the `Reason` column for any of these codes.
222#[derive(Debug, Clone, Copy, PartialEq, Eq)]
223#[repr(u64)]
224pub enum SubscribeAnnouncesErrorCode {
225 /// `Internal Error`.
226 InternalError = 0x0,
227 /// `Unauthorized`.
228 Unauthorized = 0x1,
229 /// `Timeout`.
230 Timeout = 0x2,
231 /// `Not Supported`.
232 NotSupported = 0x3,
233 /// `Namespace Prefix Unknown`.
234 NamespacePrefixUnknown = 0x4,
235}
236
237impl SessionErrorCode {
238 /// Every session termination code draft-09 assigns, in ascending wire order.
239 ///
240 /// This is the set [`Self::from_u64`] accepts, written out so that it can
241 /// be enumerated: nothing can iterate an enum's variants, so a caller that
242 /// wants the registry has to be handed it. Writing it down is also what
243 /// lets a test state its claims about the registry itself rather than about
244 /// the range some sweep happens to reach.
245 pub const ALL: &[SessionErrorCode] = &[
246 SessionErrorCode::NoError,
247 SessionErrorCode::InternalError,
248 SessionErrorCode::Unauthorized,
249 SessionErrorCode::ProtocolViolation,
250 SessionErrorCode::DuplicateTrackAlias,
251 SessionErrorCode::ParameterLengthMismatch,
252 SessionErrorCode::TooManySubscribes,
253 SessionErrorCode::GoawayTimeout,
254 SessionErrorCode::ControlMessageTimeout,
255 SessionErrorCode::DataStreamTimeout,
256 ];
257
258 /// Convert a raw u64 to a `SessionErrorCode`, if draft-09 defines it.
259 pub fn from_u64(v: u64) -> Option<Self> {
260 match v {
261 0x0 => Some(SessionErrorCode::NoError),
262 0x1 => Some(SessionErrorCode::InternalError),
263 0x2 => Some(SessionErrorCode::Unauthorized),
264 0x3 => Some(SessionErrorCode::ProtocolViolation),
265 0x4 => Some(SessionErrorCode::DuplicateTrackAlias),
266 0x5 => Some(SessionErrorCode::ParameterLengthMismatch),
267 0x6 => Some(SessionErrorCode::TooManySubscribes),
268 0x10 => Some(SessionErrorCode::GoawayTimeout),
269 0x11 => Some(SessionErrorCode::ControlMessageTimeout),
270 0x12 => Some(SessionErrorCode::DataStreamTimeout),
271 _ => None,
272 }
273 }
274
275 /// Return the raw u64 value of this error code.
276 pub fn as_u64(self) -> u64 {
277 self as u64
278 }
279}
280
281impl AnnounceErrorCode {
282 /// Every ANNOUNCE_ERROR code draft-09 assigns, in ascending wire order.
283 ///
284 /// This is the set [`Self::from_u64`] accepts, written out so that it can
285 /// be enumerated: nothing can iterate an enum's variants, so a caller that
286 /// wants the registry has to be handed it. Writing it down is also what
287 /// lets a test state its claims about the registry itself rather than about
288 /// the range some sweep happens to reach.
289 pub const ALL: &[AnnounceErrorCode] = &[
290 AnnounceErrorCode::InternalError,
291 AnnounceErrorCode::Unauthorized,
292 AnnounceErrorCode::Timeout,
293 AnnounceErrorCode::NotSupported,
294 AnnounceErrorCode::Uninterested,
295 ];
296
297 /// Convert a raw u64 to an `AnnounceErrorCode`, if draft-09 defines it.
298 pub fn from_u64(v: u64) -> Option<Self> {
299 match v {
300 0x0 => Some(AnnounceErrorCode::InternalError),
301 0x1 => Some(AnnounceErrorCode::Unauthorized),
302 0x2 => Some(AnnounceErrorCode::Timeout),
303 0x3 => Some(AnnounceErrorCode::NotSupported),
304 0x4 => Some(AnnounceErrorCode::Uninterested),
305 _ => None,
306 }
307 }
308
309 /// Return the raw u64 value of this error code.
310 pub fn as_u64(self) -> u64 {
311 self as u64
312 }
313}
314
315impl SubscribeErrorCode {
316 /// Every SUBSCRIBE_ERROR code draft-09 assigns, in ascending wire order.
317 ///
318 /// This is the set [`Self::from_u64`] accepts, written out so that it can
319 /// be enumerated: nothing can iterate an enum's variants, so a caller that
320 /// wants the registry has to be handed it. Writing it down is also what
321 /// lets a test state its claims about the registry itself rather than about
322 /// the range some sweep happens to reach.
323 pub const ALL: &[SubscribeErrorCode] = &[
324 SubscribeErrorCode::InternalError,
325 SubscribeErrorCode::Unauthorized,
326 SubscribeErrorCode::Timeout,
327 SubscribeErrorCode::NotSupported,
328 SubscribeErrorCode::TrackDoesNotExist,
329 SubscribeErrorCode::InvalidRange,
330 SubscribeErrorCode::RetryTrackAlias,
331 ];
332
333 /// Convert a raw u64 to a `SubscribeErrorCode`, if draft-09 defines it.
334 pub fn from_u64(v: u64) -> Option<Self> {
335 match v {
336 0x0 => Some(SubscribeErrorCode::InternalError),
337 0x1 => Some(SubscribeErrorCode::Unauthorized),
338 0x2 => Some(SubscribeErrorCode::Timeout),
339 0x3 => Some(SubscribeErrorCode::NotSupported),
340 0x4 => Some(SubscribeErrorCode::TrackDoesNotExist),
341 0x5 => Some(SubscribeErrorCode::InvalidRange),
342 0x6 => Some(SubscribeErrorCode::RetryTrackAlias),
343 _ => None,
344 }
345 }
346
347 /// Return the raw u64 value of this error code.
348 pub fn as_u64(self) -> u64 {
349 self as u64
350 }
351}
352
353impl FetchErrorCode {
354 /// Every FETCH_ERROR code draft-09 assigns, in ascending wire order.
355 ///
356 /// This is the set [`Self::from_u64`] accepts, written out so that it can
357 /// be enumerated: nothing can iterate an enum's variants, so a caller that
358 /// wants the registry has to be handed it. Writing it down is also what
359 /// lets a test state its claims about the registry itself rather than about
360 /// the range some sweep happens to reach.
361 pub const ALL: &[FetchErrorCode] = &[
362 FetchErrorCode::InternalError,
363 FetchErrorCode::Unauthorized,
364 FetchErrorCode::Timeout,
365 FetchErrorCode::NotSupported,
366 FetchErrorCode::TrackDoesNotExist,
367 FetchErrorCode::InvalidRange,
368 ];
369
370 /// Convert a raw u64 to a `FetchErrorCode`, if draft-09 defines it.
371 pub fn from_u64(v: u64) -> Option<Self> {
372 match v {
373 0x0 => Some(FetchErrorCode::InternalError),
374 0x1 => Some(FetchErrorCode::Unauthorized),
375 0x2 => Some(FetchErrorCode::Timeout),
376 0x3 => Some(FetchErrorCode::NotSupported),
377 0x4 => Some(FetchErrorCode::TrackDoesNotExist),
378 0x5 => Some(FetchErrorCode::InvalidRange),
379 _ => None,
380 }
381 }
382
383 /// Return the raw u64 value of this error code.
384 pub fn as_u64(self) -> u64 {
385 self as u64
386 }
387}
388
389impl SubscribeDoneStatusCode {
390 /// Every SUBSCRIBE_DONE status code draft-09 assigns, in ascending wire order.
391 ///
392 /// This is the set [`Self::from_u64`] accepts, written out so that it can
393 /// be enumerated: nothing can iterate an enum's variants, so a caller that
394 /// wants the registry has to be handed it. Writing it down is also what
395 /// lets a test state its claims about the registry itself rather than about
396 /// the range some sweep happens to reach.
397 pub const ALL: &[SubscribeDoneStatusCode] = &[
398 SubscribeDoneStatusCode::InternalError,
399 SubscribeDoneStatusCode::Unauthorized,
400 SubscribeDoneStatusCode::TrackEnded,
401 SubscribeDoneStatusCode::SubscriptionEnded,
402 SubscribeDoneStatusCode::GoingAway,
403 SubscribeDoneStatusCode::Expired,
404 SubscribeDoneStatusCode::TooFarBehind,
405 ];
406
407 /// Convert a raw u64 to a `SubscribeDoneStatusCode`, if draft-09 defines it.
408 pub fn from_u64(v: u64) -> Option<Self> {
409 match v {
410 0x0 => Some(SubscribeDoneStatusCode::InternalError),
411 0x1 => Some(SubscribeDoneStatusCode::Unauthorized),
412 0x2 => Some(SubscribeDoneStatusCode::TrackEnded),
413 0x3 => Some(SubscribeDoneStatusCode::SubscriptionEnded),
414 0x4 => Some(SubscribeDoneStatusCode::GoingAway),
415 0x5 => Some(SubscribeDoneStatusCode::Expired),
416 0x6 => Some(SubscribeDoneStatusCode::TooFarBehind),
417 _ => None,
418 }
419 }
420
421 /// Return the raw u64 value of this status code.
422 pub fn as_u64(self) -> u64 {
423 self as u64
424 }
425}
426
427impl SubscribeAnnouncesErrorCode {
428 /// Every SUBSCRIBE_ANNOUNCES_ERROR code draft-09 assigns, in ascending wire order.
429 ///
430 /// This is the set [`Self::from_u64`] accepts, written out so that it can
431 /// be enumerated: nothing can iterate an enum's variants, so a caller that
432 /// wants the registry has to be handed it. Writing it down is also what
433 /// lets a test state its claims about the registry itself rather than about
434 /// the range some sweep happens to reach.
435 pub const ALL: &[SubscribeAnnouncesErrorCode] = &[
436 SubscribeAnnouncesErrorCode::InternalError,
437 SubscribeAnnouncesErrorCode::Unauthorized,
438 SubscribeAnnouncesErrorCode::Timeout,
439 SubscribeAnnouncesErrorCode::NotSupported,
440 SubscribeAnnouncesErrorCode::NamespacePrefixUnknown,
441 ];
442
443 /// Convert a raw u64 to a `SubscribeAnnouncesErrorCode`, if draft-09 defines
444 /// it.
445 pub fn from_u64(v: u64) -> Option<Self> {
446 match v {
447 0x0 => Some(SubscribeAnnouncesErrorCode::InternalError),
448 0x1 => Some(SubscribeAnnouncesErrorCode::Unauthorized),
449 0x2 => Some(SubscribeAnnouncesErrorCode::Timeout),
450 0x3 => Some(SubscribeAnnouncesErrorCode::NotSupported),
451 0x4 => Some(SubscribeAnnouncesErrorCode::NamespacePrefixUnknown),
452 _ => None,
453 }
454 }
455
456 /// Return the raw u64 value of this error code.
457 pub fn as_u64(self) -> u64 {
458 self as u64
459 }
460}
461
462#[cfg(test)]
463mod tests {
464 use super::*;
465
466 #[test]
467 fn session_error_code_roundtrip() {
468 for code in [
469 SessionErrorCode::NoError,
470 SessionErrorCode::InternalError,
471 SessionErrorCode::Unauthorized,
472 SessionErrorCode::ProtocolViolation,
473 SessionErrorCode::DuplicateTrackAlias,
474 SessionErrorCode::ParameterLengthMismatch,
475 SessionErrorCode::TooManySubscribes,
476 SessionErrorCode::GoawayTimeout,
477 SessionErrorCode::ControlMessageTimeout,
478 SessionErrorCode::DataStreamTimeout,
479 ] {
480 assert_eq!(SessionErrorCode::from_u64(code.as_u64()), Some(code));
481 }
482 }
483
484 #[test]
485 fn unknown_codes_are_none() {
486 // 0x7..=0xF are unassigned in draft-09's termination table, and the
487 // table stops at 0x12. Assert over the whole gap rather than a sample.
488 for code in 0x7..=0xF {
489 assert_eq!(SessionErrorCode::from_u64(code), None, "0x{code:x}");
490 }
491 assert_eq!(SessionErrorCode::from_u64(0x13), None);
492 assert_eq!(AnnounceErrorCode::from_u64(0x5), None);
493 assert_eq!(SubscribeErrorCode::from_u64(0x7), None);
494 assert_eq!(FetchErrorCode::from_u64(0x6), None);
495 assert_eq!(SubscribeDoneStatusCode::from_u64(0x7), None);
496 assert_eq!(SubscribeAnnouncesErrorCode::from_u64(0x5), None);
497 assert_eq!(SessionErrorCode::from_u64(u64::MAX), None);
498 }
499
500 #[test]
501 fn fetch_error_has_no_retry_track_alias() {
502 // draft-09 gives SUBSCRIBE_ERROR 0x6 but stops FETCH_ERROR at 0x5.
503 assert_eq!(SubscribeErrorCode::from_u64(0x6), Some(SubscribeErrorCode::RetryTrackAlias));
504 assert_eq!(FetchErrorCode::from_u64(0x6), None);
505 }
506}
507
508/// TRACK_STATUS Status Code values (draft-09, Section 7.24).
509///
510/// The draft defines these as a prose list rather than as a `Code`/`Reason`
511/// table, so they are named from the prose. It is stricter about this field
512/// than about the error registries above: the Status Code "MUST hold one of the
513/// following values" and "Any other value in the Status Code field is a
514/// malformed message", so [`TrackStatusCode::from_u64`] answering `None` is a
515/// decode failure rather than a merely unrecognised code.
516#[derive(Debug, Clone, Copy, PartialEq, Eq)]
517#[repr(u64)]
518pub enum TrackStatusCode {
519 /// The track is in progress, and subsequent fields contain the highest
520 /// group and object ID for that track.
521 InProgress = 0x00,
522 /// The track does not exist. Subsequent fields MUST be zero, and any other
523 /// value is a malformed message.
524 TrackDoesNotExist = 0x01,
525 /// The track has not yet begun. Subsequent fields MUST be zero, and any
526 /// other value is a malformed message.
527 NotYetBegun = 0x02,
528 /// The track has finished, so there is no live edge. Subsequent fields
529 /// contain the highest group and object ID known.
530 Finished = 0x03,
531 /// The publisher is a relay that cannot obtain the current track status
532 /// from upstream. Subsequent fields contain the largest group and object
533 /// ID known.
534 RelayStatusUnavailable = 0x04,
535}
536
537impl TrackStatusCode {
538 /// Convert a raw u64 to a `TrackStatusCode`, if this draft assigns it.
539 pub fn from_u64(v: u64) -> Option<Self> {
540 match v {
541 0x00 => Some(TrackStatusCode::InProgress),
542 0x01 => Some(TrackStatusCode::TrackDoesNotExist),
543 0x02 => Some(TrackStatusCode::NotYetBegun),
544 0x03 => Some(TrackStatusCode::Finished),
545 0x04 => Some(TrackStatusCode::RelayStatusUnavailable),
546 _ => None,
547 }
548 }
549
550 /// Whether this code requires the fields after it to be zero.
551 ///
552 /// Section 7.24 says of 0x01 "Subsequent fields MUST be zero, and any other
553 /// value is a malformed message", and the same of 0x02. The other three
554 /// codes describe those fields as carrying a real location, so they place
555 /// no requirement on them.
556 pub fn requires_zero_location(self) -> bool {
557 matches!(self, TrackStatusCode::TrackDoesNotExist | TrackStatusCode::NotYetBegun)
558 }
559
560 /// Return the raw u64 value of this status code.
561 pub fn as_u64(self) -> u64 {
562 self as u64
563 }
564}