1#![warn(
6 missing_docs,
7 unused_import_braces,
8 unused_imports,
9 unused_qualifications
10)]
11#![deny(
12 missing_debug_implementations,
13 missing_copy_implementations,
14 trivial_casts,
15 trivial_numeric_casts,
16 unsafe_code,
17 unused_must_use
18)]
19
20#[macro_export]
25macro_rules! typed_string {
26 {
27 $(#[$meta:meta])*
28 $v:vis struct $ty:ident (String);
29
30 $(#[$meta_ref:meta])*
31 $v_ref:vis struct $ty_ref:ident (str);
32 } => {
33 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
34 #[repr(transparent)]
35 $(#[$meta])*
36 $v struct $ty(String);
37
38 impl $ty {
39 #[inline]
41 pub fn new<T: Into<String>>(raw: T) -> Self {
42 Self(raw.into())
43 }
44
45 #[inline]
47 pub fn into_inner(self) -> String {
48 self.0
49 }
50
51 #[inline]
53 pub fn as_str(&self) -> &str {
54 self.0.as_str()
55 }
56 }
57
58 impl From<String> for $ty {
59 #[inline]
60 fn from(kid: String) -> Self {
61 Self::new(kid)
62 }
63 }
64
65 impl From<&'_ str> for $ty {
66 #[inline]
67 fn from(kid: &str) -> Self {
68 Self::new(String::from(kid))
69 }
70 }
71
72 impl From<&'_ $ty_ref> for $ty {
73 #[inline]
74 fn from(kid: &$ty_ref) -> Self {
75 $ty::from(kid.as_str())
76 }
77 }
78
79 impl From<$ty> for String {
80 #[inline]
81 fn from(wrapper: $ty) -> Self {
82 wrapper.0
83 }
84 }
85
86 impl ::std::borrow::Borrow<$ty_ref> for $ty {
87 #[inline]
88 fn borrow(&self) -> &$ty_ref {
89 &self
90 }
91 }
92
93 impl ::std::ops::Deref for $ty {
94 type Target = $ty_ref;
95
96 #[inline]
97 fn deref(&self) -> &Self::Target {
98 $ty_ref::from_str(self.0.as_str())
99 }
100 }
101
102 impl AsRef<$ty_ref> for $ty {
103 #[inline]
104 fn as_ref(&self) -> &$ty_ref {
105 &self
106 }
107 }
108
109 impl<'a> ::std::fmt::Display for $ty {
110 #[inline]
111 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
112 f.write_str(self.as_str())
113 }
114 }
115
116 impl ::serde::Serialize for $ty {
117 fn serialize<S: ::serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
118 <String as ::serde::Serialize>::serialize(&self.0, serializer)
119 }
120 }
121
122 impl<'de> ::serde::Deserialize<'de> for $ty {
123 fn deserialize<D: ::serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
124 let raw = <String as ::serde::Deserialize<'de>>::deserialize(deserializer)?;
125 Ok(Self::new(raw))
126 }
127 }
128
129 #[derive(Debug, Hash, PartialEq, Eq)]
130 #[repr(transparent)]
131 $(#[$meta_ref])*
132 $v_ref struct $ty_ref(str);
133
134 impl $ty_ref {
135 #[allow(unsafe_code)]
136 #[inline]
137 pub fn from_str(raw: &str) -> &Self {
140 let ptr: *const str = raw;
141 unsafe {
144 &*(ptr as *const Self)
145 }
146 }
147
148 #[inline]
150 pub const fn as_str(&self) -> &str {
151 &self.0
152 }
153 }
154
155 impl ToOwned for $ty_ref {
156 type Owned = $ty;
157
158 #[inline]
159 fn to_owned(&self) -> Self::Owned {
160 $ty(self.0.to_owned())
161 }
162 }
163
164 impl AsRef<$ty_ref> for $ty_ref {
165 #[inline]
166 fn as_ref(&self) -> &$ty_ref {
167 self
168 }
169 }
170
171 impl PartialEq<$ty_ref> for $ty {
172 #[inline]
173 fn eq(&self, other: &$ty_ref) -> bool {
174 self.0 == &other.0
175 }
176 }
177
178 impl PartialEq<$ty> for $ty_ref {
179 #[inline]
180 fn eq(&self, other: &$ty) -> bool {
181 &self.0 == other.0
182 }
183 }
184
185 impl<'a> ::std::fmt::Display for &'a $ty_ref {
186 #[inline]
187 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
188 f.write_str(&self.0)
189 }
190 }
191
192 impl<'de: 'a, 'a> ::serde::Deserialize<'de> for &'a $ty_ref {
193 fn deserialize<D: ::serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
194 let raw = <&str as ::serde::Deserialize<'de>>::deserialize(deserializer)?;
195 Ok($ty_ref::from_str(raw))
196 }
197 }
198
199 impl<'a> ::serde::Serialize for &'a $ty_ref {
200 fn serialize<S: ::serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
201 <&str as ::serde::Serialize>::serialize(&self.as_str(), serializer)
202 }
203 }
204 }
205}
206
207#[cfg(doctest)]
208#[doc(hidden)]
209mod doctest {
210 typed_string! {
211 #[doc(hidden)]
212 pub struct Example(String);
213
214 #[doc(hidden)]
215 pub struct ExampleRef(str);
216 }
217
218 fn ref_from_str_does_not_extend_lifetimes() -> ! {
231 loop {}
232 }
233}