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