1#![allow(unsafe_code)]
2
3use std::borrow::{Borrow, Cow};
6use std::hash::{Hash, Hasher};
7use std::marker::PhantomData;
8use std::ops::Deref;
9use std::ptr::NonNull;
10use std::{fmt, str};
11
12#[derive(Copy, Clone)]
18pub struct Str<'de> {
19 ptr: NonNull<u8>,
20 len: usize,
21 _marker: PhantomData<&'de str>,
22}
23
24const _: () = assert!(std::mem::size_of::<Str<'_>>() == 16);
25
26unsafe impl Send for Str<'_> {}
28unsafe impl Sync for Str<'_> {}
29
30impl Deref for Str<'_> {
31 type Target = str;
32
33 #[inline]
34 fn deref(&self) -> &str {
35 unsafe {
36 let slice = std::slice::from_raw_parts(self.ptr.as_ptr(), self.len);
37 str::from_utf8_unchecked(slice)
38 }
39 }
40}
41
42impl AsRef<str> for Str<'_> {
43 #[inline]
44 fn as_ref(&self) -> &str {
45 self
46 }
47}
48
49impl Borrow<str> for Str<'_> {
50 #[inline]
51 fn borrow(&self) -> &str {
52 self
53 }
54}
55
56impl fmt::Display for Str<'_> {
57 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58 f.write_str(self)
59 }
60}
61
62impl fmt::Debug for Str<'_> {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 fmt::Debug::fmt(&**self, f)
65 }
66}
67
68impl PartialEq for Str<'_> {
69 #[inline]
70 fn eq(&self, other: &Self) -> bool {
71 **self == **other
72 }
73}
74
75impl Eq for Str<'_> {}
76
77impl PartialOrd for Str<'_> {
78 #[inline]
79 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
80 Some(self.cmp(other))
81 }
82}
83
84impl Ord for Str<'_> {
85 #[inline]
86 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
87 (**self).cmp(&**other)
88 }
89}
90
91impl PartialEq<str> for Str<'_> {
92 #[inline]
93 fn eq(&self, other: &str) -> bool {
94 **self == *other
95 }
96}
97
98impl PartialEq<&str> for Str<'_> {
99 #[inline]
100 fn eq(&self, other: &&str) -> bool {
101 **self == **other
102 }
103}
104
105impl Hash for Str<'_> {
106 #[inline]
107 fn hash<H: Hasher>(&self, state: &mut H) {
108 (**self).hash(state);
109 }
110}
111
112impl Default for Str<'_> {
113 #[inline]
114 fn default() -> Self {
115 Self::from_borrowed("")
116 }
117}
118
119impl<'de> Str<'de> {
120 pub fn as_str(&self) -> &'de str {
122 unsafe {
123 let slice = std::slice::from_raw_parts(self.ptr.as_ptr(), self.len);
124 str::from_utf8_unchecked(slice)
125 }
126 }
127
128 #[inline]
129 pub(crate) fn from_borrowed(s: &'de str) -> Self {
130 let ptr = unsafe { NonNull::new_unchecked(s.as_ptr() as *mut u8) };
132 Self {
133 ptr,
134 len: s.len(),
135 _marker: PhantomData,
136 }
137 }
138
139 pub fn into_boxed_str(self) -> Box<str> {
141 (&*self).into()
142 }
143}
144
145impl<'de> From<&'de str> for Str<'de> {
146 #[inline]
147 fn from(s: &'de str) -> Self {
148 Self::from_borrowed(s)
149 }
150}
151
152impl<'de> From<Str<'de>> for Cow<'de, str> {
153 #[inline]
154 fn from(s: Str<'de>) -> Self {
155 let borrowed: &'de str =
157 unsafe { str::from_utf8_unchecked(std::slice::from_raw_parts(s.ptr.as_ptr(), s.len)) };
158 Cow::Borrowed(borrowed)
159 }
160}
161
162impl From<Str<'_>> for Box<str> {
163 #[inline]
164 fn from(s: Str<'_>) -> Self {
165 (&*s).into()
166 }
167}
168
169impl From<Str<'_>> for String {
170 #[inline]
171 fn from(s: Str<'_>) -> Self {
172 (*s).to_owned()
173 }
174}
175
176#[cfg(test)]
177#[path = "./str_tests.rs"]
178mod tests;