1use crate::varint::{Moqt17, Moqt18, VarInt, VarIntError};
4use bytes::{Buf, BufMut};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12pub enum VarIntEncoding {
13 Rfc9000,
16 Moqt17,
20 Moqt18,
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
27pub enum DraftVersion {
28 Draft07,
30 Draft08,
32 Draft09,
34 Draft10,
36 Draft11,
38 Draft12,
40 Draft13,
42 Draft14,
44 Draft15,
46 Draft16,
48 Draft17,
50 Draft18,
52 Draft19,
54}
55
56impl DraftVersion {
57 pub fn version_varint(&self) -> VarInt {
62 let n = match self {
63 DraftVersion::Draft07 => 7,
64 DraftVersion::Draft08 => 8,
65 DraftVersion::Draft09 => 9,
66 DraftVersion::Draft10 => 10,
67 DraftVersion::Draft11 => 11,
68 DraftVersion::Draft12 => 12,
69 DraftVersion::Draft13 => 13,
70 DraftVersion::Draft14 => 14,
71 DraftVersion::Draft15 => 15,
72 DraftVersion::Draft16 => 16,
73 DraftVersion::Draft17 => 17,
74 DraftVersion::Draft18 => 18,
75 DraftVersion::Draft19 => 19,
76 };
77 VarInt::from_usize(0xff000000 + n as usize)
78 }
79
80 pub fn quic_alpn(&self) -> &'static [u8] {
87 match self {
88 DraftVersion::Draft07
89 | DraftVersion::Draft08
90 | DraftVersion::Draft09
91 | DraftVersion::Draft10
92 | DraftVersion::Draft11
93 | DraftVersion::Draft12
94 | DraftVersion::Draft13
95 | DraftVersion::Draft14 => b"moq-00",
96 DraftVersion::Draft15 => b"moqt-15",
97 DraftVersion::Draft16 => b"moqt-16",
98 DraftVersion::Draft17 => b"moqt-17",
99 DraftVersion::Draft18 => b"moqt-18",
100 DraftVersion::Draft19 => b"moqt-19",
101 }
102 }
103
104 pub fn from_alpn(alpn: &[u8]) -> Option<DraftVersion> {
112 match alpn {
113 b"moqt-15" => Some(DraftVersion::Draft15),
114 b"moqt-16" => Some(DraftVersion::Draft16),
115 b"moqt-17" => Some(DraftVersion::Draft17),
116 b"moqt-18" => Some(DraftVersion::Draft18),
117 b"moqt-19" => Some(DraftVersion::Draft19),
118 _ => None,
119 }
120 }
121
122 pub fn from_number(n: u8) -> Option<DraftVersion> {
126 match n {
127 7 => Some(DraftVersion::Draft07),
128 8 => Some(DraftVersion::Draft08),
129 9 => Some(DraftVersion::Draft09),
130 10 => Some(DraftVersion::Draft10),
131 11 => Some(DraftVersion::Draft11),
132 12 => Some(DraftVersion::Draft12),
133 13 => Some(DraftVersion::Draft13),
134 14 => Some(DraftVersion::Draft14),
135 15 => Some(DraftVersion::Draft15),
136 16 => Some(DraftVersion::Draft16),
137 17 => Some(DraftVersion::Draft17),
138 18 => Some(DraftVersion::Draft18),
139 19 => Some(DraftVersion::Draft19),
140 _ => None,
141 }
142 }
143
144 pub fn uses_fixed_length_framing(&self) -> bool {
149 self.number() >= 11
150 }
151
152 pub fn varint_encoding(&self) -> VarIntEncoding {
160 match self {
161 DraftVersion::Draft07
162 | DraftVersion::Draft08
163 | DraftVersion::Draft09
164 | DraftVersion::Draft10
165 | DraftVersion::Draft11
166 | DraftVersion::Draft12
167 | DraftVersion::Draft13
168 | DraftVersion::Draft14
169 | DraftVersion::Draft15
170 | DraftVersion::Draft16 => VarIntEncoding::Rfc9000,
171 DraftVersion::Draft17 => VarIntEncoding::Moqt17,
172 DraftVersion::Draft18 | DraftVersion::Draft19 => VarIntEncoding::Moqt18,
173 }
174 }
175
176 pub fn uses_moqt_varint(&self) -> bool {
179 self.varint_encoding() != VarIntEncoding::Rfc9000
180 }
181
182 pub fn varint_len(&self, first_byte: u8) -> usize {
191 match self.varint_encoding() {
192 VarIntEncoding::Rfc9000 => 1 << (first_byte >> 6),
193 VarIntEncoding::Moqt17 | VarIntEncoding::Moqt18 => {
194 if first_byte == 0xFF {
195 9
196 } else {
197 first_byte.leading_ones() as usize + 1
198 }
199 }
200 }
201 }
202
203 pub fn decode_varint(&self, buf: &mut impl Buf) -> Result<VarInt, VarIntError> {
205 match self.varint_encoding() {
206 VarIntEncoding::Rfc9000 => VarInt::decode(buf),
207 VarIntEncoding::Moqt17 => VarInt::decode_moqt::<Moqt17>(buf),
208 VarIntEncoding::Moqt18 => VarInt::decode_moqt::<Moqt18>(buf),
209 }
210 }
211
212 pub fn encode_varint(&self, value: VarInt, buf: &mut impl BufMut) {
214 match self.varint_encoding() {
215 VarIntEncoding::Rfc9000 => value.encode(buf),
216 VarIntEncoding::Moqt17 => value.encode_moqt::<Moqt17>(buf),
217 VarIntEncoding::Moqt18 => value.encode_moqt::<Moqt18>(buf),
218 }
219 }
220
221 pub fn number(&self) -> u8 {
223 match self {
224 DraftVersion::Draft07 => 7,
225 DraftVersion::Draft08 => 8,
226 DraftVersion::Draft09 => 9,
227 DraftVersion::Draft10 => 10,
228 DraftVersion::Draft11 => 11,
229 DraftVersion::Draft12 => 12,
230 DraftVersion::Draft13 => 13,
231 DraftVersion::Draft14 => 14,
232 DraftVersion::Draft15 => 15,
233 DraftVersion::Draft16 => 16,
234 DraftVersion::Draft17 => 17,
235 DraftVersion::Draft18 => 18,
236 DraftVersion::Draft19 => 19,
237 }
238 }
239}
240
241impl std::fmt::Display for DraftVersion {
242 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
243 write!(f, "draft-{:02}", self.number())
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use super::*;
250
251 #[test]
254 fn every_draft_states_its_varint_encoding() {
255 use VarIntEncoding::*;
256 let expected = [
257 (DraftVersion::Draft07, Rfc9000),
258 (DraftVersion::Draft08, Rfc9000),
259 (DraftVersion::Draft09, Rfc9000),
260 (DraftVersion::Draft10, Rfc9000),
261 (DraftVersion::Draft11, Rfc9000),
262 (DraftVersion::Draft12, Rfc9000),
263 (DraftVersion::Draft13, Rfc9000),
264 (DraftVersion::Draft14, Rfc9000),
265 (DraftVersion::Draft15, Rfc9000),
266 (DraftVersion::Draft16, Rfc9000),
267 (DraftVersion::Draft17, Moqt17),
268 (DraftVersion::Draft18, Moqt18),
269 (DraftVersion::Draft19, Moqt18),
270 ];
271 for (draft, encoding) in expected {
272 assert_eq!(draft.varint_encoding(), encoding, "{draft}");
273 assert_eq!(draft.uses_moqt_varint(), encoding != Rfc9000, "{draft}");
274 }
275 }
276
277 #[test]
280 fn varint_len_and_round_trip_follow_the_encoding() {
281 let mut buf = Vec::new();
282 DraftVersion::Draft14.encode_varint(VarInt::from_usize(5000), &mut buf);
283 assert_eq!(buf, vec![0x53, 0x88]);
284 assert_eq!(DraftVersion::Draft14.varint_len(buf[0]), 2);
285
286 let mut buf = Vec::new();
287 DraftVersion::Draft19.encode_varint(VarInt::from_usize(5000), &mut buf);
288 assert_eq!(buf, vec![0x93, 0x88]);
289 assert_eq!(DraftVersion::Draft19.varint_len(buf[0]), 2);
290
291 assert_eq!(DraftVersion::Draft14.varint_len(0x40), 2);
294 assert_eq!(DraftVersion::Draft19.varint_len(0x40), 1);
295 }
296
297 #[test]
298 fn from_alpn_resolves_drafts_15_plus() {
299 assert_eq!(DraftVersion::from_alpn(b"moqt-15"), Some(DraftVersion::Draft15));
300 assert_eq!(DraftVersion::from_alpn(b"moqt-16"), Some(DraftVersion::Draft16));
301 assert_eq!(DraftVersion::from_alpn(b"moqt-17"), Some(DraftVersion::Draft17));
302 assert_eq!(DraftVersion::from_alpn(b"moqt-18"), Some(DraftVersion::Draft18));
303 assert_eq!(DraftVersion::from_alpn(b"moqt-19"), Some(DraftVersion::Draft19));
304 }
305
306 #[test]
307 fn from_alpn_none_for_moq_00_and_unknown() {
308 assert_eq!(DraftVersion::from_alpn(b"moq-00"), None);
309 assert_eq!(DraftVersion::from_alpn(b"h3"), None);
310 assert_eq!(DraftVersion::from_alpn(b""), None);
311 assert_eq!(DraftVersion::from_alpn(b"moqt-99"), None);
312 }
313
314 #[test]
315 fn from_alpn_round_trips_with_quic_alpn() {
316 for d in [
317 DraftVersion::Draft15,
318 DraftVersion::Draft16,
319 DraftVersion::Draft17,
320 DraftVersion::Draft18,
321 DraftVersion::Draft19,
322 ] {
323 assert_eq!(DraftVersion::from_alpn(d.quic_alpn()), Some(d));
324 }
325 }
326
327 #[test]
328 fn from_number_resolves_supported_range() {
329 for n in 7..=19u8 {
330 assert!(DraftVersion::from_number(n).is_some(), "draft {n} should resolve");
331 }
332 }
333
334 #[test]
335 fn from_number_none_outside_range() {
336 assert_eq!(DraftVersion::from_number(0), None);
337 assert_eq!(DraftVersion::from_number(6), None);
338 assert_eq!(DraftVersion::from_number(20), None);
339 assert_eq!(DraftVersion::from_number(255), None);
340 }
341}