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