ruma_identifiers/
room_version_id.rs1use std::{cmp::Ordering, convert::TryFrom, str::FromStr};
4
5use ruma_serde_macros::DisplayAsRefStr;
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8
9#[derive(Clone, Debug, PartialEq, Eq, Hash, DisplayAsRefStr)]
27#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
28pub enum RoomVersionId {
29 V1,
31
32 V2,
34
35 V3,
37
38 V4,
40
41 V5,
43
44 V6,
46
47 V7,
49
50 V8,
52
53 V9,
55
56 #[doc(hidden)]
57 _Custom(CustomRoomVersion),
58}
59
60impl RoomVersionId {
61 pub fn as_str(&self) -> &str {
63 match &self {
66 Self::V1 => "1",
67 Self::V2 => "2",
68 Self::V3 => "3",
69 Self::V4 => "4",
70 Self::V5 => "5",
71 Self::V6 => "6",
72 Self::V7 => "7",
73 Self::V8 => "8",
74 Self::V9 => "9",
75 Self::_Custom(version) => version.as_str(),
76 }
77 }
78
79 pub fn as_bytes(&self) -> &[u8] {
81 self.as_str().as_bytes()
82 }
83}
84
85impl From<RoomVersionId> for String {
86 fn from(id: RoomVersionId) -> Self {
87 match id {
88 RoomVersionId::V1 => "1".to_owned(),
89 RoomVersionId::V2 => "2".to_owned(),
90 RoomVersionId::V3 => "3".to_owned(),
91 RoomVersionId::V4 => "4".to_owned(),
92 RoomVersionId::V5 => "5".to_owned(),
93 RoomVersionId::V6 => "6".to_owned(),
94 RoomVersionId::V7 => "7".to_owned(),
95 RoomVersionId::V8 => "8".to_owned(),
96 RoomVersionId::V9 => "9".to_owned(),
97 RoomVersionId::_Custom(version) => version.into(),
98 }
99 }
100}
101
102impl AsRef<str> for RoomVersionId {
103 fn as_ref(&self) -> &str {
104 self.as_str()
105 }
106}
107
108impl PartialOrd for RoomVersionId {
109 fn partial_cmp(&self, other: &RoomVersionId) -> Option<Ordering> {
115 self.as_ref().partial_cmp(other.as_ref())
116 }
117}
118
119impl Ord for RoomVersionId {
120 fn cmp(&self, other: &Self) -> Ordering {
126 self.as_ref().cmp(other.as_ref())
127 }
128}
129
130#[cfg(feature = "serde")]
131impl Serialize for RoomVersionId {
132 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
133 where
134 S: Serializer,
135 {
136 serializer.serialize_str(self.as_ref())
137 }
138}
139
140#[cfg(feature = "serde")]
141impl<'de> Deserialize<'de> for RoomVersionId {
142 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
143 where
144 D: Deserializer<'de>,
145 {
146 crate::deserialize_id(deserializer, "a Matrix room version ID as a string")
147 }
148}
149
150fn try_from<S>(room_version_id: S) -> Result<RoomVersionId, crate::Error>
152where
153 S: AsRef<str> + Into<Box<str>>,
154{
155 let version = match room_version_id.as_ref() {
156 "1" => RoomVersionId::V1,
157 "2" => RoomVersionId::V2,
158 "3" => RoomVersionId::V3,
159 "4" => RoomVersionId::V4,
160 "5" => RoomVersionId::V5,
161 "6" => RoomVersionId::V6,
162 "7" => RoomVersionId::V7,
163 "8" => RoomVersionId::V8,
164 "9" => RoomVersionId::V9,
165 custom => {
166 ruma_identifiers_validation::room_version_id::validate(custom)?;
167 RoomVersionId::_Custom(CustomRoomVersion(room_version_id.into()))
168 }
169 };
170
171 Ok(version)
172}
173
174impl FromStr for RoomVersionId {
175 type Err = crate::Error;
176
177 fn from_str(s: &str) -> Result<Self, crate::Error> {
178 try_from(s)
179 }
180}
181
182impl TryFrom<&str> for RoomVersionId {
183 type Error = crate::Error;
184
185 fn try_from(s: &str) -> Result<Self, crate::Error> {
186 try_from(s)
187 }
188}
189
190impl TryFrom<String> for RoomVersionId {
191 type Error = crate::Error;
192
193 fn try_from(s: String) -> Result<Self, crate::Error> {
194 try_from(s)
195 }
196}
197
198impl PartialEq<&str> for RoomVersionId {
199 fn eq(&self, other: &&str) -> bool {
200 self.as_str() == *other
201 }
202}
203
204impl PartialEq<RoomVersionId> for &str {
205 fn eq(&self, other: &RoomVersionId) -> bool {
206 *self == other.as_str()
207 }
208}
209
210impl PartialEq<String> for RoomVersionId {
211 fn eq(&self, other: &String) -> bool {
212 self.as_str() == other
213 }
214}
215
216impl PartialEq<RoomVersionId> for String {
217 fn eq(&self, other: &RoomVersionId) -> bool {
218 self == other.as_str()
219 }
220}
221
222#[derive(Clone, Debug, PartialEq, Eq, Hash)]
223#[doc(hidden)]
224pub struct CustomRoomVersion(Box<str>);
225
226#[doc(hidden)]
227impl CustomRoomVersion {
228 pub fn as_str(&self) -> &str {
230 &self.0
231 }
232}
233
234#[doc(hidden)]
235impl From<CustomRoomVersion> for String {
236 fn from(v: CustomRoomVersion) -> Self {
237 v.0.into()
238 }
239}
240
241#[doc(hidden)]
242impl AsRef<str> for CustomRoomVersion {
243 fn as_ref(&self) -> &str {
244 self.as_str()
245 }
246}
247
248#[cfg(test)]
249mod tests {
250 use std::convert::TryFrom;
251
252 use super::RoomVersionId;
253 use crate::Error;
254
255 #[test]
256 fn valid_version_1_room_version_id() {
257 assert_eq!(
258 RoomVersionId::try_from("1").expect("Failed to create RoomVersionId.").as_ref(),
259 "1"
260 );
261 }
262
263 #[test]
264 fn valid_version_2_room_version_id() {
265 assert_eq!(
266 RoomVersionId::try_from("2").expect("Failed to create RoomVersionId.").as_ref(),
267 "2"
268 );
269 }
270
271 #[test]
272 fn valid_version_3_room_version_id() {
273 assert_eq!(
274 RoomVersionId::try_from("3").expect("Failed to create RoomVersionId.").as_ref(),
275 "3"
276 );
277 }
278
279 #[test]
280 fn valid_version_4_room_version_id() {
281 assert_eq!(
282 RoomVersionId::try_from("4").expect("Failed to create RoomVersionId.").as_ref(),
283 "4"
284 );
285 }
286
287 #[test]
288 fn valid_version_5_room_version_id() {
289 assert_eq!(
290 RoomVersionId::try_from("5").expect("Failed to create RoomVersionId.").as_ref(),
291 "5"
292 );
293 }
294
295 #[test]
296 fn valid_version_6_room_version_id() {
297 assert_eq!(
298 RoomVersionId::try_from("6").expect("Failed to create RoomVersionId.").as_ref(),
299 "6"
300 );
301 }
302
303 #[test]
304 fn valid_custom_room_version_id() {
305 assert_eq!(
306 RoomVersionId::try_from("io.ruma.1").expect("Failed to create RoomVersionId.").as_ref(),
307 "io.ruma.1"
308 );
309 }
310
311 #[test]
312 fn empty_room_version_id() {
313 assert_eq!(RoomVersionId::try_from(""), Err(Error::EmptyRoomVersionId));
314 }
315
316 #[test]
317 fn over_max_code_point_room_version_id() {
318 assert_eq!(
319 RoomVersionId::try_from("0123456789012345678901234567890123456789"),
320 Err(Error::MaximumLengthExceeded)
321 );
322 }
323
324 #[cfg(feature = "serde")]
325 #[test]
326 fn serialize_official_room_id() {
327 assert_eq!(
328 serde_json::to_string(
329 &RoomVersionId::try_from("1").expect("Failed to create RoomVersionId.")
330 )
331 .expect("Failed to convert RoomVersionId to JSON."),
332 r#""1""#
333 );
334 }
335
336 #[cfg(feature = "serde")]
337 #[test]
338 fn deserialize_official_room_id() {
339 let deserialized = serde_json::from_str::<RoomVersionId>(r#""1""#)
340 .expect("Failed to convert RoomVersionId to JSON.");
341
342 assert_eq!(deserialized, RoomVersionId::V1);
343
344 assert_eq!(
345 deserialized,
346 RoomVersionId::try_from("1").expect("Failed to create RoomVersionId.")
347 );
348 }
349
350 #[cfg(feature = "serde")]
351 #[test]
352 fn serialize_custom_room_id() {
353 assert_eq!(
354 serde_json::to_string(
355 &RoomVersionId::try_from("io.ruma.1").expect("Failed to create RoomVersionId.")
356 )
357 .expect("Failed to convert RoomVersionId to JSON."),
358 r#""io.ruma.1""#
359 );
360 }
361
362 #[cfg(feature = "serde")]
363 #[test]
364 fn deserialize_custom_room_id() {
365 let deserialized = serde_json::from_str::<RoomVersionId>(r#""io.ruma.1""#)
366 .expect("Failed to convert RoomVersionId to JSON.");
367
368 assert_eq!(
369 deserialized,
370 RoomVersionId::try_from("io.ruma.1").expect("Failed to create RoomVersionId.")
371 );
372 }
373}