ruma_identifiers/
macros.rs1macro_rules! doc_concat {
5 ( $( #[doc = $doc:expr] $( $thing:tt )* )* ) => ( $( #[doc = $doc] $( $thing )* )* );
6}
7
8macro_rules! partial_eq_string {
9 ($id:ty $([$( $g:ident ),*])?) => {
10 partial_eq_string!(@imp $(<$($g),*>)?, $id, str);
11 partial_eq_string!(@imp $(<$($g),*>)?, $id, &str);
12 partial_eq_string!(@imp $(<$($g),*>)?, $id, String);
13 partial_eq_string!(@imp $(<$($g),*>)?, str, $id);
14 partial_eq_string!(@imp $(<$($g),*>)?, &str, $id);
15 partial_eq_string!(@imp $(<$($g),*>)?, String, $id);
16 };
17 (@imp $(<$( $g:ident ),*>)?, $l:ty, $r:ty) => {
18 impl $(<$($g),*>)? PartialEq<$r> for $l {
19 fn eq(&self, other: &$r) -> bool {
20 AsRef::<str>::as_ref(self)
21 == AsRef::<str>::as_ref(other)
22 }
23 }
24 }
25}
26
27macro_rules! opaque_identifier_common_impls {
28 ($id:ty) => {
29 impl $id {
30 pub(super) fn from_borrowed(s: &str) -> &Self {
31 unsafe { std::mem::transmute(s) }
32 }
33
34 pub(super) fn from_owned(s: Box<str>) -> Box<Self> {
35 unsafe { Box::from_raw(Box::into_raw(s) as _) }
36 }
37
38 pub(super) fn from_rc(s: std::rc::Rc<str>) -> std::rc::Rc<Self> {
39 unsafe { std::rc::Rc::from_raw(std::rc::Rc::into_raw(s) as _) }
40 }
41
42 pub(super) fn from_arc(s: std::sync::Arc<str>) -> std::sync::Arc<Self> {
43 unsafe { std::sync::Arc::from_raw(std::sync::Arc::into_raw(s) as _) }
44 }
45
46 pub(super) fn into_owned(self: Box<Self>) -> Box<str> {
47 unsafe { Box::from_raw(Box::into_raw(self) as _) }
48 }
49
50 doc_concat! {
51 #[doc = concat!("Creates a string slice from this `", stringify!($id), "`.")]
52 pub fn as_str(&self) -> &str {
53 &self.0
54 }
55 }
56
57 doc_concat! {
58 #[doc = concat!("Creates a byte slice from this `", stringify!($id), "`.")]
59 pub fn as_bytes(&self) -> &[u8] {
60 self.0.as_bytes()
61 }
62 }
63 }
64
65 impl Clone for Box<$id> {
66 fn clone(&self) -> Self {
67 (**self).to_owned()
68 }
69 }
70
71 impl ToOwned for $id {
72 type Owned = Box<$id>;
73
74 fn to_owned(&self) -> Self::Owned {
75 Self::from_owned(self.0.into())
76 }
77 }
78
79 impl AsRef<str> for $id {
80 fn as_ref(&self) -> &str {
81 self.as_str()
82 }
83 }
84
85 impl AsRef<str> for Box<$id> {
86 fn as_ref(&self) -> &str {
87 self.as_str()
88 }
89 }
90
91 impl From<&$id> for Box<$id> {
92 fn from(id: &$id) -> Self {
93 id.to_owned()
94 }
95 }
96
97 impl From<&$id> for std::rc::Rc<$id> {
98 fn from(s: &$id) -> std::rc::Rc<$id> {
99 let rc = std::rc::Rc::<str>::from(s.as_str());
100 <$id>::from_rc(rc)
101 }
102 }
103
104 impl From<&$id> for std::sync::Arc<$id> {
105 fn from(s: &$id) -> std::sync::Arc<$id> {
106 let arc = std::sync::Arc::<str>::from(s.as_str());
107 <$id>::from_arc(arc)
108 }
109 }
110
111 impl PartialEq<$id> for Box<$id> {
112 fn eq(&self, other: &$id) -> bool {
113 self.as_str() == other.as_str()
114 }
115 }
116
117 impl PartialEq<&'_ $id> for Box<$id> {
118 fn eq(&self, other: &&$id) -> bool {
119 self.as_str() == other.as_str()
120 }
121 }
122
123 impl PartialEq<Box<$id>> for $id {
124 fn eq(&self, other: &Box<$id>) -> bool {
125 self.as_str() == other.as_str()
126 }
127 }
128
129 impl PartialEq<Box<$id>> for &'_ $id {
130 fn eq(&self, other: &Box<$id>) -> bool {
131 self.as_str() == other.as_str()
132 }
133 }
134
135 impl std::fmt::Debug for $id {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 <str as std::fmt::Debug>::fmt(self.as_str(), f)
138 }
139 }
140
141 impl std::fmt::Display for $id {
142 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143 write!(f, "{}", self.as_str())
144 }
145 }
146
147 #[cfg(feature = "serde")]
148 impl serde::Serialize for $id {
149 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
150 where
151 S: serde::Serializer,
152 {
153 serializer.serialize_str(self.as_str())
154 }
155 }
156
157 partial_eq_string!($id);
158 partial_eq_string!(Box<$id>);
159 };
160}
161
162macro_rules! opaque_identifier {
163 ($id:ident) => {
164 opaque_identifier_common_impls!($id);
165
166 impl<'a> From<&'a str> for &'a $id {
167 fn from(s: &'a str) -> Self {
168 $id::from_borrowed(s)
169 }
170 }
171
172 impl From<&str> for Box<$id> {
173 fn from(s: &str) -> Self {
174 $id::from_owned(s.into())
175 }
176 }
177
178 impl From<Box<str>> for Box<$id> {
179 fn from(s: Box<str>) -> Self {
180 $id::from_owned(s)
181 }
182 }
183
184 impl From<String> for Box<$id> {
185 fn from(s: String) -> Self {
186 $id::from_owned(s.into())
187 }
188 }
189
190 impl From<Box<$id>> for Box<str> {
191 fn from(id: Box<$id>) -> Self {
192 id.into_owned()
193 }
194 }
195
196 impl From<Box<$id>> for String {
197 fn from(id: Box<$id>) -> Self {
198 id.into_owned().into()
199 }
200 }
201
202 #[cfg(feature = "serde")]
203 impl<'de> serde::Deserialize<'de> for Box<$id> {
204 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
205 where
206 D: serde::Deserializer<'de>,
207 {
208 Box::<str>::deserialize(deserializer).map($id::from_owned)
209 }
210 }
211 };
212}
213
214macro_rules! opaque_identifier_validated {
215 ($id:ident, $validate_id:expr) => {
216 impl $id {
217 #[rustfmt::skip]
218 doc_concat! {
219 #[doc = concat!("\
220 Try parsing a `&str` into a `Box<", stringify!($id), ">`.\n\
221 \n\
222 The same can also be done using `FromStr`, `TryFrom` or `TryInto`.\n\
223 This function is simply more constrained and thus useful in generic contexts.\
224 ")]
225 pub fn parse(
226 s: impl AsRef<str> + Into<Box<str>>,
227 ) -> Result<Box<Self>, crate::Error> {
228 $validate_id(s.as_ref())?;
229 Ok($id::from_owned(s.into()))
230 }
231 }
232
233 doc_concat! {
234 #[doc = concat!("Try parsing a `&str` into an `Rc<", stringify!($id), ">`.")]
235 pub fn parse_rc(
236 s: impl AsRef<str> + Into<std::rc::Rc<str>>,
237 ) -> Result<std::rc::Rc<Self>, crate::Error> {
238 $validate_id(s.as_ref())?;
239 Ok($id::from_rc(s.into()))
240 }
241 }
242
243 doc_concat! {
244 #[doc = concat!("Try parsing a `&str` into an `Arc<", stringify!($id), ">`.")]
245 pub fn parse_arc(
246 s: impl AsRef<str> + Into<std::sync::Arc<str>>,
247 ) -> Result<std::sync::Arc<Self>, crate::Error> {
248 $validate_id(s.as_ref())?;
249 Ok($id::from_arc(s.into()))
250 }
251 }
252 }
253
254 opaque_identifier_common_impls!($id);
255
256 impl From<Box<$id>> for String {
257 fn from(id: Box<$id>) -> Self {
258 id.into_owned().into()
259 }
260 }
261
262 #[cfg(feature = "serde")]
263 impl<'de> serde::Deserialize<'de> for Box<$id> {
264 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
265 where
266 D: serde::Deserializer<'de>,
267 {
268 use serde::de::Error;
269
270 let s = String::deserialize(deserializer)?;
271
272 match $id::parse(s) {
273 Ok(o) => Ok(o),
274 Err(e) => Err(D::Error::custom(e)),
275 }
276 }
277 }
278
279 impl<'a> std::convert::TryFrom<&'a str> for &'a $id {
280 type Error = crate::Error;
281
282 fn try_from(s: &'a str) -> Result<Self, Self::Error> {
283 $validate_id(s)?;
284 Ok($id::from_borrowed(s))
285 }
286 }
287
288 impl std::str::FromStr for Box<$id> {
289 type Err = crate::Error;
290
291 fn from_str(s: &str) -> Result<Self, Self::Err> {
292 $id::parse(s)
293 }
294 }
295
296 impl std::convert::TryFrom<&str> for Box<$id> {
297 type Error = crate::Error;
298
299 fn try_from(s: &str) -> Result<Self, Self::Error> {
300 $id::parse(s)
301 }
302 }
303
304 impl std::convert::TryFrom<String> for Box<$id> {
305 type Error = crate::Error;
306
307 fn try_from(s: String) -> Result<Self, Self::Error> {
308 $id::parse(s)
309 }
310 }
311 };
312}