diff options
author | Aleksey Kladov <[email protected]> | 2018-08-16 21:40:48 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-08-16 21:40:48 +0100 |
commit | 6a3f819f795d656f36a2967647a83438f8fb58c4 (patch) | |
tree | 24cda2f8a5d7263b3df739f4f22ee24d323c84d4 /crates/smol_str/src/lib.rs | |
parent | e0a43a159d03a91d8cce07003d427df4f3d6966d (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.rs | 168 |
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 @@ | |||
1 | use std::{sync::Arc, ops::Deref, fmt}; | ||
2 | |||
3 | #[derive(Clone)] | ||
4 | pub struct SmolStr(Repr); | ||
5 | |||
6 | impl 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 | |||
20 | impl Deref for SmolStr { | ||
21 | type Target = str; | ||
22 | |||
23 | fn deref(&self) -> &str { | ||
24 | self.as_str() | ||
25 | } | ||
26 | } | ||
27 | |||
28 | impl PartialEq<str> for SmolStr { | ||
29 | fn eq(&self, other: &str) -> bool { | ||
30 | self.as_str() == other | ||
31 | } | ||
32 | } | ||
33 | |||
34 | impl PartialEq<SmolStr> for str { | ||
35 | fn eq(&self, other: &SmolStr) -> bool { | ||
36 | other == self | ||
37 | } | ||
38 | } | ||
39 | |||
40 | impl<'a> PartialEq<&'a str> for SmolStr { | ||
41 | fn eq(&self, other: &&'a str) -> bool { | ||
42 | self == *other | ||
43 | } | ||
44 | } | ||
45 | |||
46 | impl<'a> PartialEq<SmolStr> for &'a str { | ||
47 | fn eq(&self, other: &SmolStr) -> bool { | ||
48 | *self == other | ||
49 | } | ||
50 | } | ||
51 | |||
52 | impl PartialEq<String> for SmolStr { | ||
53 | fn eq(&self, other: &String) -> bool { | ||
54 | self.as_str() == other | ||
55 | } | ||
56 | } | ||
57 | |||
58 | impl PartialEq<SmolStr> for String { | ||
59 | fn eq(&self, other: &SmolStr) -> bool { | ||
60 | other == self | ||
61 | } | ||
62 | } | ||
63 | |||
64 | impl<'a> PartialEq<&'a String> for SmolStr { | ||
65 | fn eq(&self, other: &&'a String) -> bool { | ||
66 | self == *other | ||
67 | } | ||
68 | } | ||
69 | |||
70 | impl<'a> PartialEq<SmolStr> for &'a String { | ||
71 | fn eq(&self, other: &SmolStr) -> bool { | ||
72 | *self == other | ||
73 | } | ||
74 | } | ||
75 | |||
76 | impl 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 | |||
82 | impl 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 | |||
88 | const INLINE_CAP: usize = 22; | ||
89 | const WS_TAG: u8 = (INLINE_CAP + 1) as u8; | ||
90 | |||
91 | #[derive(Clone, Debug)] | ||
92 | enum Repr { | ||
93 | Heap(Arc<str>), | ||
94 | Inline { | ||
95 | len: u8, | ||
96 | buf: [u8; INLINE_CAP], | ||
97 | }, | ||
98 | } | ||
99 | |||
100 | impl 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 | |||
142 | const N_NEWLINES: usize = 32; | ||
143 | const N_SPACES: usize = 128; | ||
144 | const 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)] | ||
149 | mod 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 | |||