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