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}
33
34impl DraftVersion {
35 pub fn version_varint(&self) -> VarInt {
40 let n = match self {
41 DraftVersion::Draft07 => 7,
42 DraftVersion::Draft08 => 8,
43 DraftVersion::Draft09 => 9,
44 DraftVersion::Draft10 => 10,
45 DraftVersion::Draft11 => 11,
46 DraftVersion::Draft12 => 12,
47 DraftVersion::Draft13 => 13,
48 DraftVersion::Draft14 => 14,
49 DraftVersion::Draft15 => 15,
50 DraftVersion::Draft16 => 16,
51 DraftVersion::Draft17 => 17,
52 DraftVersion::Draft18 => 18,
53 };
54 VarInt::from_usize(0xff000000 + n as usize)
55 }
56
57 pub fn quic_alpn(&self) -> &'static [u8] {
63 match self {
64 DraftVersion::Draft07
65 | DraftVersion::Draft08
66 | DraftVersion::Draft09
67 | DraftVersion::Draft10
68 | DraftVersion::Draft11
69 | DraftVersion::Draft12
70 | DraftVersion::Draft13
71 | DraftVersion::Draft14 => b"moq-00",
72 DraftVersion::Draft15 => b"moqt-15",
73 DraftVersion::Draft16 => b"moqt-16",
74 DraftVersion::Draft17 => b"moqt-17",
75 DraftVersion::Draft18 => b"moqt-18",
76 }
77 }
78
79 pub fn from_alpn(alpn: &[u8]) -> Option<DraftVersion> {
87 match alpn {
88 b"moqt-15" => Some(DraftVersion::Draft15),
89 b"moqt-16" => Some(DraftVersion::Draft16),
90 b"moqt-17" => Some(DraftVersion::Draft17),
91 b"moqt-18" => Some(DraftVersion::Draft18),
92 _ => None,
93 }
94 }
95
96 pub fn from_number(n: u8) -> Option<DraftVersion> {
100 match n {
101 7 => Some(DraftVersion::Draft07),
102 8 => Some(DraftVersion::Draft08),
103 9 => Some(DraftVersion::Draft09),
104 10 => Some(DraftVersion::Draft10),
105 11 => Some(DraftVersion::Draft11),
106 12 => Some(DraftVersion::Draft12),
107 13 => Some(DraftVersion::Draft13),
108 14 => Some(DraftVersion::Draft14),
109 15 => Some(DraftVersion::Draft15),
110 16 => Some(DraftVersion::Draft16),
111 17 => Some(DraftVersion::Draft17),
112 18 => Some(DraftVersion::Draft18),
113 _ => None,
114 }
115 }
116
117 pub fn uses_fixed_length_framing(&self) -> bool {
122 self.number() >= 11
123 }
124
125 pub fn number(&self) -> u8 {
127 match self {
128 DraftVersion::Draft07 => 7,
129 DraftVersion::Draft08 => 8,
130 DraftVersion::Draft09 => 9,
131 DraftVersion::Draft10 => 10,
132 DraftVersion::Draft11 => 11,
133 DraftVersion::Draft12 => 12,
134 DraftVersion::Draft13 => 13,
135 DraftVersion::Draft14 => 14,
136 DraftVersion::Draft15 => 15,
137 DraftVersion::Draft16 => 16,
138 DraftVersion::Draft17 => 17,
139 DraftVersion::Draft18 => 18,
140 }
141 }
142}
143
144impl std::fmt::Display for DraftVersion {
145 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146 write!(f, "draft-{:02}", self.number())
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153
154 #[test]
155 fn from_alpn_resolves_drafts_15_plus() {
156 assert_eq!(DraftVersion::from_alpn(b"moqt-15"), Some(DraftVersion::Draft15));
157 assert_eq!(DraftVersion::from_alpn(b"moqt-16"), Some(DraftVersion::Draft16));
158 assert_eq!(DraftVersion::from_alpn(b"moqt-17"), Some(DraftVersion::Draft17));
159 assert_eq!(DraftVersion::from_alpn(b"moqt-18"), Some(DraftVersion::Draft18));
160 }
161
162 #[test]
163 fn from_alpn_none_for_moq_00_and_unknown() {
164 assert_eq!(DraftVersion::from_alpn(b"moq-00"), None);
165 assert_eq!(DraftVersion::from_alpn(b"h3"), None);
166 assert_eq!(DraftVersion::from_alpn(b""), None);
167 assert_eq!(DraftVersion::from_alpn(b"moqt-99"), None);
168 }
169
170 #[test]
171 fn from_alpn_round_trips_with_quic_alpn() {
172 for d in [
173 DraftVersion::Draft15,
174 DraftVersion::Draft16,
175 DraftVersion::Draft17,
176 DraftVersion::Draft18,
177 ] {
178 assert_eq!(DraftVersion::from_alpn(d.quic_alpn()), Some(d));
179 }
180 }
181
182 #[test]
183 fn from_number_resolves_supported_range() {
184 for n in 7..=18u8 {
185 assert!(DraftVersion::from_number(n).is_some(), "draft {n} should resolve");
186 }
187 }
188
189 #[test]
190 fn from_number_none_outside_range() {
191 assert_eq!(DraftVersion::from_number(0), None);
192 assert_eq!(DraftVersion::from_number(6), None);
193 assert_eq!(DraftVersion::from_number(19), None);
194 assert_eq!(DraftVersion::from_number(255), None);
195 }
196}