diff options
Diffstat (limited to 'src/smol_str.rs')
-rw-r--r-- | src/smol_str.rs | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/src/smol_str.rs b/src/smol_str.rs new file mode 100644 index 000000000..2a330c343 --- /dev/null +++ b/src/smol_str.rs | |||
@@ -0,0 +1,60 @@ | |||
1 | use std::{sync::Arc}; | ||
2 | |||
3 | const INLINE_CAP: usize = 22; | ||
4 | |||
5 | #[derive(Clone, Debug)] | ||
6 | pub(crate) enum SmolStr { | ||
7 | Heap(Arc<str>), | ||
8 | Inline { | ||
9 | len: u8, | ||
10 | buf: [u8; INLINE_CAP], | ||
11 | }, | ||
12 | } | ||
13 | |||
14 | impl SmolStr { | ||
15 | pub fn new(text: &str) -> SmolStr { | ||
16 | let len = text.len(); | ||
17 | if len <= INLINE_CAP { | ||
18 | let mut buf = [0; INLINE_CAP]; | ||
19 | buf[..len].copy_from_slice(text.as_bytes()); | ||
20 | SmolStr::Inline { len: len as u8, buf } | ||
21 | } else { | ||
22 | SmolStr::Heap( | ||
23 | text.to_string().into_boxed_str().into() | ||
24 | ) | ||
25 | } | ||
26 | } | ||
27 | |||
28 | pub fn as_str(&self) -> &str { | ||
29 | match self { | ||
30 | SmolStr::Heap(data) => &*data, | ||
31 | SmolStr::Inline { len, buf } => { | ||
32 | let len = *len as usize; | ||
33 | let buf = &buf[..len]; | ||
34 | unsafe { ::std::str::from_utf8_unchecked(buf) } | ||
35 | } | ||
36 | } | ||
37 | } | ||
38 | } | ||
39 | |||
40 | #[cfg(test)] | ||
41 | mod tests { | ||
42 | use super::*; | ||
43 | |||
44 | #[test] | ||
45 | #[cfg(target_pointer_width = "64")] | ||
46 | fn smol_str_is_smol() { | ||
47 | assert_eq!(::std::mem::size_of::<SmolStr>(), 8 + 8 + 8) | ||
48 | } | ||
49 | |||
50 | #[test] | ||
51 | fn test_round_trip() { | ||
52 | let mut text = String::new(); | ||
53 | for n in 0..256 { | ||
54 | let smol = SmolStr::new(&text); | ||
55 | assert_eq!(smol.as_str(), text.as_str()); | ||
56 | text.push_str(&n.to_string()); | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | |||