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