cheetah_string/
cheetah_str.rs1use alloc::borrow::Cow;
2use alloc::string::{ParseError, String, ToString};
3use alloc::sync::Arc;
4use core::borrow::Borrow;
5use core::cmp::Ordering;
6use core::fmt;
7use core::hash::{Hash, Hasher};
8use core::ops::Deref;
9use core::str::{self, FromStr};
10
11use crate::CheetahString;
12
13const INLINE_CAPACITY: usize = 23;
14
15#[derive(Clone)]
22pub struct CheetahStr {
23 inner: Repr,
24}
25
26#[derive(Clone)]
27enum Repr {
28 Inline {
29 len: u8,
30 data: [u8; INLINE_CAPACITY],
31 },
32 Static(&'static str),
33 Shared(Arc<str>),
34}
35
36impl CheetahStr {
37 #[inline]
39 pub const fn empty() -> Self {
40 Self {
41 inner: Repr::Inline {
42 len: 0,
43 data: [0; INLINE_CAPACITY],
44 },
45 }
46 }
47
48 #[inline]
50 pub fn new() -> Self {
51 Self::empty()
52 }
53
54 #[inline]
56 pub const fn from_static_str(s: &'static str) -> Self {
57 Self {
58 inner: Repr::Static(s),
59 }
60 }
61
62 #[inline]
64 pub fn from_slice(s: &str) -> Self {
65 if s.len() <= INLINE_CAPACITY {
66 let mut data = [0u8; INLINE_CAPACITY];
67 data[..s.len()].copy_from_slice(s.as_bytes());
68 Self {
69 inner: Repr::Inline {
70 len: s.len() as u8,
71 data,
72 },
73 }
74 } else {
75 Self {
76 inner: Repr::Shared(Arc::from(s)),
77 }
78 }
79 }
80
81 #[inline]
83 pub fn from_string(s: String) -> Self {
84 if s.len() <= INLINE_CAPACITY {
85 Self::from_slice(&s)
86 } else {
87 Self {
88 inner: Repr::Shared(s.into_boxed_str().into()),
89 }
90 }
91 }
92
93 #[inline]
95 pub fn as_str(&self) -> &str {
96 match &self.inner {
97 Repr::Inline { len, data } => {
98 unsafe { str::from_utf8_unchecked(&data[..*len as usize]) }
100 }
101 Repr::Static(s) => s,
102 Repr::Shared(s) => s.as_ref(),
103 }
104 }
105
106 #[inline]
108 pub fn as_bytes(&self) -> &[u8] {
109 self.as_str().as_bytes()
110 }
111
112 #[inline]
114 pub fn len(&self) -> usize {
115 self.as_str().len()
116 }
117
118 #[inline]
120 pub fn is_empty(&self) -> bool {
121 self.as_str().is_empty()
122 }
123}
124
125impl Default for CheetahStr {
126 #[inline]
127 fn default() -> Self {
128 Self::empty()
129 }
130}
131
132impl From<&str> for CheetahStr {
133 #[inline]
134 fn from(value: &str) -> Self {
135 Self::from_slice(value)
136 }
137}
138
139impl From<String> for CheetahStr {
140 #[inline]
141 fn from(value: String) -> Self {
142 Self::from_string(value)
143 }
144}
145
146impl From<Cow<'static, str>> for CheetahStr {
147 #[inline]
148 fn from(value: Cow<'static, str>) -> Self {
149 match value {
150 Cow::Borrowed(s) => Self::from_static_str(s),
151 Cow::Owned(s) => Self::from_string(s),
152 }
153 }
154}
155
156impl From<&CheetahString> for CheetahStr {
157 #[inline]
158 fn from(value: &CheetahString) -> Self {
159 Self::from_slice(value.as_str())
160 }
161}
162
163impl From<CheetahString> for CheetahStr {
164 #[inline]
165 fn from(value: CheetahString) -> Self {
166 Self::from_string(String::from(value))
167 }
168}
169
170impl From<CheetahStr> for String {
171 #[inline]
172 fn from(value: CheetahStr) -> Self {
173 value.as_str().to_string()
174 }
175}
176
177impl FromStr for CheetahStr {
178 type Err = ParseError;
179
180 #[inline]
181 fn from_str(s: &str) -> Result<Self, Self::Err> {
182 Ok(Self::from_slice(s))
183 }
184}
185
186impl Deref for CheetahStr {
187 type Target = str;
188
189 #[inline]
190 fn deref(&self) -> &Self::Target {
191 self.as_str()
192 }
193}
194
195impl AsRef<str> for CheetahStr {
196 #[inline]
197 fn as_ref(&self) -> &str {
198 self.as_str()
199 }
200}
201
202impl AsRef<[u8]> for CheetahStr {
203 #[inline]
204 fn as_ref(&self) -> &[u8] {
205 self.as_bytes()
206 }
207}
208
209impl Borrow<str> for CheetahStr {
210 #[inline]
211 fn borrow(&self) -> &str {
212 self.as_str()
213 }
214}
215
216impl fmt::Display for CheetahStr {
217 #[inline]
218 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
219 self.as_str().fmt(f)
220 }
221}
222
223impl fmt::Debug for CheetahStr {
224 #[inline]
225 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
226 fmt::Debug::fmt(self.as_str(), f)
227 }
228}
229
230impl Hash for CheetahStr {
231 #[inline]
232 fn hash<H: Hasher>(&self, state: &mut H) {
233 self.as_str().hash(state);
234 }
235}
236
237impl PartialEq for CheetahStr {
238 #[inline]
239 fn eq(&self, other: &Self) -> bool {
240 self.as_str() == other.as_str()
241 }
242}
243
244impl PartialEq<str> for CheetahStr {
245 #[inline]
246 fn eq(&self, other: &str) -> bool {
247 self.as_str() == other
248 }
249}
250
251impl PartialEq<&str> for CheetahStr {
252 #[inline]
253 fn eq(&self, other: &&str) -> bool {
254 self.as_str() == *other
255 }
256}
257
258impl PartialEq<CheetahStr> for str {
259 #[inline]
260 fn eq(&self, other: &CheetahStr) -> bool {
261 self == other.as_str()
262 }
263}
264
265impl PartialEq<CheetahStr> for &str {
266 #[inline]
267 fn eq(&self, other: &CheetahStr) -> bool {
268 *self == other.as_str()
269 }
270}
271
272impl Eq for CheetahStr {}
273
274impl PartialOrd for CheetahStr {
275 #[inline]
276 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
277 Some(self.cmp(other))
278 }
279}
280
281impl Ord for CheetahStr {
282 #[inline]
283 fn cmp(&self, other: &Self) -> Ordering {
284 self.as_str().cmp(other.as_str())
285 }
286}