ruma_common/identifiers/
voip_version_id.rs
1use std::fmt;
4
5use js_int::UInt;
6use ruma_macros::DisplayAsRefStr;
7use serde::{
8 de::{self, Visitor},
9 Deserialize, Deserializer, Serialize,
10};
11
12use crate::{IdParseError, PrivOwnedStr};
13
14#[derive(Clone, Debug, PartialEq, Eq, Hash, DisplayAsRefStr)]
31#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
32pub enum VoipVersionId {
33 V0,
35
36 V1,
38
39 #[doc(hidden)]
40 _Custom(PrivOwnedStr),
41}
42
43impl VoipVersionId {
44 pub fn as_str(&self) -> &str {
46 match &self {
47 Self::V0 => "0",
48 Self::V1 => "1",
49 Self::_Custom(PrivOwnedStr(s)) => s,
50 }
51 }
52
53 pub fn as_bytes(&self) -> &[u8] {
55 self.as_str().as_bytes()
56 }
57}
58
59impl From<VoipVersionId> for String {
60 fn from(id: VoipVersionId) -> Self {
61 match id {
62 VoipVersionId::_Custom(PrivOwnedStr(version)) => version.into(),
63 _ => id.as_str().to_owned(),
64 }
65 }
66}
67
68impl AsRef<str> for VoipVersionId {
69 fn as_ref(&self) -> &str {
70 self.as_str()
71 }
72}
73
74impl<'de> Deserialize<'de> for VoipVersionId {
75 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
76 where
77 D: Deserializer<'de>,
78 {
79 struct CallVersionVisitor;
80
81 impl Visitor<'_> for CallVersionVisitor {
82 type Value = VoipVersionId;
83
84 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
85 formatter.write_str("0 or string")
86 }
87
88 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
89 where
90 E: de::Error,
91 {
92 Ok(value.into())
93 }
94
95 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
96 where
97 E: de::Error,
98 {
99 let uint = UInt::try_from(value).map_err(de::Error::custom)?;
100 Self::Value::try_from(uint).map_err(de::Error::custom)
101 }
102 }
103
104 deserializer.deserialize_any(CallVersionVisitor)
105 }
106}
107
108impl Serialize for VoipVersionId {
109 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
110 where
111 S: serde::Serializer,
112 {
113 match self {
114 Self::V0 => serializer.serialize_u64(0),
115 _ => serializer.serialize_str(self.as_str()),
116 }
117 }
118}
119
120impl TryFrom<UInt> for VoipVersionId {
121 type Error = IdParseError;
122
123 fn try_from(u: UInt) -> Result<Self, Self::Error> {
124 ruma_identifiers_validation::voip_version_id::validate(u)?;
125 Ok(Self::V0)
126 }
127}
128
129fn from<T>(s: T) -> VoipVersionId
130where
131 T: AsRef<str> + Into<Box<str>>,
132{
133 match s.as_ref() {
134 "1" => VoipVersionId::V1,
135 _ => VoipVersionId::_Custom(PrivOwnedStr(s.into())),
136 }
137}
138
139impl From<&str> for VoipVersionId {
140 fn from(s: &str) -> Self {
141 from(s)
142 }
143}
144
145impl From<String> for VoipVersionId {
146 fn from(s: String) -> Self {
147 from(s)
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use assert_matches2::assert_matches;
154 use js_int::uint;
155 use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
156
157 use super::VoipVersionId;
158 use crate::IdParseError;
159
160 #[test]
161 fn valid_version_0() {
162 assert_eq!(VoipVersionId::try_from(uint!(0)), Ok(VoipVersionId::V0));
163 }
164
165 #[test]
166 fn invalid_uint_version() {
167 assert_matches!(
168 VoipVersionId::try_from(uint!(1)),
169 Err(IdParseError::InvalidVoipVersionId(_))
170 );
171 }
172
173 #[test]
174 fn valid_version_1() {
175 assert_eq!(VoipVersionId::from("1"), VoipVersionId::V1);
176 }
177
178 #[test]
179 fn valid_custom_string_version() {
180 assert_matches!(VoipVersionId::from("io.ruma.2"), version);
181 assert_eq!(version.as_ref(), "io.ruma.2");
182 }
183
184 #[test]
185 fn serialize_version_0() {
186 assert_eq!(to_json_value(&VoipVersionId::V0).unwrap(), json!(0));
187 }
188
189 #[test]
190 fn deserialize_version_0() {
191 assert_eq!(from_json_value::<VoipVersionId>(json!(0)).unwrap(), VoipVersionId::V0);
192 }
193
194 #[test]
195 fn serialize_version_1() {
196 assert_eq!(to_json_value(&VoipVersionId::V1).unwrap(), json!("1"));
197 }
198
199 #[test]
200 fn deserialize_version_1() {
201 assert_eq!(from_json_value::<VoipVersionId>(json!("1")).unwrap(), VoipVersionId::V1);
202 }
203
204 #[test]
205 fn serialize_custom_string() {
206 let version = VoipVersionId::from("io.ruma.1");
207 assert_eq!(to_json_value(&version).unwrap(), json!("io.ruma.1"));
208 }
209
210 #[test]
211 fn deserialize_custom_string() {
212 let version = VoipVersionId::from("io.ruma.1");
213 assert_eq!(from_json_value::<VoipVersionId>(json!("io.ruma.1")).unwrap(), version);
214 }
215}