ruma_identifiers/
event_id.rs1use crate::ServerName;
4
5#[repr(transparent)]
38#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
39pub struct EventId(str);
40
41opaque_identifier_validated!(EventId, ruma_identifiers_validation::event_id::validate);
42
43impl EventId {
44 #[cfg(feature = "rand")]
50 pub fn new(server_name: &ServerName) -> Box<Self> {
51 Self::from_owned(format!("${}:{}", crate::generate_localpart(18), server_name).into())
52 }
53
54 pub fn localpart(&self) -> &str {
60 let idx = self.colon_idx().unwrap_or_else(|| self.as_str().len());
61 &self.as_str()[1..idx]
62 }
63
64 pub fn server_name(&self) -> Option<&ServerName> {
68 self.colon_idx().map(|idx| ServerName::from_borrowed(&self.as_str()[idx + 1..]))
69 }
70
71 fn colon_idx(&self) -> Option<usize> {
72 self.as_str().find(':')
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use std::convert::TryFrom;
79
80 use super::EventId;
81 use crate::Error;
82
83 #[test]
84 fn valid_original_event_id() {
85 assert_eq!(
86 <&EventId>::try_from("$39hvsi03hlne:example.com").expect("Failed to create EventId."),
87 "$39hvsi03hlne:example.com"
88 );
89 }
90
91 #[test]
92 fn valid_base64_event_id() {
93 assert_eq!(
94 <&EventId>::try_from("$acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk")
95 .expect("Failed to create EventId."),
96 "$acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk"
97 )
98 }
99
100 #[test]
101 fn valid_url_safe_base64_event_id() {
102 assert_eq!(
103 <&EventId>::try_from("$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg")
104 .expect("Failed to create EventId."),
105 "$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg"
106 )
107 }
108
109 #[cfg(feature = "rand")]
110 #[test]
111 fn generate_random_valid_event_id() {
112 use crate::server_name;
113
114 let event_id = EventId::new(server_name!("example.com"));
115 let id_str = event_id.as_str();
116
117 assert!(id_str.starts_with('$'));
118 assert_eq!(id_str.len(), 31);
119 }
120
121 #[cfg(feature = "serde")]
122 #[test]
123 fn serialize_valid_original_event_id() {
124 assert_eq!(
125 serde_json::to_string(
126 <&EventId>::try_from("$39hvsi03hlne:example.com")
127 .expect("Failed to create EventId.")
128 )
129 .expect("Failed to convert EventId to JSON."),
130 r#""$39hvsi03hlne:example.com""#
131 );
132 }
133
134 #[cfg(feature = "serde")]
135 #[test]
136 fn serialize_valid_base64_event_id() {
137 assert_eq!(
138 serde_json::to_string(
139 <&EventId>::try_from("$acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk")
140 .expect("Failed to create EventId.")
141 )
142 .expect("Failed to convert EventId to JSON."),
143 r#""$acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk""#
144 );
145 }
146
147 #[cfg(feature = "serde")]
148 #[test]
149 fn serialize_valid_url_safe_base64_event_id() {
150 assert_eq!(
151 serde_json::to_string(
152 <&EventId>::try_from("$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg")
153 .expect("Failed to create EventId.")
154 )
155 .expect("Failed to convert EventId to JSON."),
156 r#""$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg""#
157 );
158 }
159
160 #[cfg(feature = "serde")]
161 #[test]
162 fn deserialize_valid_original_event_id() {
163 assert_eq!(
164 serde_json::from_str::<Box<EventId>>(r#""$39hvsi03hlne:example.com""#)
165 .expect("Failed to convert JSON to EventId"),
166 <&EventId>::try_from("$39hvsi03hlne:example.com").expect("Failed to create EventId.")
167 );
168 }
169
170 #[cfg(feature = "serde")]
171 #[test]
172 fn deserialize_valid_base64_event_id() {
173 assert_eq!(
174 serde_json::from_str::<Box<EventId>>(
175 r#""$acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk""#
176 )
177 .expect("Failed to convert JSON to EventId"),
178 <&EventId>::try_from("$acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk")
179 .expect("Failed to create EventId.")
180 );
181 }
182
183 #[cfg(feature = "serde")]
184 #[test]
185 fn deserialize_valid_url_safe_base64_event_id() {
186 assert_eq!(
187 serde_json::from_str::<Box<EventId>>(
188 r#""$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg""#
189 )
190 .expect("Failed to convert JSON to EventId"),
191 <&EventId>::try_from("$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg")
192 .expect("Failed to create EventId.")
193 );
194 }
195
196 #[test]
197 fn valid_original_event_id_with_explicit_standard_port() {
198 assert_eq!(
199 <&EventId>::try_from("$39hvsi03hlne:example.com:443")
200 .expect("Failed to create EventId."),
201 "$39hvsi03hlne:example.com:443"
202 );
203 }
204
205 #[test]
206 fn valid_original_event_id_with_non_standard_port() {
207 assert_eq!(
208 <&EventId>::try_from("$39hvsi03hlne:example.com:5000")
209 .expect("Failed to create EventId."),
210 "$39hvsi03hlne:example.com:5000"
211 );
212 }
213
214 #[test]
215 fn missing_original_event_id_sigil() {
216 assert_eq!(
217 <&EventId>::try_from("39hvsi03hlne:example.com").unwrap_err(),
218 Error::MissingLeadingSigil
219 );
220 }
221
222 #[test]
223 fn missing_base64_event_id_sigil() {
224 assert_eq!(
225 <&EventId>::try_from("acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk").unwrap_err(),
226 Error::MissingLeadingSigil
227 );
228 }
229
230 #[test]
231 fn missing_url_safe_base64_event_id_sigil() {
232 assert_eq!(
233 <&EventId>::try_from("Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg").unwrap_err(),
234 Error::MissingLeadingSigil
235 );
236 }
237
238 #[test]
239 fn invalid_event_id_host() {
240 assert_eq!(<&EventId>::try_from("$39hvsi03hlne:/").unwrap_err(), Error::InvalidServerName);
241 }
242
243 #[test]
244 fn invalid_event_id_port() {
245 assert_eq!(
246 <&EventId>::try_from("$39hvsi03hlne:example.com:notaport").unwrap_err(),
247 Error::InvalidServerName
248 );
249 }
250}