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