ruma_identifiers/
room_alias_id.rs

1//! Matrix room alias identifiers.
2
3use crate::{matrix_uri::UriAction, server_name::ServerName, EventId, MatrixToUri, MatrixUri};
4
5/// A Matrix [room alias ID].
6///
7/// A `RoomAliasId` is converted from a string slice, and can be converted back into a string as
8/// needed.
9///
10/// ```
11/// # use std::convert::TryFrom;
12/// # use ruma_identifiers::RoomAliasId;
13/// assert_eq!(<&RoomAliasId>::try_from("#ruma:example.com").unwrap(), "#ruma:example.com");
14/// ```
15///
16/// [room alias ID]: https://spec.matrix.org/v1.2/appendices/#room-aliases
17#[repr(transparent)]
18#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
19pub struct RoomAliasId(str);
20
21opaque_identifier_validated!(RoomAliasId, ruma_identifiers_validation::room_alias_id::validate);
22
23impl RoomAliasId {
24    /// Returns the room's alias.
25    pub fn alias(&self) -> &str {
26        &self.as_str()[1..self.colon_idx()]
27    }
28
29    /// Returns the server name of the room alias ID.
30    pub fn server_name(&self) -> &ServerName {
31        ServerName::from_borrowed(&self.as_str()[self.colon_idx() + 1..])
32    }
33
34    /// Create a `matrix.to` URI for this room alias ID.
35    pub fn matrix_to_uri(&self) -> MatrixToUri {
36        MatrixToUri::new(self.into(), Vec::new())
37    }
38
39    /// Create a `matrix.to` URI for an event scoped under this room alias ID.
40    pub fn matrix_to_event_uri(&self, ev_id: &EventId) -> MatrixToUri {
41        MatrixToUri::new((self, ev_id).into(), Vec::new())
42    }
43
44    /// Create a `matrix:` URI for this room alias ID.
45    ///
46    /// If `join` is `true`, a click on the URI should join the room.
47    pub fn matrix_uri(&self, join: bool) -> MatrixUri {
48        MatrixUri::new(self.into(), Vec::new(), Some(UriAction::Join).filter(|_| join))
49    }
50
51    /// Create a `matrix:` URI for an event scoped under this room alias ID.
52    pub fn matrix_event_uri(&self, ev_id: &EventId) -> MatrixUri {
53        MatrixUri::new((self, ev_id).into(), Vec::new(), None)
54    }
55
56    fn colon_idx(&self) -> usize {
57        self.as_str().find(':').unwrap()
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use std::convert::TryFrom;
64
65    use super::RoomAliasId;
66    use crate::Error;
67
68    #[test]
69    fn valid_room_alias_id() {
70        assert_eq!(
71            <&RoomAliasId>::try_from("#ruma:example.com").expect("Failed to create RoomAliasId."),
72            "#ruma:example.com"
73        );
74    }
75
76    #[test]
77    fn empty_localpart() {
78        assert_eq!(
79            <&RoomAliasId>::try_from("#:myhomeserver.io").expect("Failed to create RoomAliasId."),
80            "#:myhomeserver.io"
81        );
82    }
83
84    #[cfg(feature = "serde")]
85    #[test]
86    fn serialize_valid_room_alias_id() {
87        assert_eq!(
88            serde_json::to_string(
89                <&RoomAliasId>::try_from("#ruma:example.com")
90                    .expect("Failed to create RoomAliasId.")
91            )
92            .expect("Failed to convert RoomAliasId to JSON."),
93            r##""#ruma:example.com""##
94        );
95    }
96
97    #[cfg(feature = "serde")]
98    #[test]
99    fn deserialize_valid_room_alias_id() {
100        assert_eq!(
101            serde_json::from_str::<Box<RoomAliasId>>(r##""#ruma:example.com""##)
102                .expect("Failed to convert JSON to RoomAliasId"),
103            <&RoomAliasId>::try_from("#ruma:example.com").expect("Failed to create RoomAliasId.")
104        );
105    }
106
107    #[test]
108    fn valid_room_alias_id_with_explicit_standard_port() {
109        assert_eq!(
110            <&RoomAliasId>::try_from("#ruma:example.com:443")
111                .expect("Failed to create RoomAliasId."),
112            "#ruma:example.com:443"
113        );
114    }
115
116    #[test]
117    fn valid_room_alias_id_with_non_standard_port() {
118        assert_eq!(
119            <&RoomAliasId>::try_from("#ruma:example.com:5000")
120                .expect("Failed to create RoomAliasId."),
121            "#ruma:example.com:5000"
122        );
123    }
124
125    #[test]
126    fn valid_room_alias_id_unicode() {
127        assert_eq!(
128            <&RoomAliasId>::try_from("#老虎£я:example.com")
129                .expect("Failed to create RoomAliasId."),
130            "#老虎£я:example.com"
131        );
132    }
133
134    #[test]
135    fn missing_room_alias_id_sigil() {
136        assert_eq!(
137            <&RoomAliasId>::try_from("39hvsi03hlne:example.com").unwrap_err(),
138            Error::MissingLeadingSigil
139        );
140    }
141
142    #[test]
143    fn missing_room_alias_id_delimiter() {
144        assert_eq!(<&RoomAliasId>::try_from("#ruma").unwrap_err(), Error::MissingDelimiter);
145    }
146
147    #[test]
148    fn invalid_leading_sigil() {
149        assert_eq!(
150            <&RoomAliasId>::try_from("!room_id:foo.bar").unwrap_err(),
151            Error::MissingLeadingSigil
152        );
153    }
154
155    #[test]
156    fn invalid_room_alias_id_host() {
157        assert_eq!(<&RoomAliasId>::try_from("#ruma:/").unwrap_err(), Error::InvalidServerName);
158    }
159
160    #[test]
161    fn invalid_room_alias_id_port() {
162        assert_eq!(
163            <&RoomAliasId>::try_from("#ruma:example.com:notaport").unwrap_err(),
164            Error::InvalidServerName
165        );
166    }
167}