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