aboutsummaryrefslogtreecommitdiff
path: root/crates/smol_str/src/lib.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-16 21:40:48 +0100
committerAleksey Kladov <[email protected]>2018-08-16 21:40:48 +0100
commit6a3f819f795d656f36a2967647a83438f8fb58c4 (patch)
tree24cda2f8a5d7263b3df739f4f22ee24d323c84d4 /crates/smol_str/src/lib.rs
parente0a43a159d03a91d8cce07003d427df4f3d6966d (diff)
move smol_str to a separare repo
Diffstat (limited to 'crates/smol_str/src/lib.rs')
-rw-r--r--crates/smol_str/src/lib.rs168
1 files changed, 0 insertions, 168 deletions
diff --git a/crates/smol_str/src/lib.rs b/crates/smol_str/src/lib.rs
deleted file mode 100644
index 79b179ef4..000000000
--- a/crates/smol_str/src/lib.rs
+++ /dev/null
@@ -1,168 +0,0 @@
1use std::{sync::Arc, ops::Deref, fmt};
2
3#[derive(Clone)]
4pub struct SmolStr(Repr);
5
6impl SmolStr {
7 pub fn new(text: &str) -> SmolStr {
8 SmolStr(Repr::new(text))
9 }
10
11 pub fn as_str(&self) -> &str {
12 self.0.as_str()
13 }
14
15 pub fn to_string(&self) -> String {
16 self.as_str().to_string()
17 }
18}
19
20impl Deref for SmolStr {
21 type Target = str;
22
23 fn deref(&self) -> &str {
24 self.as_str()
25 }
26}
27
28impl PartialEq<str> for SmolStr {
29 fn eq(&self, other: &str) -> bool {
30 self.as_str() == other
31 }
32}
33
34impl PartialEq<SmolStr> for str {
35 fn eq(&self, other: &SmolStr) -> bool {
36 other == self
37 }
38}
39
40impl<'a> PartialEq<&'a str> for SmolStr {
41 fn eq(&self, other: &&'a str) -> bool {
42 self == *other
43 }
44}
45
46impl<'a> PartialEq<SmolStr> for &'a str {
47 fn eq(&self, other: &SmolStr) -> bool {
48 *self == other
49 }
50}
51
52impl PartialEq<String> for SmolStr {
53 fn eq(&self, other: &String) -> bool {
54 self.as_str() == other
55 }
56}
57
58impl PartialEq<SmolStr> for String {
59 fn eq(&self, other: &SmolStr) -> bool {
60 other == self
61 }
62}
63
64impl<'a> PartialEq<&'a String> for SmolStr {
65 fn eq(&self, other: &&'a String) -> bool {
66 self == *other
67 }
68}
69
70impl<'a> PartialEq<SmolStr> for &'a String {
71 fn eq(&self, other: &SmolStr) -> bool {
72 *self == other
73 }
74}
75
76impl fmt::Debug for SmolStr {
77 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78 fmt::Debug::fmt(self.as_str(), f)
79 }
80}
81
82impl fmt::Display for SmolStr {
83 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
84 fmt::Display::fmt(self.as_str(), f)
85 }
86}
87
88const INLINE_CAP: usize = 22;
89const WS_TAG: u8 = (INLINE_CAP + 1) as u8;
90
91#[derive(Clone, Debug)]
92enum Repr {
93 Heap(Arc<str>),
94 Inline {
95 len: u8,
96 buf: [u8; INLINE_CAP],
97 },
98}
99
100impl Repr {
101 fn new(text: &str) -> Repr {
102 let len = text.len();
103 if len <= INLINE_CAP {
104 let mut buf = [0; INLINE_CAP];
105 buf[..len].copy_from_slice(text.as_bytes());
106 return Repr::Inline { len: len as u8, buf };
107 }
108
109 let newlines = text.bytes().take_while(|&b| b == b'\n').count();
110 let spaces = text[newlines..].bytes().take_while(|&b| b == b' ').count();
111 if newlines + spaces == len && newlines <= N_NEWLINES && spaces <= N_SPACES {
112 let mut buf = [0; INLINE_CAP];
113 buf[0] = newlines as u8;
114 buf[1] = spaces as u8;
115 return Repr::Inline { len: WS_TAG, buf };
116 }
117
118 Repr::Heap(
119 text.to_string().into_boxed_str().into()
120 )
121 }
122
123 fn as_str(&self) -> &str {
124 match self {
125 Repr::Heap(data) => &*data,
126 Repr::Inline { len, buf } => {
127 if *len == WS_TAG {
128 let newlines = buf[0] as usize;
129 let spaces = buf[1] as usize;
130 assert!(newlines <= N_NEWLINES && spaces <= N_SPACES);
131 return &WS[N_NEWLINES - newlines..N_NEWLINES + spaces];
132 }
133
134 let len = *len as usize;
135 let buf = &buf[..len];
136 unsafe { ::std::str::from_utf8_unchecked(buf) }
137 }
138 }
139 }
140}
141
142const N_NEWLINES: usize = 32;
143const N_SPACES: usize = 128;
144const WS: &str =
145 "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n ";
146
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151
152 #[test]
153 #[cfg(target_pointer_width = "64")]
154 fn smol_str_is_smol() {
155 assert_eq!(::std::mem::size_of::<SmolStr>(), 8 + 8 + 8)
156 }
157
158 #[test]
159 fn test_round_trip() {
160 let mut text = String::new();
161 for n in 0..256 {
162 let smol = SmolStr::new(&text);
163 assert_eq!(smol.as_str(), text.as_str());
164 text.push_str(&n.to_string());
165 }
166 }
167}
168