aboutsummaryrefslogtreecommitdiff
path: root/src/smol_str.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/smol_str.rs')
-rw-r--r--src/smol_str.rs60
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 @@
1use std::{sync::Arc};
2
3const INLINE_CAP: usize = 22;
4
5#[derive(Clone, Debug)]
6pub(crate) enum SmolStr {
7 Heap(Arc<str>),
8 Inline {
9 len: u8,
10 buf: [u8; INLINE_CAP],
11 },
12}
13
14impl 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)]
41mod 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