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