1use std::fmt;
2use std::str::FromStr;
3
4use crate::{coding, ietf, lite};
5
6pub(crate) const NEGOTIATED: [Version; 3] = [
10 Version::Lite(lite::Version::Draft02),
11 Version::Lite(lite::Version::Draft01),
12 Version::Ietf(ietf::Version::Draft14),
13];
14
15pub const ALPNS: &[&str] = &[lite::ALPN_03, lite::ALPN, ietf::ALPN_16, ietf::ALPN_15, ietf::ALPN_14];
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20#[non_exhaustive]
21pub enum Version {
22 Ietf(ietf::Version),
23 Lite(lite::Version),
24}
25
26impl Version {
27 pub fn alpn(&self) -> &'static str {
29 match self {
30 Self::Lite(lite::Version::Draft03) => lite::ALPN_03,
31 Self::Lite(lite::Version::Draft01 | lite::Version::Draft02) => lite::ALPN,
32 Self::Ietf(ietf::Version::Draft14) => ietf::ALPN_14,
33 Self::Ietf(ietf::Version::Draft15) => ietf::ALPN_15,
34 Self::Ietf(ietf::Version::Draft16) => ietf::ALPN_16,
35 }
36 }
37}
38
39impl fmt::Display for Version {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 match self {
42 Self::Lite(lite::Version::Draft01) => write!(f, "moq-lite-01"),
43 Self::Lite(lite::Version::Draft02) => write!(f, "moq-lite-02"),
44 Self::Lite(lite::Version::Draft03) => write!(f, "moq-lite-03"),
45 Self::Ietf(ietf::Version::Draft14) => write!(f, "moq-transport-14"),
46 Self::Ietf(ietf::Version::Draft15) => write!(f, "moq-transport-15"),
47 Self::Ietf(ietf::Version::Draft16) => write!(f, "moq-transport-16"),
48 }
49 }
50}
51
52impl FromStr for Version {
53 type Err = String;
54
55 fn from_str(s: &str) -> Result<Self, Self::Err> {
56 match s {
57 "moq-lite-01" => Ok(Self::Lite(lite::Version::Draft01)),
58 "moq-lite-02" => Ok(Self::Lite(lite::Version::Draft02)),
59 "moq-lite-03" => Ok(Self::Lite(lite::Version::Draft03)),
60 "moq-transport-14" => Ok(Self::Ietf(ietf::Version::Draft14)),
61 "moq-transport-15" => Ok(Self::Ietf(ietf::Version::Draft15)),
62 "moq-transport-16" => Ok(Self::Ietf(ietf::Version::Draft16)),
63 _ => Err(format!("unknown version: {s}")),
64 }
65 }
66}
67
68#[cfg(feature = "serde")]
69impl serde::Serialize for Version {
70 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
71 serializer.serialize_str(&self.to_string())
72 }
73}
74
75#[cfg(feature = "serde")]
76impl<'de> serde::Deserialize<'de> for Version {
77 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
78 let s = String::deserialize(deserializer)?;
79 s.parse().map_err(serde::de::Error::custom)
80 }
81}
82
83impl From<ietf::Version> for Version {
84 fn from(value: ietf::Version) -> Self {
85 Self::Ietf(value)
86 }
87}
88
89impl From<lite::Version> for Version {
90 fn from(value: lite::Version) -> Self {
91 Self::Lite(value)
92 }
93}
94
95impl TryFrom<coding::Version> for Version {
96 type Error = ();
97
98 fn try_from(value: coding::Version) -> Result<Self, Self::Error> {
99 ietf::Version::try_from(value)
100 .map(Self::Ietf)
101 .or_else(|_| lite::Version::try_from(value).map(Self::Lite))
102 }
103}
104
105impl<V> coding::Decode<V> for Version {
106 fn decode<R: bytes::Buf>(r: &mut R, version: V) -> Result<Self, coding::DecodeError> {
107 coding::Version::decode(r, version).and_then(|v| v.try_into().map_err(|_| coding::DecodeError::InvalidValue))
108 }
109}
110
111impl<V> coding::Encode<V> for Version {
112 fn encode<W: bytes::BufMut>(&self, w: &mut W, v: V) -> Result<(), coding::EncodeError> {
113 match self {
114 Self::Ietf(version) => coding::Version::from(*version).encode(w, v)?,
115 Self::Lite(version) => coding::Version::from(*version).encode(w, v)?,
116 }
117 Ok(())
118 }
119}
120
121impl From<Version> for coding::Version {
122 fn from(value: Version) -> Self {
123 match value {
124 Version::Ietf(version) => version.into(),
125 Version::Lite(version) => version.into(),
126 }
127 }
128}
129
130impl From<Vec<Version>> for coding::Versions {
131 fn from(value: Vec<Version>) -> Self {
132 let inner: Vec<coding::Version> = value.into_iter().map(|v| v.into()).collect();
133 coding::Versions::from(inner)
134 }
135}
136
137#[derive(Debug, Clone)]
139pub struct Versions(Vec<Version>);
140
141impl Versions {
142 pub fn all() -> Self {
144 Self(vec![
145 Version::Lite(lite::Version::Draft03),
146 Version::Lite(lite::Version::Draft02),
147 Version::Lite(lite::Version::Draft01),
148 Version::Ietf(ietf::Version::Draft16),
149 Version::Ietf(ietf::Version::Draft15),
150 Version::Ietf(ietf::Version::Draft14),
151 ])
152 }
153
154 pub fn alpns(&self) -> Vec<&'static str> {
156 let mut alpns = Vec::new();
157 for v in &self.0 {
158 let alpn = v.alpn();
159 if !alpns.contains(&alpn) {
160 alpns.push(alpn);
161 }
162 }
163 alpns
164 }
165
166 pub fn filter(&self, other: &Versions) -> Option<Versions> {
168 let filtered: Vec<Version> = self.0.iter().filter(|v| other.0.contains(v)).copied().collect();
169 if filtered.is_empty() {
170 None
171 } else {
172 Some(Versions(filtered))
173 }
174 }
175
176 pub fn select(&self, version: Version) -> Option<Version> {
178 self.0.contains(&version).then_some(version)
179 }
180
181 pub fn contains(&self, version: &Version) -> bool {
182 self.0.contains(version)
183 }
184
185 pub fn iter(&self) -> impl Iterator<Item = &Version> {
186 self.0.iter()
187 }
188}
189
190impl Default for Versions {
191 fn default() -> Self {
192 Self::all()
193 }
194}
195
196impl From<Version> for Versions {
197 fn from(value: Version) -> Self {
198 Self(vec![value])
199 }
200}
201
202impl From<Vec<Version>> for Versions {
203 fn from(value: Vec<Version>) -> Self {
204 Self(value)
205 }
206}
207
208impl<const N: usize> From<[Version; N]> for Versions {
209 fn from(value: [Version; N]) -> Self {
210 Self(value.to_vec())
211 }
212}
213
214impl From<Versions> for coding::Versions {
215 fn from(value: Versions) -> Self {
216 let inner: Vec<coding::Version> = value.0.into_iter().map(|v| v.into()).collect();
217 coding::Versions::from(inner)
218 }
219}