Skip to main content

moqtap_codec/
types.rs

1use crate::varint::VarInt;
2use bytes::{Buf, BufMut};
3
4/// Read exactly `len` bytes from `buf`, returning them as a `Vec<u8>`.
5#[inline]
6#[allow(clippy::uninit_vec)]
7pub fn read_bytes(buf: &mut impl Buf, len: usize) -> Result<Vec<u8>, crate::error::CodecError> {
8    if buf.remaining() < len {
9        return Err(crate::error::CodecError::UnexpectedEnd);
10    }
11    let mut v = Vec::with_capacity(len);
12    // Safety: `set_len(len)` with capacity `len` exposes `len` uninitialized
13    // `u8`s. `copy_to_slice` immediately overwrites all of them before any
14    // read. `u8` has no drop, so no leaks on panic beyond the `Vec` itself.
15    unsafe {
16        v.set_len(len);
17    }
18    buf.copy_to_slice(&mut v);
19    Ok(v)
20}
21
22/// Track Namespace: ordered N-tuple of byte-string elements (1 <= N <= 32).
23#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct TrackNamespace(pub Vec<Vec<u8>>);
25
26/// Full Track Name: namespace + track name.
27/// Maximum total size: 4096 bytes.
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct FullTrackName {
30    /// The track namespace tuple.
31    pub namespace: TrackNamespace,
32    /// The track name within the namespace.
33    pub track_name: Vec<u8>,
34}
35
36/// Location within a track: (Group, Object).
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub struct Location {
39    /// Group identifier.
40    pub group: VarInt,
41    /// Object identifier within the group.
42    pub object: VarInt,
43}
44
45/// Object status values (draft-14).
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47#[repr(u8)]
48pub enum ObjectStatus {
49    /// Object payload follows normally.
50    Normal = 0x0,
51    /// Last object in the group.
52    EndOfGroup = 0x1,
53    /// Last object in the track.
54    EndOfTrack = 0x2,
55    /// The referenced object does not exist.
56    DoesNotExist = 0x3,
57}
58
59/// Group ordering preference.
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61#[repr(u8)]
62pub enum GroupOrder {
63    /// Publisher determines the order.
64    Publisher = 0x0,
65    /// Groups delivered in ascending order.
66    Ascending = 0x1,
67    /// Groups delivered in descending order.
68    Descending = 0x2,
69}
70
71/// Forwarding preference for objects.
72#[derive(Debug, Clone, Copy, PartialEq, Eq)]
73#[repr(u8)]
74pub enum ForwardingPreference {
75    /// Object forwarding (sent on a subgroup stream).
76    Object = 0x0,
77    /// Datagram forwarding (sent as a QUIC datagram).
78    Datagram = 0x1,
79}
80
81/// Whether content exists (used in SUBSCRIBE_OK).
82#[derive(Debug, Clone, Copy, PartialEq, Eq)]
83#[repr(u8)]
84pub enum ContentExists {
85    /// No largest location is provided.
86    NoLargestLocation = 0,
87    /// A largest location follows.
88    HasLargestLocation = 1,
89}
90
91/// Forward state (0 = don't forward, 1 = forward).
92#[derive(Debug, Clone, Copy, PartialEq, Eq)]
93#[repr(u8)]
94pub enum Forward {
95    /// Do not forward.
96    DontForward = 0,
97    /// Forward enabled.
98    Forward = 1,
99}
100
101/// Subscription filter types (draft-14).
102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103#[repr(u8)]
104pub enum FilterType {
105    /// Start from the next group.
106    NextGroupStart = 0x1,
107    /// Start from the largest available object.
108    LargestObject = 0x2,
109    /// Start from an absolute location.
110    AbsoluteStart = 0x3,
111    /// Absolute range with start and end locations.
112    AbsoluteRange = 0x4,
113}
114
115/// Authorization token alias types.
116#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117#[repr(u8)]
118pub enum TokenAliasType {
119    /// Delete a previously registered alias.
120    Delete = 0x0,
121    /// Register a new alias.
122    Register = 0x1,
123    /// Use an existing alias.
124    UseAlias = 0x2,
125    /// Use a literal token value.
126    UseValue = 0x3,
127}
128
129impl TrackNamespace {
130    /// Encode the namespace tuple into the buffer.
131    pub fn encode(&self, buf: &mut impl BufMut) {
132        VarInt::from_usize(self.0.len()).encode(buf);
133        for elem in &self.0 {
134            VarInt::from_usize(elem.len()).encode(buf);
135            buf.put_slice(elem);
136        }
137    }
138
139    /// Decode a namespace tuple from the buffer.
140    pub fn decode(buf: &mut impl Buf) -> Result<Self, crate::error::CodecError> {
141        let n = VarInt::decode(buf)?.into_inner() as usize;
142        if n == 0 || n > crate::error::MAX_NAMESPACE_TUPLE_SIZE {
143            return Err(crate::error::CodecError::InvalidNamespaceTupleSize(n));
144        }
145        Self::decode_elements(buf, n)
146    }
147
148    /// Decode a namespace tuple that may have zero elements (for suffix types).
149    pub fn decode_allow_empty(buf: &mut impl Buf) -> Result<Self, crate::error::CodecError> {
150        let n = VarInt::decode(buf)?.into_inner() as usize;
151        if n > crate::error::MAX_NAMESPACE_TUPLE_SIZE {
152            return Err(crate::error::CodecError::InvalidNamespaceTupleSize(n));
153        }
154        Self::decode_elements(buf, n)
155    }
156
157    fn decode_elements(buf: &mut impl Buf, n: usize) -> Result<Self, crate::error::CodecError> {
158        let mut elements = Vec::with_capacity(n);
159        for _ in 0..n {
160            let len = VarInt::decode(buf)?.into_inner() as usize;
161            elements.push(read_bytes(buf, len)?);
162        }
163        Ok(TrackNamespace(elements))
164    }
165}
166
167impl Location {
168    /// Encode the location (group, object) into the buffer.
169    pub fn encode(&self, buf: &mut impl BufMut) {
170        self.group.encode(buf);
171        self.object.encode(buf);
172    }
173
174    /// Decode a location from the buffer.
175    pub fn decode(buf: &mut impl Buf) -> Result<Self, crate::error::CodecError> {
176        let group = VarInt::decode(buf)?;
177        let object = VarInt::decode(buf)?;
178        Ok(Location { group, object })
179    }
180}
181
182impl ObjectStatus {
183    /// Convert a raw byte to an `ObjectStatus`, if valid.
184    pub fn from_u8(v: u8) -> Option<Self> {
185        match v {
186            0x0 => Some(ObjectStatus::Normal),
187            0x1 => Some(ObjectStatus::EndOfGroup),
188            0x2 => Some(ObjectStatus::EndOfTrack),
189            0x3 => Some(ObjectStatus::DoesNotExist),
190            _ => None,
191        }
192    }
193}
194
195impl GroupOrder {
196    /// Convert a raw byte to a `GroupOrder`, if valid.
197    pub fn from_u8(v: u8) -> Option<Self> {
198        match v {
199            0x0 => Some(GroupOrder::Publisher),
200            0x1 => Some(GroupOrder::Ascending),
201            0x2 => Some(GroupOrder::Descending),
202            _ => None,
203        }
204    }
205}
206
207impl ForwardingPreference {
208    /// Convert a raw byte to a `ForwardingPreference`, if valid.
209    pub fn from_u8(v: u8) -> Option<Self> {
210        match v {
211            0x0 => Some(ForwardingPreference::Object),
212            0x1 => Some(ForwardingPreference::Datagram),
213            _ => None,
214        }
215    }
216}
217
218impl FilterType {
219    /// Convert a raw byte to a `FilterType`, if valid.
220    pub fn from_u8(v: u8) -> Option<Self> {
221        Self::from_u64(v as u64)
222    }
223
224    /// Convert a raw u64 to a `FilterType`, if valid.
225    pub fn from_u64(v: u64) -> Option<Self> {
226        match v {
227            0x1 => Some(FilterType::NextGroupStart),
228            0x2 => Some(FilterType::LargestObject),
229            0x3 => Some(FilterType::AbsoluteStart),
230            0x4 => Some(FilterType::AbsoluteRange),
231            _ => None,
232        }
233    }
234}