Skip to main content

moqtap_codec/
dispatch.rs

1//! Unified types and version-aware decode/encode for runtime draft dispatch.
2//!
3//! This module provides wrapper enums (`Any*`) that hold any enabled draft's
4//! types and dispatch encoding/decoding based on
5//! [`DraftVersion`](crate::version::DraftVersion).
6//!
7//! Each enum variant is gated on its draft feature flag. Enable multiple draft
8//! features (e.g. `draft07` + `draft14`) for runtime dispatch between drafts.
9
10use bytes::{Buf, BufMut};
11
12use crate::error::CodecError;
13use crate::version::DraftVersion;
14
15/// Generates a dispatch enum with one variant per enabled draft feature.
16///
17/// Each variant wraps the draft-specific type and delegates encode/decode
18/// to the appropriate draft module.
19macro_rules! dispatch_enum {
20    (
21        $(#[$meta:meta])*
22        $vis:vis enum $name:ident {
23            $(
24                #[cfg(feature = $feat:literal)]
25                $variant:ident => $module:path,
26            )+
27        }
28        decode($decode_fn:ident);
29        encode($encode_fn:ident -> $encode_ret:ty);
30    ) => {
31        $(#[$meta])*
32        $vis enum $name {
33            $(
34                #[cfg(feature = $feat)]
35                #[doc = concat!("Draft-", $feat, " variant.")]
36                $variant($module),
37            )+
38        }
39
40        impl $name {
41            /// Decode from wire using the specified draft version.
42            #[allow(unused_variables)]
43            pub fn decode(
44                version: DraftVersion,
45                buf: &mut impl Buf,
46            ) -> Result<Self, CodecError> {
47                match version {
48                    $(
49                        #[cfg(feature = $feat)]
50                        DraftVersion::$variant => {
51                            <$module>::$decode_fn(buf).map($name::$variant)
52                        }
53                    )+
54                    #[allow(unreachable_patterns)]
55                    _ => Err(CodecError::UnsupportedDraft(
56                        format!("draft {:?} not enabled via feature flag", version),
57                    )),
58                }
59            }
60
61            /// Encode to wire using the appropriate draft's format.
62            #[allow(unused_variables, unreachable_code)]
63            pub fn encode(&self, buf: &mut impl BufMut) -> $encode_ret {
64                match self {
65                    $(
66                        #[cfg(feature = $feat)]
67                        $name::$variant(inner) => inner.$encode_fn(buf),
68                    )+
69                    #[allow(unreachable_patterns)]
70                    _ => unreachable!("AnyXxx enum has no enabled variants"),
71                }
72            }
73
74            /// Returns the draft version this value belongs to.
75            #[allow(unreachable_code)]
76            pub fn draft(&self) -> DraftVersion {
77                match self {
78                    $(
79                        #[cfg(feature = $feat)]
80                        $name::$variant(_) => DraftVersion::$variant,
81                    )+
82                    #[allow(unreachable_patterns)]
83                    _ => unreachable!("AnyXxx enum has no enabled variants"),
84                }
85            }
86        }
87    };
88}
89
90// ── Control messages ────────────────────────────────────────
91
92dispatch_enum! {
93    /// A control message from any enabled draft.
94    #[derive(Debug, Clone)]
95    pub enum AnyControlMessage {
96        #[cfg(feature = "draft07")]
97        Draft07 => crate::draft07::message::ControlMessage,
98        #[cfg(feature = "draft08")]
99        Draft08 => crate::draft08::message::ControlMessage,
100        #[cfg(feature = "draft09")]
101        Draft09 => crate::draft09::message::ControlMessage,
102        #[cfg(feature = "draft10")]
103        Draft10 => crate::draft10::message::ControlMessage,
104        #[cfg(feature = "draft11")]
105        Draft11 => crate::draft11::message::ControlMessage,
106        #[cfg(feature = "draft12")]
107        Draft12 => crate::draft12::message::ControlMessage,
108        #[cfg(feature = "draft13")]
109        Draft13 => crate::draft13::message::ControlMessage,
110        #[cfg(feature = "draft14")]
111        Draft14 => crate::draft14::message::ControlMessage,
112        #[cfg(feature = "draft15")]
113        Draft15 => crate::draft15::message::ControlMessage,
114        #[cfg(feature = "draft16")]
115        Draft16 => crate::draft16::message::ControlMessage,
116        #[cfg(feature = "draft17")]
117        Draft17 => crate::draft17::message::ControlMessage,
118    }
119    decode(decode);
120    encode(encode -> Result<(), CodecError>);
121}
122
123impl AnyControlMessage {
124    /// Returns `true` if this is a CLIENT_SETUP or SERVER_SETUP message.
125    pub fn is_setup(&self) -> bool {
126        match self {
127            #[cfg(feature = "draft07")]
128            AnyControlMessage::Draft07(m) => matches!(
129                m,
130                crate::draft07::message::ControlMessage::ClientSetup(_)
131                    | crate::draft07::message::ControlMessage::ServerSetup(_)
132            ),
133            #[cfg(feature = "draft08")]
134            AnyControlMessage::Draft08(m) => matches!(
135                m,
136                crate::draft08::message::ControlMessage::ClientSetup(_)
137                    | crate::draft08::message::ControlMessage::ServerSetup(_)
138            ),
139            #[cfg(feature = "draft09")]
140            AnyControlMessage::Draft09(m) => matches!(
141                m,
142                crate::draft09::message::ControlMessage::ClientSetup(_)
143                    | crate::draft09::message::ControlMessage::ServerSetup(_)
144            ),
145            #[cfg(feature = "draft10")]
146            AnyControlMessage::Draft10(m) => matches!(
147                m,
148                crate::draft10::message::ControlMessage::ClientSetup(_)
149                    | crate::draft10::message::ControlMessage::ServerSetup(_)
150            ),
151            #[cfg(feature = "draft11")]
152            AnyControlMessage::Draft11(m) => matches!(
153                m,
154                crate::draft11::message::ControlMessage::ClientSetup(_)
155                    | crate::draft11::message::ControlMessage::ServerSetup(_)
156            ),
157            #[cfg(feature = "draft12")]
158            AnyControlMessage::Draft12(m) => matches!(
159                m,
160                crate::draft12::message::ControlMessage::ClientSetup(_)
161                    | crate::draft12::message::ControlMessage::ServerSetup(_)
162            ),
163            #[cfg(feature = "draft13")]
164            AnyControlMessage::Draft13(m) => matches!(
165                m,
166                crate::draft13::message::ControlMessage::ClientSetup(_)
167                    | crate::draft13::message::ControlMessage::ServerSetup(_)
168            ),
169            #[cfg(feature = "draft14")]
170            AnyControlMessage::Draft14(m) => matches!(
171                m,
172                crate::draft14::message::ControlMessage::ClientSetup(_)
173                    | crate::draft14::message::ControlMessage::ServerSetup(_)
174            ),
175            #[cfg(feature = "draft15")]
176            AnyControlMessage::Draft15(m) => matches!(
177                m,
178                crate::draft15::message::ControlMessage::ClientSetup(_)
179                    | crate::draft15::message::ControlMessage::ServerSetup(_)
180            ),
181            #[cfg(feature = "draft16")]
182            AnyControlMessage::Draft16(m) => matches!(
183                m,
184                crate::draft16::message::ControlMessage::ClientSetup(_)
185                    | crate::draft16::message::ControlMessage::ServerSetup(_)
186            ),
187            #[cfg(feature = "draft17")]
188            AnyControlMessage::Draft17(m) => {
189                matches!(m, crate::draft17::message::ControlMessage::Setup(_))
190            }
191            #[allow(unreachable_patterns)]
192            _ => false,
193        }
194    }
195}
196
197// ── Data stream headers ─────────────────────────────────────
198
199dispatch_enum! {
200    /// A subgroup header from any enabled draft.
201    #[derive(Debug, Clone)]
202    pub enum AnySubgroupHeader {
203        #[cfg(feature = "draft07")]
204        Draft07 => crate::draft07::data_stream::SubgroupHeader,
205        #[cfg(feature = "draft08")]
206        Draft08 => crate::draft08::data_stream::SubgroupHeader,
207        #[cfg(feature = "draft09")]
208        Draft09 => crate::draft09::data_stream::SubgroupHeader,
209        #[cfg(feature = "draft10")]
210        Draft10 => crate::draft10::data_stream::SubgroupHeader,
211        #[cfg(feature = "draft11")]
212        Draft11 => crate::draft11::data_stream::SubgroupHeader,
213        #[cfg(feature = "draft12")]
214        Draft12 => crate::draft12::data_stream::SubgroupHeader,
215        #[cfg(feature = "draft13")]
216        Draft13 => crate::draft13::data_stream::SubgroupHeader,
217        #[cfg(feature = "draft14")]
218        Draft14 => crate::draft14::data_stream::SubgroupHeader,
219        #[cfg(feature = "draft15")]
220        Draft15 => crate::draft15::data_stream::SubgroupHeader,
221        #[cfg(feature = "draft16")]
222        Draft16 => crate::draft16::data_stream::SubgroupHeader,
223        #[cfg(feature = "draft17")]
224        Draft17 => crate::draft17::data_stream::SubgroupHeader,
225    }
226    decode(decode);
227    encode(encode -> ());
228}
229
230dispatch_enum! {
231    /// An object header from any enabled draft.
232    #[derive(Debug, Clone)]
233    pub enum AnyObjectHeader {
234        #[cfg(feature = "draft07")]
235        Draft07 => crate::draft07::data_stream::ObjectHeader,
236        #[cfg(feature = "draft08")]
237        Draft08 => crate::draft08::data_stream::ObjectHeader,
238        #[cfg(feature = "draft09")]
239        Draft09 => crate::draft09::data_stream::ObjectHeader,
240        #[cfg(feature = "draft10")]
241        Draft10 => crate::draft10::data_stream::ObjectHeader,
242        #[cfg(feature = "draft11")]
243        Draft11 => crate::draft11::data_stream::ObjectHeader,
244        #[cfg(feature = "draft12")]
245        Draft12 => crate::draft12::data_stream::ObjectHeader,
246        #[cfg(feature = "draft13")]
247        Draft13 => crate::draft13::data_stream::ObjectHeader,
248        // NOTE: drafts 14-17 have no standalone ObjectHeader. Subgroup
249        // objects on those drafts use delta-encoded object IDs and
250        // header-typed extension/properties presence flags, so
251        // decoding requires stateful per-stream context. Callers must
252        // use each draft's `SubgroupObjectReader` (or
253        // `FetchObject::decode` for fetch streams) directly.
254    }
255    decode(decode);
256    encode(encode -> ());
257}
258
259dispatch_enum! {
260    /// A datagram header from any enabled draft.
261    #[derive(Debug, Clone)]
262    pub enum AnyDatagramHeader {
263        #[cfg(feature = "draft07")]
264        Draft07 => crate::draft07::data_stream::DatagramHeader,
265        #[cfg(feature = "draft08")]
266        Draft08 => crate::draft08::data_stream::DatagramHeader,
267        #[cfg(feature = "draft09")]
268        Draft09 => crate::draft09::data_stream::DatagramHeader,
269        #[cfg(feature = "draft10")]
270        Draft10 => crate::draft10::data_stream::DatagramHeader,
271        #[cfg(feature = "draft11")]
272        Draft11 => crate::draft11::data_stream::DatagramHeader,
273        #[cfg(feature = "draft12")]
274        Draft12 => crate::draft12::data_stream::DatagramHeader,
275        #[cfg(feature = "draft13")]
276        Draft13 => crate::draft13::data_stream::DatagramHeader,
277        #[cfg(feature = "draft14")]
278        Draft14 => crate::draft14::data_stream::DatagramObject,
279        #[cfg(feature = "draft15")]
280        Draft15 => crate::draft15::data_stream::DatagramHeader,
281        #[cfg(feature = "draft16")]
282        Draft16 => crate::draft16::data_stream::DatagramHeader,
283        #[cfg(feature = "draft17")]
284        Draft17 => crate::draft17::data_stream::DatagramHeader,
285    }
286    decode(decode);
287    encode(encode -> ());
288}
289
290dispatch_enum! {
291    /// A fetch header from any enabled draft.
292    ///
293    /// Note: Header structure varies significantly across drafts.
294    /// Draft-07 has a minimal fetch header, Draft-14 has a full header.
295    #[derive(Debug, Clone)]
296    pub enum AnyFetchHeader {
297        #[cfg(feature = "draft07")]
298        Draft07 => crate::draft07::data_stream::FetchHeader,
299        #[cfg(feature = "draft08")]
300        Draft08 => crate::draft08::data_stream::FetchHeader,
301        #[cfg(feature = "draft09")]
302        Draft09 => crate::draft09::data_stream::FetchHeader,
303        #[cfg(feature = "draft10")]
304        Draft10 => crate::draft10::data_stream::FetchHeader,
305        #[cfg(feature = "draft11")]
306        Draft11 => crate::draft11::data_stream::FetchHeader,
307        #[cfg(feature = "draft12")]
308        Draft12 => crate::draft12::data_stream::FetchHeader,
309        #[cfg(feature = "draft13")]
310        Draft13 => crate::draft13::data_stream::FetchHeader,
311        #[cfg(feature = "draft14")]
312        Draft14 => crate::draft14::data_stream::FetchHeader,
313        #[cfg(feature = "draft15")]
314        Draft15 => crate::draft15::data_stream::FetchHeader,
315        #[cfg(feature = "draft16")]
316        Draft16 => crate::draft16::data_stream::FetchHeader,
317        #[cfg(feature = "draft17")]
318        Draft17 => crate::draft17::data_stream::FetchHeader,
319    }
320    decode(decode);
321    encode(encode -> ());
322}