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