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