1use std::fmt;
2use std::str::FromStr;
3
4use crate::{coding, ietf, lite};
5
6pub(crate) const NEGOTIATED: [Version; 3] = [
12 Version::Lite(lite::Version::Lite02),
13 Version::Lite(lite::Version::Lite01),
14 Version::Ietf(ietf::Version::Draft14),
15];
16
17pub const ALPNS: &[&str] = &[
25 ALPN_LITE_05,
26 ALPN_LITE_04,
27 ALPN_LITE_03,
28 ALPN_LITE,
29 ALPN_20,
30 ALPN_19,
31 ALPN_18,
32 ALPN_17,
33 ALPN_16,
34 ALPN_15,
35 ALPN_14,
36];
37
38pub(crate) const ALPN_LITE: &str = "moql";
40pub(crate) const ALPN_LITE_03: &str = "moq-lite-03";
41pub(crate) const ALPN_LITE_04: &str = "moq-lite-04";
42pub(crate) const ALPN_LITE_05: &str = "moq-lite-05";
43pub(crate) const ALPN_LITE_06_WIP: &str = "moq-lite-06-wip";
44pub(crate) const ALPN_14: &str = "moq-00";
45pub(crate) const ALPN_15: &str = "moqt-15";
46pub(crate) const ALPN_16: &str = "moqt-16";
47pub(crate) const ALPN_17: &str = "moqt-17";
48pub(crate) const ALPN_18: &str = "moqt-18";
49pub(crate) const ALPN_19: &str = "moqt-19";
50pub(crate) const ALPN_20: &str = "moqt-20";
51
52const ALL: [Version; 13] = [
53 Version::Lite(lite::Version::Lite06Wip),
54 Version::Lite(lite::Version::Lite05),
55 Version::Lite(lite::Version::Lite04),
56 Version::Lite(lite::Version::Lite03),
57 Version::Lite(lite::Version::Lite02),
58 Version::Lite(lite::Version::Lite01),
59 Version::Ietf(ietf::Version::Draft20),
60 Version::Ietf(ietf::Version::Draft19),
61 Version::Ietf(ietf::Version::Draft18),
62 Version::Ietf(ietf::Version::Draft17),
63 Version::Ietf(ietf::Version::Draft16),
64 Version::Ietf(ietf::Version::Draft15),
65 Version::Ietf(ietf::Version::Draft14),
66];
67
68#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
70#[non_exhaustive]
71pub enum Version {
72 Lite(lite::Version),
74 Ietf(ietf::Version),
76}
77
78impl Version {
79 pub fn names() -> impl Iterator<Item = &'static str> {
81 ALL.iter().map(Self::name)
82 }
83
84 fn name(&self) -> &'static str {
85 match self {
86 Self::Lite(lite::Version::Lite01) => "moq-lite-01",
87 Self::Lite(lite::Version::Lite02) => "moq-lite-02",
88 Self::Lite(lite::Version::Lite03) => "moq-lite-03",
89 Self::Lite(lite::Version::Lite04) => "moq-lite-04",
90 Self::Lite(lite::Version::Lite05) => "moq-lite-05",
91 Self::Lite(lite::Version::Lite06Wip) => "moq-lite-06-wip",
92 Self::Ietf(ietf::Version::Draft14) => "moq-transport-14",
93 Self::Ietf(ietf::Version::Draft15) => "moq-transport-15",
94 Self::Ietf(ietf::Version::Draft16) => "moq-transport-16",
95 Self::Ietf(ietf::Version::Draft17) => "moq-transport-17",
96 Self::Ietf(ietf::Version::Draft18) => "moq-transport-18",
97 Self::Ietf(ietf::Version::Draft19) => "moq-transport-19",
98 Self::Ietf(ietf::Version::Draft20) => "moq-transport-20",
99 }
100 }
101
102 pub fn from_code(code: u64) -> Option<Self> {
104 match code {
105 0xff0dad01 => Some(Self::Lite(lite::Version::Lite01)),
106 0xff0dad02 => Some(Self::Lite(lite::Version::Lite02)),
107 0xff0dad03 => Some(Self::Lite(lite::Version::Lite03)),
108 0xff0dad04 => Some(Self::Lite(lite::Version::Lite04)),
109 0xff0dad05 => Some(Self::Lite(lite::Version::Lite05)),
110 0xff0dad06 => Some(Self::Lite(lite::Version::Lite06Wip)),
111 0xff00000e => Some(Self::Ietf(ietf::Version::Draft14)),
112 0xff00000f => Some(Self::Ietf(ietf::Version::Draft15)),
113 0xff000010 => Some(Self::Ietf(ietf::Version::Draft16)),
114 0xff000011 => Some(Self::Ietf(ietf::Version::Draft17)),
115 0xff000012 => Some(Self::Ietf(ietf::Version::Draft18)),
116 0xff000013 => Some(Self::Ietf(ietf::Version::Draft19)),
117 0xff000014 => Some(Self::Ietf(ietf::Version::Draft20)),
118 _ => None,
119 }
120 }
121
122 pub fn code(&self) -> u64 {
124 match self {
125 Self::Lite(lite::Version::Lite01) => 0xff0dad01,
126 Self::Lite(lite::Version::Lite02) => 0xff0dad02,
127 Self::Lite(lite::Version::Lite03) => 0xff0dad03,
128 Self::Lite(lite::Version::Lite04) => 0xff0dad04,
129 Self::Lite(lite::Version::Lite05) => 0xff0dad05,
130 Self::Lite(lite::Version::Lite06Wip) => 0xff0dad06,
131 Self::Ietf(ietf::Version::Draft14) => 0xff00000e,
132 Self::Ietf(ietf::Version::Draft15) => 0xff00000f,
133 Self::Ietf(ietf::Version::Draft16) => 0xff000010,
134 Self::Ietf(ietf::Version::Draft17) => 0xff000011,
135 Self::Ietf(ietf::Version::Draft18) => 0xff000012,
136 Self::Ietf(ietf::Version::Draft19) => 0xff000013,
137 Self::Ietf(ietf::Version::Draft20) => 0xff000014,
138 }
139 }
140
141 pub fn from_alpn(alpn: &str) -> Option<Self> {
146 match alpn {
147 ALPN_LITE => None, ALPN_LITE_03 => Some(Self::Lite(lite::Version::Lite03)),
149 ALPN_LITE_04 => Some(Self::Lite(lite::Version::Lite04)),
150 ALPN_LITE_05 => Some(Self::Lite(lite::Version::Lite05)),
151 ALPN_LITE_06_WIP => Some(Self::Lite(lite::Version::Lite06Wip)),
152 ALPN_14 => Some(Self::Ietf(ietf::Version::Draft14)),
153 ALPN_15 => Some(Self::Ietf(ietf::Version::Draft15)),
154 ALPN_16 => Some(Self::Ietf(ietf::Version::Draft16)),
155 ALPN_17 => Some(Self::Ietf(ietf::Version::Draft17)),
156 ALPN_18 => Some(Self::Ietf(ietf::Version::Draft18)),
157 ALPN_19 => Some(Self::Ietf(ietf::Version::Draft19)),
158 ALPN_20 => Some(Self::Ietf(ietf::Version::Draft20)),
159 _ => None,
160 }
161 }
162
163 pub fn alpn(&self) -> &'static str {
165 match self {
166 Self::Lite(lite::Version::Lite06Wip) => ALPN_LITE_06_WIP,
167 Self::Lite(lite::Version::Lite05) => ALPN_LITE_05,
168 Self::Lite(lite::Version::Lite04) => ALPN_LITE_04,
169 Self::Lite(lite::Version::Lite03) => ALPN_LITE_03,
170 Self::Lite(lite::Version::Lite01 | lite::Version::Lite02) => ALPN_LITE,
171 Self::Ietf(ietf::Version::Draft14) => ALPN_14,
172 Self::Ietf(ietf::Version::Draft15) => ALPN_15,
173 Self::Ietf(ietf::Version::Draft16) => ALPN_16,
174 Self::Ietf(ietf::Version::Draft17) => ALPN_17,
175 Self::Ietf(ietf::Version::Draft18) => ALPN_18,
176 Self::Ietf(ietf::Version::Draft19) => ALPN_19,
177 Self::Ietf(ietf::Version::Draft20) => ALPN_20,
178 }
179 }
180
181 pub fn uses_setup_negotiation(&self) -> bool {
184 matches!(
185 self,
186 Self::Lite(lite::Version::Lite01 | lite::Version::Lite02) | Self::Ietf(ietf::Version::Draft14)
187 )
188 }
189
190 pub fn is_lite(&self) -> bool {
192 match self {
193 Self::Lite(_) => true,
194 Self::Ietf(_) => false,
195 }
196 }
197
198 pub fn is_ietf(&self) -> bool {
200 match self {
201 Self::Ietf(_) => true,
202 Self::Lite(_) => false,
203 }
204 }
205}
206
207impl fmt::Display for Version {
208 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209 f.write_str(self.name())
210 }
211}
212
213impl FromStr for Version {
214 type Err = String;
215
216 fn from_str(s: &str) -> Result<Self, Self::Err> {
217 ALL.iter()
218 .find(|version| version.name() == s)
219 .copied()
220 .ok_or_else(|| format!("unknown version: {s}"))
221 }
222}
223
224impl serde::Serialize for Version {
225 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
226 serializer.serialize_str(&self.to_string())
227 }
228}
229
230impl<'de> serde::Deserialize<'de> for Version {
231 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
232 let s = String::deserialize(deserializer)?;
233 s.parse().map_err(serde::de::Error::custom)
234 }
235}
236
237impl TryFrom<coding::Version> for Version {
238 type Error = ();
239
240 fn try_from(value: coding::Version) -> Result<Self, Self::Error> {
241 Self::from_code(value.0).ok_or(())
242 }
243}
244
245impl coding::Decode<Version> for Version {
246 fn decode<R: bytes::Buf>(r: &mut R, version: Version) -> Result<Self, coding::DecodeError> {
247 coding::Version::decode(r, version).and_then(|v| v.try_into().map_err(|_| coding::DecodeError::InvalidValue))
248 }
249}
250
251impl coding::Encode<Version> for Version {
252 fn encode<W: bytes::BufMut>(&self, w: &mut W, v: Version) -> Result<(), coding::EncodeError> {
253 coding::Version::from(*self).encode(w, v)
254 }
255}
256
257impl From<Version> for coding::Version {
258 fn from(value: Version) -> Self {
259 Self(value.code())
260 }
261}
262
263impl From<Vec<Version>> for coding::Versions {
264 fn from(value: Vec<Version>) -> Self {
265 let inner: Vec<coding::Version> = value.into_iter().map(|v| v.into()).collect();
266 coding::Versions::from(inner)
267 }
268}
269
270#[derive(Debug, Clone)]
272pub struct Versions(Vec<Version>);
273
274impl Versions {
275 pub fn all() -> Self {
282 Self(
283 ALL.iter()
284 .filter(|version| !matches!(version, Version::Lite(lite::Version::Lite06Wip)))
285 .copied()
286 .collect(),
287 )
288 }
289
290 pub fn alpns(&self) -> Vec<&'static str> {
292 let mut alpns = Vec::new();
293 for v in &self.0 {
294 let alpn = v.alpn();
295 if !alpns.contains(&alpn) {
296 alpns.push(alpn);
297 }
298 }
299 alpns
300 }
301
302 pub fn filter(&self, other: &Versions) -> Option<Versions> {
304 let filtered: Vec<Version> = self.0.iter().filter(|v| other.0.contains(v)).copied().collect();
305 if filtered.is_empty() {
306 None
307 } else {
308 Some(Versions(filtered))
309 }
310 }
311
312 pub fn select(&self, version: Version) -> Option<Version> {
314 self.0.contains(&version).then_some(version)
315 }
316
317 pub fn contains(&self, version: &Version) -> bool {
319 self.0.contains(version)
320 }
321
322 pub fn iter(&self) -> impl Iterator<Item = &Version> {
324 self.0.iter()
325 }
326}
327
328impl Default for Versions {
329 fn default() -> Self {
330 Self::all()
331 }
332}
333
334impl From<Version> for Versions {
335 fn from(value: Version) -> Self {
336 Self(vec![value])
337 }
338}
339
340impl From<Vec<Version>> for Versions {
341 fn from(value: Vec<Version>) -> Self {
342 Self(value)
343 }
344}
345
346impl<const N: usize> From<[Version; N]> for Versions {
347 fn from(value: [Version; N]) -> Self {
348 Self(value.to_vec())
349 }
350}
351
352impl From<Versions> for coding::Versions {
353 fn from(value: Versions) -> Self {
354 let inner: Vec<coding::Version> = value.0.into_iter().map(|v| v.into()).collect();
355 coding::Versions::from(inner)
356 }
357}