1use crate::varint::VarInt;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7pub enum DraftVersion {
8 Draft07,
10 Draft08,
12 Draft09,
14 Draft10,
16 Draft11,
18 Draft12,
20 Draft13,
22 Draft14,
24 Draft15,
26 Draft16,
28 Draft17,
30 Draft18,
32 Draft19,
34}
35
36impl DraftVersion {
37 pub fn version_varint(&self) -> VarInt {
42 let n = match self {
43 DraftVersion::Draft07 => 7,
44 DraftVersion::Draft08 => 8,
45 DraftVersion::Draft09 => 9,
46 DraftVersion::Draft10 => 10,
47 DraftVersion::Draft11 => 11,
48 DraftVersion::Draft12 => 12,
49 DraftVersion::Draft13 => 13,
50 DraftVersion::Draft14 => 14,
51 DraftVersion::Draft15 => 15,
52 DraftVersion::Draft16 => 16,
53 DraftVersion::Draft17 => 17,
54 DraftVersion::Draft18 => 18,
55 DraftVersion::Draft19 => 19,
56 };
57 VarInt::from_usize(0xff000000 + n as usize)
58 }
59
60 pub fn quic_alpn(&self) -> &'static [u8] {
66 match self {
67 DraftVersion::Draft07
68 | DraftVersion::Draft08
69 | DraftVersion::Draft09
70 | DraftVersion::Draft10
71 | DraftVersion::Draft11
72 | DraftVersion::Draft12
73 | DraftVersion::Draft13
74 | DraftVersion::Draft14 => b"moq-00",
75 DraftVersion::Draft15 => b"moqt-15",
76 DraftVersion::Draft16 => b"moqt-16",
77 DraftVersion::Draft17 => b"moqt-17",
78 DraftVersion::Draft18 => b"moqt-18",
79 DraftVersion::Draft19 => b"moqt-19",
80 }
81 }
82
83 pub fn from_alpn(alpn: &[u8]) -> Option<DraftVersion> {
91 match alpn {
92 b"moqt-15" => Some(DraftVersion::Draft15),
93 b"moqt-16" => Some(DraftVersion::Draft16),
94 b"moqt-17" => Some(DraftVersion::Draft17),
95 b"moqt-18" => Some(DraftVersion::Draft18),
96 b"moqt-19" => Some(DraftVersion::Draft19),
97 _ => None,
98 }
99 }
100
101 pub fn from_number(n: u8) -> Option<DraftVersion> {
105 match n {
106 7 => Some(DraftVersion::Draft07),
107 8 => Some(DraftVersion::Draft08),
108 9 => Some(DraftVersion::Draft09),
109 10 => Some(DraftVersion::Draft10),
110 11 => Some(DraftVersion::Draft11),
111 12 => Some(DraftVersion::Draft12),
112 13 => Some(DraftVersion::Draft13),
113 14 => Some(DraftVersion::Draft14),
114 15 => Some(DraftVersion::Draft15),
115 16 => Some(DraftVersion::Draft16),
116 17 => Some(DraftVersion::Draft17),
117 18 => Some(DraftVersion::Draft18),
118 19 => Some(DraftVersion::Draft19),
119 _ => None,
120 }
121 }
122
123 pub fn uses_fixed_length_framing(&self) -> bool {
128 self.number() >= 11
129 }
130
131 pub fn number(&self) -> u8 {
133 match self {
134 DraftVersion::Draft07 => 7,
135 DraftVersion::Draft08 => 8,
136 DraftVersion::Draft09 => 9,
137 DraftVersion::Draft10 => 10,
138 DraftVersion::Draft11 => 11,
139 DraftVersion::Draft12 => 12,
140 DraftVersion::Draft13 => 13,
141 DraftVersion::Draft14 => 14,
142 DraftVersion::Draft15 => 15,
143 DraftVersion::Draft16 => 16,
144 DraftVersion::Draft17 => 17,
145 DraftVersion::Draft18 => 18,
146 DraftVersion::Draft19 => 19,
147 }
148 }
149}
150
151impl std::fmt::Display for DraftVersion {
152 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153 write!(f, "draft-{:02}", self.number())
154 }
155}
156
157#[cfg(test)]
158mod tests {
159 use super::*;
160
161 #[test]
162 fn from_alpn_resolves_drafts_15_plus() {
163 assert_eq!(DraftVersion::from_alpn(b"moqt-15"), Some(DraftVersion::Draft15));
164 assert_eq!(DraftVersion::from_alpn(b"moqt-16"), Some(DraftVersion::Draft16));
165 assert_eq!(DraftVersion::from_alpn(b"moqt-17"), Some(DraftVersion::Draft17));
166 assert_eq!(DraftVersion::from_alpn(b"moqt-18"), Some(DraftVersion::Draft18));
167 assert_eq!(DraftVersion::from_alpn(b"moqt-19"), Some(DraftVersion::Draft19));
168 }
169
170 #[test]
171 fn from_alpn_none_for_moq_00_and_unknown() {
172 assert_eq!(DraftVersion::from_alpn(b"moq-00"), None);
173 assert_eq!(DraftVersion::from_alpn(b"h3"), None);
174 assert_eq!(DraftVersion::from_alpn(b""), None);
175 assert_eq!(DraftVersion::from_alpn(b"moqt-99"), None);
176 }
177
178 #[test]
179 fn from_alpn_round_trips_with_quic_alpn() {
180 for d in [
181 DraftVersion::Draft15,
182 DraftVersion::Draft16,
183 DraftVersion::Draft17,
184 DraftVersion::Draft18,
185 DraftVersion::Draft19,
186 ] {
187 assert_eq!(DraftVersion::from_alpn(d.quic_alpn()), Some(d));
188 }
189 }
190
191 #[test]
192 fn from_number_resolves_supported_range() {
193 for n in 7..=19u8 {
194 assert!(DraftVersion::from_number(n).is_some(), "draft {n} should resolve");
195 }
196 }
197
198 #[test]
199 fn from_number_none_outside_range() {
200 assert_eq!(DraftVersion::from_number(0), None);
201 assert_eq!(DraftVersion::from_number(6), None);
202 assert_eq!(DraftVersion::from_number(20), None);
203 assert_eq!(DraftVersion::from_number(255), None);
204 }
205}