Skip to main content

moqtap_codec/draft19/
message.rs

1//! Draft-19 control message encoding and decoding.
2//!
3//! Key differences from draft-18:
4//! - `Request ID` field removed from GOAWAY entirely; the control-stream and
5//!   request-stream forms are now identical.
6//! - New Range Filter parameters (length-prefixed): SUBGROUP_FILTER (0x25),
7//!   OBJECTID_FILTER (0x26), PRIORITY_FILTER (0x27), OBJECT_PROPERTY_FILTER
8//!   (0x28) and TRACK_PROPERTY_FILTER (0x29).
9//! - New Setup Options MAX_FILTER_RANGES (0x06) and MAX_REQUEST_UPDATES (0x08);
10//!   both are even KVP types carrying a varint value.
11//! - GROUP_ORDER (0x22) moves from PUBLISH_OK to SUBSCRIBE_TRACKS (the wire
12//!   encoding of the parameter is unchanged).
13//! - PUBLISH_BLOCKED renamed to PUBLISH_SKIPPED (still type 0x0F; wire
14//!   identical).
15//! - SUBSCRIPTION_FILTER renamed to LOCATION_FILTER (still parameter 0x21).
16//! - REQUEST_ERROR adds CONFLICTING_FILTERS (0x35) and INVALID_FILTER (0x36);
17//!   DUPLICATE_SUBSCRIPTION (0x19) is removed.
18
19pub use crate::error::{
20    CodecError, MAX_GOAWAY_URI_LENGTH, MAX_MESSAGE_LENGTH, MAX_NAMESPACE_TUPLE_SIZE,
21    MAX_REASON_PHRASE_LENGTH,
22};
23use crate::kvp::{KeyValuePair, KvpValue};
24use crate::types::*;
25use crate::varint::VarInt;
26use bytes::{Buf, BufMut};
27
28// ============================================================
29// Parameter encoding helpers for draft-18
30// ============================================================
31
32/// How a parameter value is encoded on the wire.
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34enum ParamEncoding {
35    /// Bare varint.
36    Varint,
37    /// Single byte (uint8).
38    Uint8,
39    /// Length-prefixed bytes.
40    LengthPrefixed,
41}
42
43fn param_encoding(key: u64) -> Option<ParamEncoding> {
44    match key {
45        // 0x02 = OBJECT_DELIVERY_TIMEOUT (renamed from DELIVERY_TIMEOUT)
46        // 0x04 = MAX_CACHE_DURATION
47        // 0x06 = SUBGROUP_DELIVERY_TIMEOUT (new in draft-18)
48        // 0x08 = EXPIRES
49        // 0x0A = FILL_TIMEOUT (new in draft-18, FETCH only)
50        // 0x32 = NEW_GROUP_REQUEST
51        0x02 | 0x04 | 0x06 | 0x08 | 0x0A | 0x32 => Some(ParamEncoding::Varint),
52        // 0x10 = FORWARD, 0x20 = SUBSCRIBER_PRIORITY, 0x22 = GROUP_ORDER
53        0x10 | 0x20 | 0x22 => Some(ParamEncoding::Uint8),
54        // 0x03 = AUTHORIZATION_TOKEN
55        // 0x09 = LARGEST_OBJECT
56        // 0x21 = LOCATION_FILTER (renamed from SUBSCRIPTION_FILTER)
57        // 0x25 = SUBGROUP_FILTER, 0x26 = OBJECTID_FILTER, 0x27 = PRIORITY_FILTER,
58        // 0x28 = OBJECT_PROPERTY_FILTER, 0x29 = TRACK_PROPERTY_FILTER
59        //        (Range Filters, new in draft-19)
60        // 0x34 = TRACK_NAMESPACE_PREFIX
61        0x03 | 0x09 | 0x21 | 0x25 | 0x26 | 0x27 | 0x28 | 0x29 | 0x34 => {
62            Some(ParamEncoding::LengthPrefixed)
63        }
64        _ => None,
65    }
66}
67
68/// Decode a count-prefixed list of parameters with delta-encoded types.
69fn decode_parameters(buf: &mut impl Buf) -> Result<Vec<KeyValuePair>, CodecError> {
70    let count = VarInt::decode(buf)?.into_inner() as usize;
71    let mut params = Vec::with_capacity(count);
72    let mut prev_key: u64 = 0;
73
74    for _ in 0..count {
75        let delta = VarInt::decode(buf)?.into_inner();
76        let abs_key = prev_key + delta;
77        prev_key = abs_key;
78
79        let encoding = param_encoding(abs_key).ok_or(CodecError::InvalidField)?;
80
81        let value = match encoding {
82            ParamEncoding::Varint => {
83                let v = VarInt::decode(buf)?;
84                KvpValue::Varint(v)
85            }
86            ParamEncoding::Uint8 => {
87                if buf.remaining() < 1 {
88                    return Err(CodecError::UnexpectedEnd);
89                }
90                let byte = buf.get_u8();
91                KvpValue::Varint(VarInt::from_u64(byte as u64).unwrap())
92            }
93            ParamEncoding::LengthPrefixed => {
94                let len = VarInt::decode(buf)?.into_inner() as usize;
95                let data = read_bytes(buf, len)?;
96                KvpValue::Bytes(data)
97            }
98        };
99
100        params.push(KeyValuePair { key: VarInt::from_u64(abs_key).unwrap(), value });
101    }
102    Ok(params)
103}
104
105/// Encode a count-prefixed list of parameters with delta-encoded types.
106fn encode_parameters(params: &[KeyValuePair], buf: &mut impl BufMut) {
107    VarInt::from_usize(params.len()).encode(buf);
108    let mut prev_key: u64 = 0;
109
110    for p in params {
111        let abs_key = p.key.into_inner();
112        let delta = abs_key - prev_key;
113        prev_key = abs_key;
114        VarInt::from_u64(delta).unwrap().encode(buf);
115
116        let encoding = param_encoding(abs_key);
117        match (&p.value, encoding) {
118            (KvpValue::Varint(v), Some(ParamEncoding::Varint)) => {
119                v.encode(buf);
120            }
121            (KvpValue::Varint(v), Some(ParamEncoding::Uint8)) => {
122                buf.put_u8(v.into_inner() as u8);
123            }
124            (KvpValue::Bytes(b), Some(ParamEncoding::LengthPrefixed)) => {
125                VarInt::from_usize(b.len()).encode(buf);
126                buf.put_slice(b);
127            }
128            _ => {
129                // Fallback: encode as KVP even/odd
130                match &p.value {
131                    KvpValue::Varint(v) => v.encode(buf),
132                    KvpValue::Bytes(b) => {
133                        VarInt::from_usize(b.len()).encode(buf);
134                        buf.put_slice(b);
135                    }
136                }
137            }
138        }
139    }
140}
141
142/// Decode delta-encoded KVPs with even/odd convention (for setup options
143/// and track properties). Read until buffer is exhausted.
144fn decode_kvp_delta(buf: &mut impl Buf) -> Result<Vec<KeyValuePair>, CodecError> {
145    let mut pairs = Vec::new();
146    let mut prev_key: u64 = 0;
147
148    while buf.has_remaining() {
149        let delta = VarInt::decode(buf)?.into_inner();
150        let abs_key = prev_key + delta;
151        prev_key = abs_key;
152
153        let value = if abs_key % 2 == 0 {
154            let v = VarInt::decode(buf)?;
155            KvpValue::Varint(v)
156        } else {
157            let len = VarInt::decode(buf)?.into_inner() as usize;
158            let data = read_bytes(buf, len)?;
159            KvpValue::Bytes(data)
160        };
161
162        pairs.push(KeyValuePair { key: VarInt::from_u64(abs_key).unwrap(), value });
163    }
164    Ok(pairs)
165}
166
167/// Encode delta-encoded KVPs with even/odd convention.
168fn encode_kvp_delta(pairs: &[KeyValuePair], buf: &mut impl BufMut) {
169    let mut prev_key: u64 = 0;
170    for p in pairs {
171        let abs_key = p.key.into_inner();
172        let delta = abs_key - prev_key;
173        prev_key = abs_key;
174        VarInt::from_u64(delta).unwrap().encode(buf);
175        match &p.value {
176            KvpValue::Varint(v) => v.encode(buf),
177            KvpValue::Bytes(b) => {
178                VarInt::from_usize(b.len()).encode(buf);
179                buf.put_slice(b);
180            }
181        }
182    }
183}
184
185// ============================================================
186// Message Types
187// ============================================================
188
189#[derive(Debug, Clone, Copy, PartialEq, Eq)]
190#[repr(u64)]
191pub enum MessageType {
192    RequestUpdate = 0x02,
193    Subscribe = 0x03,
194    SubscribeOk = 0x04,
195    RequestError = 0x05,
196    PublishNamespace = 0x06,
197    /// REQUEST_OK (0x07). PUBLISH_OK is now an alias of this type.
198    RequestOk = 0x07,
199    Namespace = 0x08,
200    PublishDone = 0x0B,
201    TrackStatus = 0x0D,
202    NamespaceDone = 0x0E,
203    PublishSkipped = 0x0F,
204    GoAway = 0x10,
205    Fetch = 0x16,
206    FetchOk = 0x18,
207    Publish = 0x1D,
208    /// SUBSCRIBE_NAMESPACE (renumbered to 0x50 in draft-18).
209    SubscribeNamespace = 0x50,
210    /// SUBSCRIBE_TRACKS (new message in draft-18).
211    SubscribeTracks = 0x51,
212    Setup = 0x2F00,
213}
214
215impl MessageType {
216    pub fn from_id(id: u64) -> Option<Self> {
217        match id {
218            0x02 => Some(MessageType::RequestUpdate),
219            0x03 => Some(MessageType::Subscribe),
220            0x04 => Some(MessageType::SubscribeOk),
221            0x05 => Some(MessageType::RequestError),
222            0x06 => Some(MessageType::PublishNamespace),
223            0x07 => Some(MessageType::RequestOk),
224            0x08 => Some(MessageType::Namespace),
225            0x0B => Some(MessageType::PublishDone),
226            0x0D => Some(MessageType::TrackStatus),
227            0x0E => Some(MessageType::NamespaceDone),
228            0x0F => Some(MessageType::PublishSkipped),
229            0x10 => Some(MessageType::GoAway),
230            0x16 => Some(MessageType::Fetch),
231            0x18 => Some(MessageType::FetchOk),
232            0x1D => Some(MessageType::Publish),
233            0x50 => Some(MessageType::SubscribeNamespace),
234            0x51 => Some(MessageType::SubscribeTracks),
235            0x2F00 => Some(MessageType::Setup),
236            _ => None,
237        }
238    }
239
240    pub fn id(&self) -> u64 {
241        *self as u64
242    }
243}
244
245// ============================================================
246// Session Lifecycle Messages
247// ============================================================
248
249/// Unified SETUP (0x2F00).
250#[derive(Debug, Clone, PartialEq, Eq)]
251pub struct Setup {
252    pub options: Vec<KeyValuePair>,
253}
254
255/// GOAWAY (0x10). In draft-19 the Request ID field is removed, so the
256/// control-stream and request-stream forms are identical on the wire.
257#[derive(Debug, Clone, PartialEq, Eq)]
258pub struct GoAway {
259    pub new_session_uri: Vec<u8>,
260    pub timeout: VarInt,
261}
262
263// ============================================================
264// Consolidated Response Messages
265// ============================================================
266
267/// REQUEST_OK (0x07). Used as a generic OK response and as the alias for
268/// PUBLISH_OK / REQUEST_UPDATE_OK / TRACK_STATUS_OK / SUBSCRIBE_NAMESPACE_OK
269/// / PUBLISH_NAMESPACE_OK.
270///
271/// `track_properties` is only populated for TRACK_STATUS_OK; for every
272/// other shape it MUST be empty (length implicit from the message length).
273#[derive(Debug, Clone, PartialEq, Eq)]
274pub struct RequestOk {
275    pub parameters: Vec<KeyValuePair>,
276    pub track_properties: Vec<KeyValuePair>,
277}
278
279/// Optional Redirect structure carried in REQUEST_ERROR with code 0x34.
280#[derive(Debug, Clone, PartialEq, Eq)]
281pub struct Redirect {
282    pub connect_uri: Vec<u8>,
283    pub track_namespace: TrackNamespace,
284    pub track_name: Vec<u8>,
285}
286
287/// REQUEST_ERROR (0x05). Adds an optional Redirect structure when
288/// `error_code` is REDIRECT (0x34).
289#[derive(Debug, Clone, PartialEq, Eq)]
290pub struct RequestError {
291    pub error_code: VarInt,
292    pub retry_interval: VarInt,
293    pub reason_phrase: Vec<u8>,
294    pub redirect: Option<Redirect>,
295}
296
297/// REQUEST_ERROR error codes with dedicated meaning.
298///
299/// Note: DUPLICATE_SUBSCRIPTION (0x19) is removed in draft-19, as multiple
300/// concurrent subscriptions per Track are now allowed.
301pub mod request_error_codes {
302    /// A Mandatory Track Property the receiver does not understand.
303    pub const UNSUPPORTED_EXTENSION: u64 = 0x33;
304    /// Response carries a [`super::Redirect`] structure.
305    pub const REDIRECT: u64 = 0x34;
306    /// New in draft-19: SUBSCRIBE_TRACKS filter parameters conflict among too
307    /// many subscribers to aggregate the subscription upstream.
308    pub const CONFLICTING_FILTERS: u64 = 0x35;
309    /// New in draft-19: a Range Filter parameter is invalid or exceeds
310    /// MAX_FILTER_RANGES.
311    pub const INVALID_FILTER: u64 = 0x36;
312}
313
314// ============================================================
315// Subscribe Messages
316// ============================================================
317
318#[derive(Debug, Clone, PartialEq, Eq)]
319pub struct Subscribe {
320    pub request_id: VarInt,
321    pub track_namespace: TrackNamespace,
322    pub track_name: Vec<u8>,
323    pub parameters: Vec<KeyValuePair>,
324}
325
326/// SUBSCRIBE_OK (0x04).
327#[derive(Debug, Clone, PartialEq, Eq)]
328pub struct SubscribeOk {
329    pub track_alias: VarInt,
330    pub parameters: Vec<KeyValuePair>,
331    pub track_properties: Vec<KeyValuePair>,
332}
333
334#[derive(Debug, Clone, PartialEq, Eq)]
335pub struct RequestUpdate {
336    pub request_id: VarInt,
337    pub parameters: Vec<KeyValuePair>,
338}
339
340// ============================================================
341// Publish Messages
342// ============================================================
343
344#[derive(Debug, Clone, PartialEq, Eq)]
345pub struct Publish {
346    pub request_id: VarInt,
347    pub track_namespace: TrackNamespace,
348    pub track_name: Vec<u8>,
349    pub track_alias: VarInt,
350    pub parameters: Vec<KeyValuePair>,
351    pub track_properties: Vec<KeyValuePair>,
352}
353
354/// PUBLISH_DONE (0x0B). Status codes 0x5/0x6 are swapped vs draft-17.
355#[derive(Debug, Clone, PartialEq, Eq)]
356pub struct PublishDone {
357    pub status_code: VarInt,
358    pub stream_count: VarInt,
359    pub reason_phrase: Vec<u8>,
360}
361
362/// Numeric values for the [`PublishDone::status_code`] field.
363pub mod publish_done_codes {
364    /// Draft-18: TOO_FAR_BEHIND is 0x05 (was 0x06 in draft-17).
365    pub const TOO_FAR_BEHIND: u64 = 0x05;
366    /// Draft-18: EXPIRED is 0x06 (was 0x05 in draft-17).
367    pub const EXPIRED: u64 = 0x06;
368}
369
370// ============================================================
371// Publish Namespace Messages
372// ============================================================
373
374#[derive(Debug, Clone, PartialEq, Eq)]
375pub struct PublishNamespace {
376    pub request_id: VarInt,
377    pub track_namespace: TrackNamespace,
378    pub parameters: Vec<KeyValuePair>,
379}
380
381// ============================================================
382// Namespace Messages
383// ============================================================
384
385#[derive(Debug, Clone, PartialEq, Eq)]
386pub struct Namespace {
387    pub namespace_suffix: TrackNamespace,
388}
389
390#[derive(Debug, Clone, PartialEq, Eq)]
391pub struct NamespaceDone {
392    pub namespace_suffix: TrackNamespace,
393}
394
395// ============================================================
396// Subscribe Namespace / Tracks Messages
397// ============================================================
398
399/// SUBSCRIBE_NAMESPACE (0x50). Subscribes to NAMESPACE / NAMESPACE_DONE
400/// advertisements for namespaces matching `namespace_prefix`. The
401/// `subscribe_options` byte from draft-17 is removed; namespace subscriptions
402/// only produce NAMESPACE / NAMESPACE_DONE.
403#[derive(Debug, Clone, PartialEq, Eq)]
404pub struct SubscribeNamespace {
405    pub request_id: VarInt,
406    pub namespace_prefix: TrackNamespace,
407    pub parameters: Vec<KeyValuePair>,
408}
409
410/// SUBSCRIBE_TRACKS (0x51, new in draft-18). Subscribes to PUBLISH messages
411/// for tracks whose namespace matches `namespace_prefix`. Carries the
412/// FORWARD parameter (which previously lived on SUBSCRIBE_NAMESPACE).
413#[derive(Debug, Clone, PartialEq, Eq)]
414pub struct SubscribeTracks {
415    pub request_id: VarInt,
416    pub namespace_prefix: TrackNamespace,
417    pub parameters: Vec<KeyValuePair>,
418}
419
420// ============================================================
421// Track Status Messages
422// ============================================================
423
424#[derive(Debug, Clone, PartialEq, Eq)]
425pub struct TrackStatus {
426    pub request_id: VarInt,
427    pub track_namespace: TrackNamespace,
428    pub track_name: Vec<u8>,
429    pub parameters: Vec<KeyValuePair>,
430}
431
432// ============================================================
433// Fetch Messages
434// ============================================================
435
436#[derive(Debug, Clone, Copy, PartialEq, Eq)]
437#[repr(u64)]
438pub enum FetchType {
439    Standalone = 1,
440    RelativeJoining = 2,
441    AbsoluteJoining = 3,
442}
443
444impl FetchType {
445    pub fn from_u64(v: u64) -> Option<Self> {
446        match v {
447            1 => Some(FetchType::Standalone),
448            2 => Some(FetchType::RelativeJoining),
449            3 => Some(FetchType::AbsoluteJoining),
450            _ => None,
451        }
452    }
453}
454
455#[derive(Debug, Clone, PartialEq, Eq)]
456pub struct Fetch {
457    pub request_id: VarInt,
458    pub fetch_type: FetchType,
459    pub fetch_payload: FetchPayload,
460    pub parameters: Vec<KeyValuePair>,
461}
462
463#[derive(Debug, Clone, PartialEq, Eq)]
464pub enum FetchPayload {
465    Standalone {
466        track_namespace: TrackNamespace,
467        track_name: Vec<u8>,
468        start_group: VarInt,
469        start_object: VarInt,
470        end_group: VarInt,
471        end_object: VarInt,
472    },
473    Joining {
474        joining_request_id: VarInt,
475        joining_start: VarInt,
476    },
477}
478
479/// FETCH_OK (0x18). `end_of_track` is uint8.
480#[derive(Debug, Clone, PartialEq, Eq)]
481pub struct FetchOk {
482    pub end_of_track: u8,
483    pub end_group: VarInt,
484    pub end_object: VarInt,
485    pub parameters: Vec<KeyValuePair>,
486    pub track_properties: Vec<KeyValuePair>,
487}
488
489// ============================================================
490// Publish Skipped
491// ============================================================
492
493/// PUBLISH_SKIPPED (0x0F, renamed from PUBLISH_BLOCKED in draft-19; wire
494/// layout is unchanged).
495#[derive(Debug, Clone, PartialEq, Eq)]
496pub struct PublishSkipped {
497    pub namespace_suffix: TrackNamespace,
498    pub track_name: Vec<u8>,
499}
500
501// ============================================================
502// Unified Message Enum
503// ============================================================
504
505#[derive(Debug, Clone, PartialEq, Eq)]
506pub enum ControlMessage {
507    Setup(Setup),
508    GoAway(GoAway),
509    RequestOk(RequestOk),
510    RequestError(RequestError),
511    Subscribe(Subscribe),
512    SubscribeOk(SubscribeOk),
513    RequestUpdate(RequestUpdate),
514    Publish(Publish),
515    PublishDone(PublishDone),
516    PublishNamespace(PublishNamespace),
517    Namespace(Namespace),
518    NamespaceDone(NamespaceDone),
519    SubscribeNamespace(SubscribeNamespace),
520    SubscribeTracks(SubscribeTracks),
521    TrackStatus(TrackStatus),
522    Fetch(Fetch),
523    FetchOk(FetchOk),
524    PublishSkipped(PublishSkipped),
525}
526
527impl ControlMessage {
528    pub fn encode(&self, buf: &mut impl BufMut) -> Result<(), CodecError> {
529        let mut payload = Vec::with_capacity(256);
530        self.encode_payload(&mut payload)?;
531
532        if payload.len() > MAX_MESSAGE_LENGTH {
533            return Err(CodecError::MessageTooLong(payload.len()));
534        }
535
536        let msg_type = self.message_type();
537        VarInt::from_usize(msg_type.id() as usize).encode(buf);
538        // Draft-18: 16-bit length (big-endian)
539        buf.put_u16(payload.len() as u16);
540        buf.put_slice(&payload);
541        Ok(())
542    }
543
544    pub fn decode(buf: &mut impl Buf) -> Result<Self, CodecError> {
545        let type_id = VarInt::decode(buf)?.into_inner();
546        let msg_type =
547            MessageType::from_id(type_id).ok_or(CodecError::UnknownMessageType(type_id))?;
548        // Draft-18: 16-bit length (big-endian)
549        if buf.remaining() < 2 {
550            return Err(CodecError::UnexpectedEnd);
551        }
552        let payload_len = buf.get_u16() as usize;
553        if buf.remaining() < payload_len {
554            return Err(CodecError::UnexpectedEnd);
555        }
556        let payload_bytes = buf.copy_to_bytes(payload_len);
557        let mut payload = &payload_bytes[..];
558        Self::decode_payload(msg_type, &mut payload)
559    }
560
561    fn encode_payload(&self, buf: &mut impl BufMut) -> Result<(), CodecError> {
562        match self {
563            ControlMessage::Setup(m) => {
564                encode_kvp_delta(&m.options, buf);
565            }
566            ControlMessage::GoAway(m) => {
567                if m.new_session_uri.len() > MAX_GOAWAY_URI_LENGTH {
568                    return Err(CodecError::GoAwayUriTooLong);
569                }
570                VarInt::from_usize(m.new_session_uri.len()).encode(buf);
571                buf.put_slice(&m.new_session_uri);
572                m.timeout.encode(buf);
573            }
574            ControlMessage::RequestOk(m) => {
575                encode_parameters(&m.parameters, buf);
576                encode_kvp_delta(&m.track_properties, buf);
577            }
578            ControlMessage::RequestError(m) => {
579                if m.reason_phrase.len() > MAX_REASON_PHRASE_LENGTH {
580                    return Err(CodecError::ReasonPhraseTooLong);
581                }
582                m.error_code.encode(buf);
583                m.retry_interval.encode(buf);
584                VarInt::from_usize(m.reason_phrase.len()).encode(buf);
585                buf.put_slice(&m.reason_phrase);
586                if let Some(r) = &m.redirect {
587                    VarInt::from_usize(r.connect_uri.len()).encode(buf);
588                    buf.put_slice(&r.connect_uri);
589                    r.track_namespace.encode(buf);
590                    VarInt::from_usize(r.track_name.len()).encode(buf);
591                    buf.put_slice(&r.track_name);
592                }
593            }
594            ControlMessage::Subscribe(m) => {
595                m.request_id.encode(buf);
596                m.track_namespace.encode(buf);
597                VarInt::from_usize(m.track_name.len()).encode(buf);
598                buf.put_slice(&m.track_name);
599                encode_parameters(&m.parameters, buf);
600            }
601            ControlMessage::SubscribeOk(m) => {
602                m.track_alias.encode(buf);
603                encode_parameters(&m.parameters, buf);
604                encode_kvp_delta(&m.track_properties, buf);
605            }
606            ControlMessage::RequestUpdate(m) => {
607                m.request_id.encode(buf);
608                encode_parameters(&m.parameters, buf);
609            }
610            ControlMessage::Publish(m) => {
611                m.request_id.encode(buf);
612                m.track_namespace.encode(buf);
613                VarInt::from_usize(m.track_name.len()).encode(buf);
614                buf.put_slice(&m.track_name);
615                m.track_alias.encode(buf);
616                encode_parameters(&m.parameters, buf);
617                encode_kvp_delta(&m.track_properties, buf);
618            }
619            ControlMessage::PublishDone(m) => {
620                if m.reason_phrase.len() > MAX_REASON_PHRASE_LENGTH {
621                    return Err(CodecError::ReasonPhraseTooLong);
622                }
623                m.status_code.encode(buf);
624                m.stream_count.encode(buf);
625                VarInt::from_usize(m.reason_phrase.len()).encode(buf);
626                buf.put_slice(&m.reason_phrase);
627            }
628            ControlMessage::PublishNamespace(m) => {
629                m.request_id.encode(buf);
630                m.track_namespace.encode(buf);
631                encode_parameters(&m.parameters, buf);
632            }
633            ControlMessage::Namespace(m) => {
634                m.namespace_suffix.encode(buf);
635            }
636            ControlMessage::NamespaceDone(m) => {
637                m.namespace_suffix.encode(buf);
638            }
639            ControlMessage::SubscribeNamespace(m) => {
640                m.request_id.encode(buf);
641                m.namespace_prefix.encode(buf);
642                encode_parameters(&m.parameters, buf);
643            }
644            ControlMessage::SubscribeTracks(m) => {
645                m.request_id.encode(buf);
646                m.namespace_prefix.encode(buf);
647                encode_parameters(&m.parameters, buf);
648            }
649            ControlMessage::TrackStatus(m) => {
650                m.request_id.encode(buf);
651                m.track_namespace.encode(buf);
652                VarInt::from_usize(m.track_name.len()).encode(buf);
653                buf.put_slice(&m.track_name);
654                encode_parameters(&m.parameters, buf);
655            }
656            ControlMessage::Fetch(m) => {
657                m.request_id.encode(buf);
658                VarInt::from_usize(m.fetch_type as usize).encode(buf);
659                match &m.fetch_payload {
660                    FetchPayload::Standalone {
661                        track_namespace,
662                        track_name,
663                        start_group,
664                        start_object,
665                        end_group,
666                        end_object,
667                    } => {
668                        track_namespace.encode(buf);
669                        VarInt::from_usize(track_name.len()).encode(buf);
670                        buf.put_slice(track_name);
671                        start_group.encode(buf);
672                        start_object.encode(buf);
673                        end_group.encode(buf);
674                        end_object.encode(buf);
675                    }
676                    FetchPayload::Joining { joining_request_id, joining_start } => {
677                        joining_request_id.encode(buf);
678                        joining_start.encode(buf);
679                    }
680                }
681                encode_parameters(&m.parameters, buf);
682            }
683            ControlMessage::FetchOk(m) => {
684                buf.put_u8(m.end_of_track);
685                m.end_group.encode(buf);
686                m.end_object.encode(buf);
687                encode_parameters(&m.parameters, buf);
688                encode_kvp_delta(&m.track_properties, buf);
689            }
690            ControlMessage::PublishSkipped(m) => {
691                m.namespace_suffix.encode(buf);
692                VarInt::from_usize(m.track_name.len()).encode(buf);
693                buf.put_slice(&m.track_name);
694            }
695        }
696        Ok(())
697    }
698
699    fn decode_payload(msg_type: MessageType, buf: &mut impl Buf) -> Result<Self, CodecError> {
700        match msg_type {
701            MessageType::Setup => {
702                let options = decode_kvp_delta(buf)?;
703                Ok(ControlMessage::Setup(Setup { options }))
704            }
705            MessageType::GoAway => {
706                let uri_len = VarInt::decode(buf)?.into_inner() as usize;
707                let uri = read_bytes(buf, uri_len)?;
708                let timeout = VarInt::decode(buf)?;
709                Ok(ControlMessage::GoAway(GoAway { new_session_uri: uri, timeout }))
710            }
711            MessageType::RequestOk => {
712                let parameters = decode_parameters(buf)?;
713                let track_properties = decode_kvp_delta(buf)?;
714                Ok(ControlMessage::RequestOk(RequestOk { parameters, track_properties }))
715            }
716            MessageType::RequestError => {
717                let error_code = VarInt::decode(buf)?;
718                let retry_interval = VarInt::decode(buf)?;
719                let reason_len = VarInt::decode(buf)?.into_inner() as usize;
720                let reason_phrase = read_bytes(buf, reason_len)?;
721                let redirect = if error_code.into_inner() == request_error_codes::REDIRECT {
722                    let uri_len = VarInt::decode(buf)?.into_inner() as usize;
723                    let connect_uri = read_bytes(buf, uri_len)?;
724                    let track_namespace = TrackNamespace::decode_allow_empty(buf)?;
725                    let name_len = VarInt::decode(buf)?.into_inner() as usize;
726                    let track_name = read_bytes(buf, name_len)?;
727                    Some(Redirect { connect_uri, track_namespace, track_name })
728                } else {
729                    None
730                };
731                Ok(ControlMessage::RequestError(RequestError {
732                    error_code,
733                    retry_interval,
734                    reason_phrase,
735                    redirect,
736                }))
737            }
738            MessageType::Subscribe => {
739                let request_id = VarInt::decode(buf)?;
740                let track_namespace = TrackNamespace::decode(buf)?;
741                let tn_len = VarInt::decode(buf)?.into_inner() as usize;
742                let track_name = read_bytes(buf, tn_len)?;
743                let parameters = decode_parameters(buf)?;
744                Ok(ControlMessage::Subscribe(Subscribe {
745                    request_id,
746                    track_namespace,
747                    track_name,
748                    parameters,
749                }))
750            }
751            MessageType::SubscribeOk => {
752                let track_alias = VarInt::decode(buf)?;
753                let parameters = decode_parameters(buf)?;
754                let track_properties = decode_kvp_delta(buf)?;
755                Ok(ControlMessage::SubscribeOk(SubscribeOk {
756                    track_alias,
757                    parameters,
758                    track_properties,
759                }))
760            }
761            MessageType::RequestUpdate => {
762                let request_id = VarInt::decode(buf)?;
763                let parameters = decode_parameters(buf)?;
764                Ok(ControlMessage::RequestUpdate(RequestUpdate { request_id, parameters }))
765            }
766            MessageType::Publish => {
767                let request_id = VarInt::decode(buf)?;
768                let track_namespace = TrackNamespace::decode(buf)?;
769                let tn_len = VarInt::decode(buf)?.into_inner() as usize;
770                let track_name = read_bytes(buf, tn_len)?;
771                let track_alias = VarInt::decode(buf)?;
772                let parameters = decode_parameters(buf)?;
773                let track_properties = decode_kvp_delta(buf)?;
774                Ok(ControlMessage::Publish(Publish {
775                    request_id,
776                    track_namespace,
777                    track_name,
778                    track_alias,
779                    parameters,
780                    track_properties,
781                }))
782            }
783            MessageType::PublishDone => {
784                let status_code = VarInt::decode(buf)?;
785                let stream_count = VarInt::decode(buf)?;
786                let reason_len = VarInt::decode(buf)?.into_inner() as usize;
787                let reason_phrase = read_bytes(buf, reason_len)?;
788                Ok(ControlMessage::PublishDone(PublishDone {
789                    status_code,
790                    stream_count,
791                    reason_phrase,
792                }))
793            }
794            MessageType::PublishNamespace => {
795                let request_id = VarInt::decode(buf)?;
796                let track_namespace = TrackNamespace::decode(buf)?;
797                let parameters = decode_parameters(buf)?;
798                Ok(ControlMessage::PublishNamespace(PublishNamespace {
799                    request_id,
800                    track_namespace,
801                    parameters,
802                }))
803            }
804            MessageType::Namespace => {
805                let namespace_suffix = TrackNamespace::decode_allow_empty(buf)?;
806                Ok(ControlMessage::Namespace(Namespace { namespace_suffix }))
807            }
808            MessageType::NamespaceDone => {
809                let namespace_suffix = TrackNamespace::decode_allow_empty(buf)?;
810                Ok(ControlMessage::NamespaceDone(NamespaceDone { namespace_suffix }))
811            }
812            MessageType::SubscribeNamespace => {
813                let request_id = VarInt::decode(buf)?;
814                let namespace_prefix = TrackNamespace::decode_allow_empty(buf)?;
815                let parameters = decode_parameters(buf)?;
816                Ok(ControlMessage::SubscribeNamespace(SubscribeNamespace {
817                    request_id,
818                    namespace_prefix,
819                    parameters,
820                }))
821            }
822            MessageType::SubscribeTracks => {
823                let request_id = VarInt::decode(buf)?;
824                let namespace_prefix = TrackNamespace::decode_allow_empty(buf)?;
825                let parameters = decode_parameters(buf)?;
826                Ok(ControlMessage::SubscribeTracks(SubscribeTracks {
827                    request_id,
828                    namespace_prefix,
829                    parameters,
830                }))
831            }
832            MessageType::TrackStatus => {
833                let request_id = VarInt::decode(buf)?;
834                let track_namespace = TrackNamespace::decode(buf)?;
835                let tn_len = VarInt::decode(buf)?.into_inner() as usize;
836                let track_name = read_bytes(buf, tn_len)?;
837                let parameters = decode_parameters(buf)?;
838                Ok(ControlMessage::TrackStatus(TrackStatus {
839                    request_id,
840                    track_namespace,
841                    track_name,
842                    parameters,
843                }))
844            }
845            MessageType::Fetch => {
846                let request_id = VarInt::decode(buf)?;
847                let fetch_type_val = VarInt::decode(buf)?.into_inner();
848                let fetch_type =
849                    FetchType::from_u64(fetch_type_val).ok_or(CodecError::InvalidField)?;
850                let fetch_payload = match fetch_type {
851                    FetchType::Standalone => {
852                        let track_namespace = TrackNamespace::decode(buf)?;
853                        let tn_len = VarInt::decode(buf)?.into_inner() as usize;
854                        let track_name = read_bytes(buf, tn_len)?;
855                        let start_group = VarInt::decode(buf)?;
856                        let start_object = VarInt::decode(buf)?;
857                        let end_group = VarInt::decode(buf)?;
858                        let end_object = VarInt::decode(buf)?;
859                        FetchPayload::Standalone {
860                            track_namespace,
861                            track_name,
862                            start_group,
863                            start_object,
864                            end_group,
865                            end_object,
866                        }
867                    }
868                    FetchType::RelativeJoining | FetchType::AbsoluteJoining => {
869                        let joining_request_id = VarInt::decode(buf)?;
870                        let joining_start = VarInt::decode(buf)?;
871                        FetchPayload::Joining { joining_request_id, joining_start }
872                    }
873                };
874                let parameters = decode_parameters(buf)?;
875                Ok(ControlMessage::Fetch(Fetch {
876                    request_id,
877                    fetch_type,
878                    fetch_payload,
879                    parameters,
880                }))
881            }
882            MessageType::FetchOk => {
883                if buf.remaining() < 1 {
884                    return Err(CodecError::UnexpectedEnd);
885                }
886                let end_of_track = buf.get_u8();
887                let end_group = VarInt::decode(buf)?;
888                let end_object = VarInt::decode(buf)?;
889                let parameters = decode_parameters(buf)?;
890                let track_properties = decode_kvp_delta(buf)?;
891                Ok(ControlMessage::FetchOk(FetchOk {
892                    end_of_track,
893                    end_group,
894                    end_object,
895                    parameters,
896                    track_properties,
897                }))
898            }
899            MessageType::PublishSkipped => {
900                let namespace_suffix = TrackNamespace::decode_allow_empty(buf)?;
901                let tn_len = VarInt::decode(buf)?.into_inner() as usize;
902                let track_name = read_bytes(buf, tn_len)?;
903                Ok(ControlMessage::PublishSkipped(PublishSkipped { namespace_suffix, track_name }))
904            }
905        }
906    }
907
908    pub fn message_type(&self) -> MessageType {
909        match self {
910            ControlMessage::Setup(_) => MessageType::Setup,
911            ControlMessage::GoAway(_) => MessageType::GoAway,
912            ControlMessage::RequestOk(_) => MessageType::RequestOk,
913            ControlMessage::RequestError(_) => MessageType::RequestError,
914            ControlMessage::Subscribe(_) => MessageType::Subscribe,
915            ControlMessage::SubscribeOk(_) => MessageType::SubscribeOk,
916            ControlMessage::RequestUpdate(_) => MessageType::RequestUpdate,
917            ControlMessage::Publish(_) => MessageType::Publish,
918            ControlMessage::PublishDone(_) => MessageType::PublishDone,
919            ControlMessage::PublishNamespace(_) => MessageType::PublishNamespace,
920            ControlMessage::Namespace(_) => MessageType::Namespace,
921            ControlMessage::NamespaceDone(_) => MessageType::NamespaceDone,
922            ControlMessage::SubscribeNamespace(_) => MessageType::SubscribeNamespace,
923            ControlMessage::SubscribeTracks(_) => MessageType::SubscribeTracks,
924            ControlMessage::TrackStatus(_) => MessageType::TrackStatus,
925            ControlMessage::Fetch(_) => MessageType::Fetch,
926            ControlMessage::FetchOk(_) => MessageType::FetchOk,
927            ControlMessage::PublishSkipped(_) => MessageType::PublishSkipped,
928        }
929    }
930}