1use {
2 ::core::{
3 borrow::Borrow,
4 convert::AsRef,
5 ffi::CStr,
6 fmt::{self, Debug, Display},
7 hash::Hash,
8 ops::Deref,
9 },
10 ::std::ffi::CString,
11};
12
13#[derive(Eq, Copy, Clone, PartialOrd, Ord)]
15pub struct IStr(pub(super) &'static str);
16
17#[inline]
26pub fn collect_interned_strings<B>() -> B
27where
28 B: ::core::iter::FromIterator<IStr>,
29{
30 crate::interner::THE_INTERNER.collect_interned_strings()
31}
32
33macro_rules! intern_doc {() => {
36r"Intern a new string, or return the extant [`IStr`] if one exists
37
38This operation may be slow, depending on whether the string has been previously
39interned."
40};}
41#[doc = intern_doc!()]
42#[inline]
43pub fn intern(s: &str) -> IStr {
44 crate::interner::THE_INTERNER.intern(s)
45}
46
47#[inline]
53pub fn get_interned(s: &str) -> Option<IStr> {
54 crate::interner::THE_INTERNER.get_interned(s)
55}
56
57impl IStr {
58 #[doc = intern_doc!()]
59 #[inline]
60 pub fn new(s: &str) -> Self {
61 intern(s)
62 }
63}
64
65impl From<&str> for IStr {
66 #[doc = intern_doc!()]
67 #[inline]
68 fn from(s: &str) -> Self {
69 intern(s)
70 }
71}
72
73impl From<String> for IStr {
74 #[doc = intern_doc!()]
75 #[inline]
76 fn from(s: String) -> Self {
77 intern(&s)
78 }
79}
80
81impl From<&String> for IStr {
82 #[doc = intern_doc!()]
83 #[inline]
84 fn from(s: &String) -> Self {
85 intern(s)
86 }
87}
88
89impl TryFrom<&CStr> for IStr {
90 type Error = ::core::str::Utf8Error;
91
92 #[doc = intern_doc!()]
93 #[inline]
94 fn try_from(c: &CStr) -> Result<Self, Self::Error> {
95 let s = c.to_str()?;
96 Ok(intern(s))
97 }
98}
99
100impl TryFrom<CString> for IStr {
101 type Error = ::core::str::Utf8Error;
102
103 #[doc = intern_doc!()]
104 #[inline]
105 fn try_from(c: CString) -> Result<Self, Self::Error> {
106 let s = c.to_str()?;
107 Ok(intern(s))
108 }
109}
110
111impl TryFrom<&CString> for IStr {
112 type Error = ::core::str::Utf8Error;
113
114 #[doc = intern_doc!()]
115 #[inline]
116 fn try_from(c: &CString) -> Result<Self, Self::Error> {
117 let s = c.to_str()?;
118 Ok(intern(s))
119 }
120}
121
122impl Deref for IStr {
125 type Target = str;
126
127 #[inline]
128 fn deref(&self) -> &str {
129 self.0
130 }
131}
132
133impl AsRef<str> for IStr {
134 #[inline]
135 fn as_ref(&self) -> &str {
136 self.0
137 }
138}
139
140impl AsRef<CStr> for IStr {
141 #[inline]
142 fn as_ref(&self) -> &CStr {
143 self.as_c_str()
144 }
145}
146
147impl Borrow<str> for IStr {
148 #[inline]
149 fn borrow(&self) -> &'static str {
150 self.0
151 }
152}
153
154impl IStr {
155 #[inline]
157 pub fn as_str(&self) -> &'static str {
158 self.0
159 }
160
161 #[inline]
163 pub fn as_c_str(&self) -> &'static CStr {
164 let ptr = self.0.as_ptr();
165 unsafe { CStr::from_ptr(ptr as _) }
167 }
168}
169
170impl From<IStr> for &'static str {
171 #[inline]
172 fn from(i: IStr) -> &'static str {
173 i.as_str()
174 }
175}
176
177impl From<IStr> for &'static CStr {
178 #[inline]
179 fn from(i: IStr) -> &'static CStr {
180 i.as_c_str()
181 }
182}
183
184impl From<IStr> for String {
185 #[inline]
186 fn from(s: IStr) -> String {
187 s.0.to_owned()
188 }
189}
190
191impl From<IStr> for CString {
192 #[inline]
193 fn from(s: IStr) -> CString {
194 s.as_c_str().to_owned()
195 }
196}
197
198impl IStr {
199 #[inline]
201 pub fn to_c_string(&self) -> CString {
202 self.as_c_str().to_owned()
203 }
204}
205
206impl Display for IStr {
208 #[inline]
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 f.write_str(self.0)
211 }
212}
213
214impl Debug for IStr {
215 #[inline]
216 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217 f.write_fmt(format_args!("IStr(\"{}\")", self.0))
218 }
219}
220
221impl PartialEq for IStr {
225 #[inline]
227 fn eq(&self, rhs: &IStr) -> bool {
228 ::core::ptr::eq(self.0.as_ptr(), rhs.0.as_ptr())
232 }
233}
234
235impl PartialEq<&str> for IStr {
237 #[inline]
239 fn eq(&self, other: &&str) -> bool {
240 self.0 == *other
241 }
242}
243impl PartialEq<IStr> for &str {
244 #[inline]
246 fn eq(&self, other: &IStr) -> bool {
247 *self == other.0
248 }
249}
250
251impl PartialEq<&CStr> for IStr {
253 #[inline]
255 fn eq(&self, other: &&CStr) -> bool {
256 self.as_c_str() == *other
257 }
258}
259impl PartialEq<IStr> for &CStr {
260 #[inline]
262 fn eq(&self, other: &IStr) -> bool {
263 *self == other.as_c_str()
264 }
265}
266
267impl PartialEq<String> for IStr {
269 #[inline]
271 fn eq(&self, other: &String) -> bool {
272 self.0 == other
273 }
274}
275impl PartialEq<IStr> for String {
276 #[inline]
278 fn eq(&self, other: &IStr) -> bool {
279 self == other.0
280 }
281}
282impl PartialEq<&String> for IStr {
283 #[inline]
285 fn eq(&self, other: &&String) -> bool {
286 self.0 == *other
287 }
288}
289impl PartialEq<IStr> for &String {
290 #[inline]
292 fn eq(&self, other: &IStr) -> bool {
293 *self == other.0
294 }
295}
296
297impl PartialEq<CString> for IStr {
299 #[inline]
301 fn eq(&self, other: &CString) -> bool {
302 let o: &CStr = other;
303 self.as_c_str() == o
304 }
305}
306impl PartialEq<IStr> for CString {
307 #[inline]
309 fn eq(&self, other: &IStr) -> bool {
310 let s: &CStr = self;
311 s == other.as_c_str()
312 }
313}
314impl PartialEq<&CString> for IStr {
315 #[inline]
317 fn eq(&self, other: &&CString) -> bool {
318 let o: &CStr = other;
319 self.as_c_str() == o
320 }
321}
322impl PartialEq<IStr> for &CString {
323 #[inline]
325 fn eq(&self, other: &IStr) -> bool {
326 let s: &CStr = self;
327 s == other.as_c_str()
328 }
329}
330
331impl Hash for IStr {
334 #[inline]
336 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
337 self.as_str().hash(state);
338 }
339}
340
341impl IStr {
342 #[inline]
350 pub fn wyhash(&self) -> u64 {
351 use crate::interner::SIZE_OF_WYHASH;
352 let hash_array: &[u8; SIZE_OF_WYHASH] = unsafe {
355 let hash_ptr = self.0.as_ptr().sub(SIZE_OF_WYHASH);
356 &*(hash_ptr as *const [u8; SIZE_OF_WYHASH])
357 };
358 u64::from_ne_bytes(*hash_array)
359 }
360}