Skip to main content

ruma_common/identifiers/
room_alias_id.rs

1//! Matrix room alias identifiers.
2
3use ruma_macros::IdDst;
4
5use super::{MatrixToUri, MatrixUri, OwnedEventId, matrix_uri::UriAction, server_name::ServerName};
6
7/// A Matrix [room alias ID].
8///
9/// A `RoomAliasId` is converted from a string slice, and can be converted back into a string as
10/// needed.
11///
12/// ```
13/// # use ruma_common::RoomAliasId;
14/// assert_eq!(<&RoomAliasId>::try_from("#ruma:example.com").unwrap(), "#ruma:example.com");
15/// ```
16///
17/// [room alias ID]: https://spec.matrix.org/v1.19/appendices/#room-aliases
18#[repr(transparent)]
19#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, IdDst)]
20#[ruma_id(validate = ruma_identifiers_validation::room_alias_id::validate, smallvec_inline_bytes = 48)]
21pub struct RoomAliasId(str);
22
23impl RoomAliasId {
24    /// Returns the room's alias.
25    pub fn alias(&self) -> &str {
26        super::find_localpart(self.as_str())
27    }
28
29    /// Returns the server name of the room alias ID.
30    pub fn server_name(&self) -> &ServerName {
31        super::find_server_name_unchecked(self.as_str()).expect("room alias should contain a colon")
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    ///
41    /// This is deprecated because room aliases are mutable, so the URI might break after a while.
42    #[deprecated = "Use `RoomId::matrix_to_event_uri` instead."]
43    pub fn matrix_to_event_uri(&self, ev_id: impl Into<OwnedEventId>) -> MatrixToUri {
44        MatrixToUri::new((self.to_owned(), ev_id.into()).into(), Vec::new())
45    }
46
47    /// Create a `matrix:` URI for this room alias ID.
48    ///
49    /// If `join` is `true`, a click on the URI should join the room.
50    pub fn matrix_uri(&self, join: bool) -> MatrixUri {
51        MatrixUri::new(self.into(), Vec::new(), join.then_some(UriAction::Join))
52    }
53
54    /// Create a `matrix:` URI for an event scoped under this room alias ID.
55    ///
56    /// This is deprecated because room aliases are mutable, so the URI might break after a while.
57    #[deprecated = "Use `RoomId::matrix_event_uri` instead."]
58    pub fn matrix_event_uri(&self, ev_id: impl Into<OwnedEventId>) -> MatrixUri {
59        MatrixUri::new((self.to_owned(), ev_id.into()).into(), Vec::new(), None)
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::{OwnedRoomAliasId, RoomAliasId};
66    use crate::IdParseError;
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    #[test]
85    fn serialize_valid_room_alias_id() {
86        assert_eq!(
87            serde_json::to_string(
88                <&RoomAliasId>::try_from("#ruma:example.com")
89                    .expect("Failed to create RoomAliasId.")
90            )
91            .expect("Failed to convert RoomAliasId to JSON."),
92            r##""#ruma:example.com""##
93        );
94    }
95
96    #[test]
97    fn deserialize_valid_room_alias_id() {
98        assert_eq!(
99            serde_json::from_str::<OwnedRoomAliasId>(r##""#ruma:example.com""##)
100                .expect("Failed to convert JSON to RoomAliasId"),
101            "#ruma:example.com"
102        );
103    }
104
105    #[test]
106    fn valid_room_alias_id_with_explicit_standard_port() {
107        assert_eq!(
108            <&RoomAliasId>::try_from("#ruma:example.com:443")
109                .expect("Failed to create RoomAliasId."),
110            "#ruma:example.com:443"
111        );
112    }
113
114    #[test]
115    fn valid_room_alias_id_with_non_standard_port() {
116        assert_eq!(
117            <&RoomAliasId>::try_from("#ruma:example.com:5000")
118                .expect("Failed to create RoomAliasId."),
119            "#ruma:example.com:5000"
120        );
121    }
122
123    #[test]
124    fn valid_room_alias_id_unicode() {
125        assert_eq!(
126            <&RoomAliasId>::try_from("#老虎£я:example.com")
127                .expect("Failed to create RoomAliasId."),
128            "#老虎£я:example.com"
129        );
130    }
131
132    #[test]
133    fn missing_room_alias_id_sigil() {
134        assert_eq!(
135            <&RoomAliasId>::try_from("39hvsi03hlne:example.com").unwrap_err(),
136            IdParseError::MissingLeadingSigil
137        );
138    }
139
140    #[test]
141    fn missing_room_alias_id_delimiter() {
142        assert_eq!(<&RoomAliasId>::try_from("#ruma").unwrap_err(), IdParseError::MissingColon);
143    }
144
145    #[test]
146    fn invalid_leading_sigil() {
147        assert_eq!(
148            <&RoomAliasId>::try_from("!room_id:foo.bar").unwrap_err(),
149            IdParseError::MissingLeadingSigil
150        );
151    }
152
153    #[test]
154    fn invalid_room_alias_id_host() {
155        assert_eq!(
156            <&RoomAliasId>::try_from("#ruma:/").unwrap_err(),
157            IdParseError::InvalidServerName
158        );
159    }
160
161    #[test]
162    fn invalid_room_alias_id_port() {
163        assert_eq!(
164            <&RoomAliasId>::try_from("#ruma:example.com:notaport").unwrap_err(),
165            IdParseError::InvalidServerName
166        );
167    }
168}