xml_string/
macros.rs

1//! Macros.
2
3/// Implement `PartialEq` and `Eq` for the given types.
4macro_rules! impl_cmp {
5    ($ty_lhs:ty, $ty_rhs:ty) => {
6        impl PartialEq<$ty_rhs> for $ty_lhs {
7            #[inline]
8            fn eq(&self, o: &$ty_rhs) -> bool {
9                <str as PartialEq<str>>::eq(AsRef::as_ref(self), AsRef::as_ref(o))
10            }
11        }
12        impl PartialOrd<$ty_rhs> for $ty_lhs {
13            #[inline]
14            fn partial_cmp(&self, o: &$ty_rhs) -> Option<core::cmp::Ordering> {
15                <str as PartialOrd<str>>::partial_cmp(AsRef::as_ref(self), AsRef::as_ref(o))
16            }
17        }
18    };
19}
20
21/// Implement `PartialEq` and `Eq` symmetrically for the given types.
22macro_rules! impl_cmp_symmetric {
23    ($ty_lhs:ty, $ty_rhs:ty) => {
24        impl_cmp!($ty_lhs, $ty_rhs);
25        impl_cmp!($ty_rhs, $ty_lhs);
26    };
27}
28
29/// Implements std traits for a custom string slice type.
30///
31/// # Safety
32///
33/// `$custom_str` type should have the same memory layout as `str`.
34/// For example, this is safe when `$custom_str` is defined as
35/// `#[repr(transparent)] struct $custom_str(str);`.
36/// The caller of this macro is responsible to satisfy this condition.
37macro_rules! impl_traits_for_custom_string_slice {
38    ($custom_str:ty) => {
39        #[cfg(feature = "alloc")]
40        impl alloc::borrow::ToOwned for $custom_str {
41            type Owned = alloc::boxed::Box<$custom_str>;
42
43            fn to_owned(&self) -> Self::Owned {
44                From::from(self)
45            }
46        }
47
48        impl_cmp_symmetric!($custom_str, str);
49        impl_cmp_symmetric!($custom_str, &'_ str);
50        impl_cmp_symmetric!(&'_ $custom_str, str);
51
52        #[cfg(feature = "alloc")]
53        impl_cmp_symmetric!($custom_str, alloc::string::String);
54        #[cfg(feature = "alloc")]
55        impl_cmp_symmetric!($custom_str, &alloc::string::String);
56        #[cfg(feature = "alloc")]
57        impl_cmp_symmetric!($custom_str, alloc::boxed::Box<str>);
58        #[cfg(feature = "alloc")]
59        impl_cmp_symmetric!(alloc::boxed::Box<$custom_str>, str);
60        #[cfg(feature = "alloc")]
61        impl_cmp_symmetric!($custom_str, alloc::borrow::Cow<'_, str>);
62
63        impl AsRef<str> for $custom_str {
64            #[inline]
65            fn as_ref(&self) -> &str {
66                &self.0
67            }
68        }
69
70        #[cfg(feature = "alloc")]
71        impl AsRef<str> for alloc::boxed::Box<$custom_str> {
72            #[inline]
73            fn as_ref(&self) -> &str {
74                &(**self).0
75            }
76        }
77
78        impl AsRef<$custom_str> for $custom_str {
79            #[inline]
80            fn as_ref(&self) -> &$custom_str {
81                self
82            }
83        }
84
85        impl core::fmt::Debug for &$custom_str {
86            #[inline]
87            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
88                f.write_str(self.as_ref())
89            }
90        }
91
92        impl core::fmt::Display for &$custom_str {
93            #[inline]
94            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
95                f.write_str(self.as_ref())
96            }
97        }
98
99        #[cfg(feature = "alloc")]
100        impl From<&$custom_str> for alloc::boxed::Box<$custom_str> {
101            fn from(s: &$custom_str) -> Self {
102                use alloc::boxed::Box;
103
104                let inner = s.as_str();
105                let inner_boxed = Box::<str>::from(inner);
106                unsafe {
107                    // This is safe when `$custom_str` has the same memory layout as `str`.
108                    // For example, this is safe when `$custom_str` is defined as
109                    // `#[repr(transparent)] struct $custom_str(str);`.
110                    // The caller of this macro is responsible to satisfy this condition.
111                    Box::<$custom_str>::from_raw(
112                        Box::<str>::into_raw(inner_boxed) as *mut $custom_str
113                    )
114                }
115            }
116        }
117
118        #[cfg(feature = "alloc")]
119        impl From<&$custom_str> for alloc::rc::Rc<$custom_str> {
120            fn from(s: &$custom_str) -> Self {
121                use alloc::rc::Rc;
122
123                let inner = s.as_str();
124                let inner_boxed = Rc::<str>::from(inner);
125                unsafe {
126                    // This is safe when `$custom_str` has the same memory layout as `str`.
127                    // For example, this is safe when `$custom_str` is defined as
128                    // `#[repr(transparent)] struct $custom_str(str);`.
129                    // The caller of this macro is responsible to satisfy this condition.
130                    Rc::<$custom_str>::from_raw(
131                        Rc::<str>::into_raw(inner_boxed) as *const $custom_str
132                    )
133                }
134            }
135        }
136
137        #[cfg(feature = "alloc")]
138        impl From<&$custom_str> for alloc::sync::Arc<$custom_str> {
139            fn from(s: &$custom_str) -> Self {
140                use alloc::sync::Arc;
141
142                let inner = s.as_str();
143                let inner_boxed = Arc::<str>::from(inner);
144                unsafe {
145                    // This is safe when `$custom_str` has the same memory layout as `str`.
146                    // For example, this is safe when `$custom_str` is defined as
147                    // `#[repr(transparent)] struct $custom_str(str);`.
148                    // The caller of this macro is responsible to satisfy this condition.
149                    Arc::<$custom_str>::from_raw(
150                        Arc::<str>::into_raw(inner_boxed) as *const $custom_str
151                    )
152                }
153            }
154        }
155    };
156}