1use std::borrow::Borrow;
27use std::borrow::Cow;
28use std::fmt;
29use std::hash;
30use std::marker::PhantomData;
31use std::sync::Arc;
32
33pub struct Str<'k> {
35 value: *const str,
38 owner: StrOwner,
39 marker: PhantomData<&'k str>,
40}
41
42unsafe impl<'k> Send for Str<'k> {}
44unsafe impl<'k> Sync for Str<'k> {}
46
47impl<'k> Default for Str<'k> {
48 fn default() -> Self {
49 Str::new("")
50 }
51}
52
53enum StrOwner {
54 None,
55 Static(&'static str),
56 Box(*mut str),
57 Shared(Arc<str>),
58}
59
60impl<'k> fmt::Debug for Str<'k> {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 fmt::Debug::fmt(self.get(), f)
63 }
64}
65
66impl<'k> fmt::Display for Str<'k> {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 fmt::Display::fmt(self.get(), f)
69 }
70}
71
72impl<'k> Clone for Str<'k> {
73 fn clone(&self) -> Self {
74 match self.owner {
75 StrOwner::Box(_) => Str::new_owned(unsafe { &*self.value }),
76 StrOwner::Shared(ref value) => Str::new_shared(value.clone()),
77 StrOwner::Static(owner) => Str {
78 value: self.value,
79 owner: StrOwner::Static(owner),
80 marker: PhantomData,
81 },
82 StrOwner::None => Str {
83 value: self.value,
84 owner: StrOwner::None,
85 marker: PhantomData,
86 },
87 }
88 }
89}
90
91impl<'k> Drop for Str<'k> {
92 fn drop(&mut self) {
93 if let StrOwner::Box(boxed) = self.owner {
94 drop(unsafe { Box::from_raw(boxed) });
95 }
96
97 }
99}
100
101impl Str<'static> {
102 pub const fn new(k: &'static str) -> Self {
104 Str {
105 value: k as *const str,
106 owner: StrOwner::Static(k),
107 marker: PhantomData,
108 }
109 }
110
111 pub fn new_owned(key: impl Into<Box<str>>) -> Self {
115 let value = key.into();
116
117 let raw = Box::into_raw(value);
118
119 Str {
120 value: raw as *const str,
121 owner: StrOwner::Box(raw),
122 marker: PhantomData,
123 }
124 }
125
126 pub fn new_shared(key: impl Into<Arc<str>>) -> Self {
131 let value = key.into();
132
133 Str {
134 value: &*value as *const str,
135 owner: StrOwner::Shared(value),
136 marker: PhantomData,
137 }
138 }
139}
140
141impl<'k> Str<'k> {
142 pub const fn new_ref(k: &'k str) -> Str<'k> {
146 Str {
147 value: k as *const str,
148 owner: StrOwner::None,
149 marker: PhantomData,
150 }
151 }
152
153 pub fn new_cow_ref(key: Cow<'k, str>) -> Self {
158 match key {
159 Cow::Borrowed(key) => Str::new_ref(key),
160 Cow::Owned(key) => Str::new_owned(key),
161 }
162 }
163
164 pub const fn by_ref(&self) -> Str<'_> {
166 Str {
167 value: self.value,
168 owner: match self.owner {
169 StrOwner::Static(owner) => StrOwner::Static(owner),
170 _ => StrOwner::None,
171 },
172 marker: PhantomData,
173 }
174 }
175
176 pub const fn get(&self) -> &str {
178 unsafe { &(*self.value) }
183 }
184
185 pub const fn get_static(&self) -> Option<&'static str> {
190 if let StrOwner::Static(owner) = self.owner {
191 Some(owner)
192 } else {
193 None
194 }
195 }
196
197 pub fn to_cow(&self) -> Cow<'static, str> {
202 match self.owner {
203 StrOwner::Static(key) => Cow::Borrowed(key),
204 _ => Cow::Owned(self.get().to_owned()),
205 }
206 }
207
208 pub fn to_shared(&self) -> Str<'static> {
213 match self.owner {
214 StrOwner::Static(owner) => Str::new(owner),
215 StrOwner::Shared(ref owner) => Str::new_shared(owner.clone()),
216 _ => Str::new_shared(self.get()),
217 }
218 }
219
220 pub fn to_owned(&self) -> Str<'static> {
226 match self.owner {
227 StrOwner::Static(owner) => Str::new(owner),
228 StrOwner::Shared(ref owner) => Str::new_shared(owner.clone()),
229 _ => Str::new_owned(self.get()),
230 }
231 }
232
233 pub fn into_string(self) -> String {
238 match self.owner {
239 StrOwner::Box(boxed) => {
240 std::mem::forget(self);
243 unsafe { Box::from_raw(boxed) }.into()
244 }
245 _ => self.get().to_owned(),
246 }
247 }
248}
249
250impl<'a> hash::Hash for Str<'a> {
251 fn hash<H: hash::Hasher>(&self, state: &mut H) {
252 self.get().hash(state)
253 }
254}
255
256impl std::ops::Deref for Str<'_> {
257 type Target = str;
258
259 fn deref(&self) -> &Self::Target {
260 self.get()
261 }
262}
263
264impl<'a, 'b> PartialEq<Str<'b>> for Str<'a> {
265 fn eq(&self, other: &Str<'b>) -> bool {
266 self.get() == other.get()
267 }
268}
269
270impl<'a> Eq for Str<'a> {}
271
272impl<'a> PartialEq<str> for Str<'a> {
273 fn eq(&self, other: &str) -> bool {
274 self.get() == other
275 }
276}
277
278impl<'a> PartialEq<Str<'a>> for str {
279 fn eq(&self, other: &Str<'a>) -> bool {
280 self == other.get()
281 }
282}
283
284impl<'a, 'b> PartialEq<&'b str> for Str<'a> {
285 fn eq(&self, other: &&'b str) -> bool {
286 self.get() == *other
287 }
288}
289
290impl<'b> PartialEq<Str<'b>> for &str {
291 fn eq(&self, other: &Str<'b>) -> bool {
292 *self == other.get()
293 }
294}
295
296impl<'a, 'b> PartialOrd<Str<'b>> for Str<'a> {
297 fn partial_cmp(&self, other: &Str<'b>) -> Option<core::cmp::Ordering> {
298 self.get().partial_cmp(other.get())
299 }
300}
301
302impl<'a> Ord for Str<'a> {
303 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
304 self.get().cmp(other.get())
305 }
306}
307
308impl<'k> Borrow<str> for Str<'k> {
309 fn borrow(&self) -> &str {
310 self.get()
311 }
312}
313
314impl<'k> AsRef<str> for Str<'k> {
315 fn as_ref(&self) -> &str {
316 self.get()
317 }
318}
319
320pub trait ToStr {
322 fn to_str(&self) -> Str<'_>;
324}
325
326impl<T: ToStr + ?Sized> ToStr for &T {
327 fn to_str(&self) -> Str<'_> {
328 (**self).to_str()
329 }
330}
331
332impl<'k> ToStr for Str<'k> {
333 fn to_str(&self) -> Str<'_> {
334 self.by_ref()
335 }
336}
337
338impl ToStr for str {
339 fn to_str(&self) -> Str<'_> {
340 Str::new_ref(self)
341 }
342}
343
344impl ToStr for String {
345 fn to_str(&self) -> Str<'_> {
346 Str::new_ref(self)
347 }
348}
349
350impl ToStr for Box<str> {
351 fn to_str(&self) -> Str<'_> {
352 Str::new_ref(self)
353 }
354}
355
356impl ToStr for Arc<str> {
357 fn to_str(&self) -> Str<'_> {
358 Str::new_shared(self.clone())
359 }
360}
361
362impl From<String> for Str<'static> {
363 fn from(value: String) -> Self {
364 Str::new_owned(value)
365 }
366}
367
368impl From<Box<str>> for Str<'static> {
369 fn from(value: Box<str>) -> Self {
370 Str::new_owned(value)
371 }
372}
373
374impl From<Arc<str>> for Str<'static> {
375 fn from(value: Arc<str>) -> Self {
376 Str::new_shared(value)
377 }
378}
379
380impl<'k> From<&'k String> for Str<'k> {
381 fn from(value: &'k String) -> Self {
382 Str::new_ref(value)
383 }
384}
385
386impl<'k> From<Str<'k>> for String {
387 fn from(value: Str<'k>) -> String {
388 value.into_string()
389 }
390}
391
392impl<'a> From<&'a str> for Str<'a> {
393 fn from(value: &'a str) -> Self {
394 Str::new_ref(value)
395 }
396}
397
398impl<'a, 'b> From<&'a Str<'b>> for Str<'a> {
399 fn from(value: &'a Str<'b>) -> Self {
400 value.by_ref()
401 }
402}