cheetah_string/
cheetah_string.rs1use core::fmt;
2use std::borrow::{Borrow, Cow};
3use std::cmp::Ordering;
4use std::fmt::Display;
5use std::hash::Hash;
6use std::ops::Deref;
7use std::str::FromStr;
8use std::sync::Arc;
9
10pub const EMPTY_STRING: &str = "";
11
12#[derive(Clone)]
13#[repr(transparent)]
14pub struct CheetahString {
15 pub(super) inner: InnerString,
16}
17
18impl Default for CheetahString {
19 fn default() -> Self {
20 CheetahString {
21 inner: InnerString::Empty,
22 }
23 }
24}
25
26impl From<String> for CheetahString {
27 #[inline]
28 fn from(s: String) -> Self {
29 CheetahString::from_string(s)
30 }
31}
32
33impl From<Arc<String>> for CheetahString {
34 #[inline]
35 fn from(s: Arc<String>) -> Self {
36 CheetahString::from_arc_string(s)
37 }
38}
39
40impl<'a> From<&'a str> for CheetahString {
41 #[inline]
42 fn from(s: &'a str) -> Self {
43 CheetahString::from_slice(s)
44 }
45}
46
47impl From<&[u8]> for CheetahString {
48 #[inline]
49 fn from(b: &[u8]) -> Self {
50 CheetahString::from_slice(unsafe { std::str::from_utf8_unchecked(b) })
51 }
52}
53
54impl FromStr for CheetahString {
55 type Err = std::string::ParseError;
56 #[inline]
57 fn from_str(s: &str) -> Result<Self, Self::Err> {
58 Ok(CheetahString::from_slice(s))
59 }
60}
61
62impl From<Vec<u8>> for CheetahString {
63 #[inline]
64 fn from(v: Vec<u8>) -> Self {
65 CheetahString::from_slice(unsafe { std::str::from_utf8_unchecked(&v) })
66 }
67}
68
69impl From<Cow<'static, str>> for CheetahString {
70 #[inline]
71 fn from(cow: Cow<'static, str>) -> Self {
72 match cow {
73 Cow::Borrowed(s) => CheetahString::from_static_str(s),
74 Cow::Owned(s) => CheetahString::from_string(s),
75 }
76 }
77}
78
79impl From<Cow<'_, String>> for CheetahString {
80 #[inline]
81 fn from(cow: Cow<'_, String>) -> Self {
82 match cow {
83 Cow::Borrowed(s) => CheetahString::from_slice(s),
84 Cow::Owned(s) => CheetahString::from_string(s),
85 }
86 }
87}
88
89impl From<char> for CheetahString {
90 #[inline]
100 fn from(c: char) -> Self {
101 CheetahString::from_string(c.to_string())
102 }
103}
104
105impl<'a> FromIterator<&'a char> for CheetahString {
106 #[inline]
107 fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> CheetahString {
108 let mut buf = String::new();
109 buf.extend(iter);
110 CheetahString::from_string(buf)
111 }
112}
113
114impl<'a> FromIterator<&'a str> for CheetahString {
115 fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> CheetahString {
116 let mut buf = String::new();
117 buf.extend(iter);
118 CheetahString::from_string(buf)
119 }
120}
121
122impl FromIterator<String> for CheetahString {
123 #[inline]
124 fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
125 let mut buf = String::new();
126 buf.extend(iter);
127 CheetahString::from_string(buf)
128 }
129}
130
131impl<'a> FromIterator<&'a String> for CheetahString {
132 #[inline]
133 fn from_iter<T: IntoIterator<Item = &'a String>>(iter: T) -> Self {
134 let mut buf = String::new();
135 buf.extend(iter.into_iter().map(|s| s.as_str()));
136 CheetahString::from_string(buf)
137 }
138}
139
140#[cfg(feature = "bytes")]
141impl From<bytes::Bytes> for CheetahString {
142 #[inline]
143 fn from(b: bytes::Bytes) -> Self {
144 CheetahString::from_bytes(b)
145 }
146}
147
148impl From<&CheetahString> for CheetahString {
149 #[inline]
150 fn from(s: &CheetahString) -> Self {
151 s.clone()
152 }
153}
154
155impl From<CheetahString> for String {
156 #[inline]
157 fn from(s: CheetahString) -> Self {
158 match s {
159 CheetahString {
160 inner: InnerString::ArcString(s),
161 } => s.as_ref().clone(),
162 CheetahString {
163 inner: InnerString::StaticStr(s),
164 } => s.to_string(),
165 CheetahString {
166 inner: InnerString::ArcVecString(s),
167 } => unsafe { String::from_utf8_unchecked(s.to_vec()) },
168 #[cfg(feature = "bytes")]
169 CheetahString {
170 inner: InnerString::Bytes(b),
171 } => unsafe { String::from_utf8_unchecked(b.to_vec()) },
172 CheetahString {
173 inner: InnerString::Empty,
174 } => String::new(),
175 }
176 }
177}
178
179impl Deref for CheetahString {
180 type Target = str;
181
182 #[inline]
183 fn deref(&self) -> &Self::Target {
184 self.as_str()
185 }
186}
187
188impl AsRef<str> for CheetahString {
189 #[inline]
190 fn as_ref(&self) -> &str {
191 self.as_str()
192 }
193}
194
195impl AsRef<[u8]> for CheetahString {
196 #[inline]
197 fn as_ref(&self) -> &[u8] {
198 self.as_bytes()
199 }
200}
201
202impl AsRef<CheetahString> for CheetahString {
203 #[inline]
204 fn as_ref(&self) -> &CheetahString {
205 self
206 }
207}
208
209impl From<&String> for CheetahString {
210 #[inline]
211 fn from(s: &String) -> Self {
212 CheetahString::from_slice(s)
213 }
214}
215
216impl CheetahString {
217 #[inline]
218 pub const fn empty() -> Self {
219 CheetahString {
220 inner: InnerString::Empty,
221 }
222 }
223
224 #[inline]
225 pub fn new() -> Self {
226 CheetahString::default()
227 }
228
229 #[inline]
230 pub const fn from_static_str(s: &'static str) -> Self {
231 CheetahString {
232 inner: InnerString::StaticStr(s),
233 }
234 }
235
236 #[inline]
237 pub fn from_vec(s: Vec<u8>) -> Self {
238 CheetahString {
239 inner: InnerString::ArcVecString(Arc::new(s)),
240 }
241 }
242
243 #[inline]
244 pub fn from_arc_vec(s: Arc<Vec<u8>>) -> Self {
245 CheetahString {
246 inner: InnerString::ArcVecString(s),
247 }
248 }
249
250 #[inline]
251 pub fn from_slice(s: &str) -> Self {
252 CheetahString {
253 inner: InnerString::ArcString(Arc::new(s.to_owned())),
254 }
255 }
256
257 #[inline]
258 pub fn from_string(s: String) -> Self {
259 CheetahString {
260 inner: InnerString::ArcString(Arc::new(s)),
261 }
262 }
263 #[inline]
264 pub fn from_arc_string(s: Arc<String>) -> Self {
265 CheetahString {
266 inner: InnerString::ArcString(s),
267 }
268 }
269
270 #[inline]
271 #[cfg(feature = "bytes")]
272 pub fn from_bytes(b: bytes::Bytes) -> Self {
273 CheetahString {
274 inner: InnerString::Bytes(b),
275 }
276 }
277
278 #[inline]
279 pub fn as_str(&self) -> &str {
280 match &self.inner {
281 InnerString::ArcString(s) => s.as_str(),
282 InnerString::StaticStr(s) => s,
283 InnerString::ArcVecString(s) => std::str::from_utf8(s.as_ref()).unwrap(),
284 #[cfg(feature = "bytes")]
285 InnerString::Bytes(b) => std::str::from_utf8(b.as_ref()).unwrap(),
286 InnerString::Empty => EMPTY_STRING,
287 }
288 }
289
290 #[inline]
291 pub fn as_bytes(&self) -> &[u8] {
292 match &self.inner {
293 InnerString::ArcString(s) => s.as_bytes(),
294 InnerString::StaticStr(s) => s.as_bytes(),
295 InnerString::ArcVecString(s) => s.as_ref(),
296 #[cfg(feature = "bytes")]
297 InnerString::Bytes(b) => b.as_ref(),
298 InnerString::Empty => &[],
299 }
300 }
301
302 #[inline]
303 pub fn len(&self) -> usize {
304 match &self.inner {
305 InnerString::ArcString(s) => s.len(),
306 InnerString::StaticStr(s) => s.len(),
307 InnerString::ArcVecString(s) => s.len(),
308 #[cfg(feature = "bytes")]
309 InnerString::Bytes(b) => b.len(),
310 InnerString::Empty => 0,
311 }
312 }
313
314 #[inline]
315 pub fn is_empty(&self) -> bool {
316 match &self.inner {
317 InnerString::ArcString(s) => s.is_empty(),
318 InnerString::StaticStr(s) => s.is_empty(),
319 InnerString::ArcVecString(s) => s.is_empty(),
320 #[cfg(feature = "bytes")]
321 InnerString::Bytes(b) => b.is_empty(),
322 InnerString::Empty => true,
323 }
324 }
325}
326
327impl PartialEq for CheetahString {
328 #[inline]
329 fn eq(&self, other: &Self) -> bool {
330 self.as_str() == other.as_str()
331 }
332}
333
334impl PartialEq<str> for CheetahString {
335 #[inline]
336 fn eq(&self, other: &str) -> bool {
337 self.as_str() == other
338 }
339}
340
341impl PartialEq<String> for CheetahString {
342 #[inline]
343 fn eq(&self, other: &String) -> bool {
344 self.as_str() == other.as_str()
345 }
346}
347
348impl PartialEq<Vec<u8>> for CheetahString {
349 #[inline]
350 fn eq(&self, other: &Vec<u8>) -> bool {
351 self.as_bytes() == other.as_slice()
352 }
353}
354
355impl<'a> PartialEq<&'a str> for CheetahString {
356 #[inline]
357 fn eq(&self, other: &&'a str) -> bool {
358 self.as_str() == *other
359 }
360}
361
362impl PartialEq<CheetahString> for str {
363 #[inline]
364 fn eq(&self, other: &CheetahString) -> bool {
365 self == other.as_str()
366 }
367}
368
369impl PartialEq<CheetahString> for String {
370 #[inline]
371 fn eq(&self, other: &CheetahString) -> bool {
372 self.as_str() == other.as_str()
373 }
374}
375
376impl PartialEq<CheetahString> for &str {
377 #[inline]
378 fn eq(&self, other: &CheetahString) -> bool {
379 *self == other.as_str()
380 }
381}
382
383impl Eq for CheetahString {}
384
385impl PartialOrd for CheetahString {
386 #[inline]
387 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
388 Some(self.cmp(other))
389 }
390}
391
392impl Ord for CheetahString {
393 #[inline]
394 fn cmp(&self, other: &Self) -> Ordering {
395 self.as_str().cmp(other.as_str())
396 }
397}
398
399impl Hash for CheetahString {
400 #[inline]
401 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
402 self.as_str().hash(state);
403 }
404}
405
406impl Display for CheetahString {
407 #[inline]
408 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
409 self.as_str().fmt(f)
410 }
411}
412
413impl std::fmt::Debug for CheetahString {
414 #[inline]
415 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
416 fmt::Debug::fmt(self.as_str(), f)
417 }
418}
419
420impl Borrow<str> for CheetahString {
421 #[inline]
422 fn borrow(&self) -> &str {
423 self.as_str()
424 }
425}
426
427#[derive(Clone)]
436pub(super) enum InnerString {
437 ArcString(Arc<String>),
438 StaticStr(&'static str),
439 ArcVecString(Arc<Vec<u8>>),
440 #[cfg(feature = "bytes")]
441 Bytes(bytes::Bytes),
442 Empty,
443}