1use std::borrow::{Borrow, Cow};
2use std::convert::Infallible;
3use std::ffi::OsStr;
4use std::fmt::{Debug, Display};
5use std::hash::{Hash, Hasher};
6use std::ops::Deref;
7use std::path::Path;
8use std::str::FromStr;
9use std::sync::{Arc, RwLock, Weak};
10
11use hashbrown::raw::RawTable;
12
13#[cfg(feature = "serde")]
14mod serde;
15
16#[inline]
17#[cold]
18fn cold() {}
19
20lazy_static::lazy_static! {
21 static ref TABLE: RwLock<RawTable<Weak<TableString>>> = RwLock::new(RawTable::new());
22}
23
24type TableHasher = ahash::AHasher;
25
26struct DisplayHasher<H: Hasher>(H);
27impl<H: Hasher> DisplayHasher<H> {
28 fn finish(&self) -> u64 {
29 self.0.finish()
30 }
31}
32impl<H: Hasher + Default> DisplayHasher<H> {
33 fn hash<T: Display>(t: &T) -> u64 {
34 use std::fmt::Write;
35 let mut h = Self(H::default());
36 let _ = write!(h, "{t}");
37 h.finish()
38 }
39}
40impl<H: Hasher> std::fmt::Write for DisplayHasher<H> {
41 fn write_str(&mut self, s: &str) -> std::fmt::Result {
42 self.0.write(s.as_bytes());
43 Ok(())
44 }
45}
46
47struct DisplayEq<'a> {
48 target: &'a [u8],
49}
50impl<'a> DisplayEq<'a> {
51 fn eq<T: Display>(src: &T, target: &'a str) -> bool {
52 use std::fmt::Write;
53 let mut eq = Self {
54 target: target.as_bytes(),
55 };
56 write!(eq, "{src}").is_ok() && eq.target.is_empty()
57 }
58}
59impl<'a> std::fmt::Write for DisplayEq<'a> {
60 fn write_str(&mut self, s: &str) -> std::fmt::Result {
61 let s = s.as_bytes();
62 if s.len() > self.target.len() || s != &self.target[..s.len()] {
63 return Err(std::fmt::Error);
64 }
65 self.target = &self.target[s.len()..];
66 Ok(())
67 }
68}
69
70struct TableString(String);
71impl Drop for TableString {
72 fn drop(&mut self) {
73 let hash = DisplayHasher::<TableHasher>::hash(&self.0);
74 let eq = |s: &Weak<TableString>| s.strong_count() == 0;
75 let mut guard = TABLE.write().unwrap();
76 if !guard.erase_entry(hash, eq) {
77 cold();
78 let hash = TableHasher::default().finish();
79 guard.erase_entry(hash, eq);
80 }
81 }
82}
83
84pub struct InternedString(Arc<TableString>);
85impl InternedString {
86 pub fn intern<T: Display + Into<String>>(t: T) -> Self {
87 let hash = DisplayHasher::<TableHasher>::hash(&t);
88 let eq = |s: &Weak<TableString>| {
89 if let Some(s) = Weak::upgrade(s) {
90 DisplayEq::eq(&t, s.0.as_str())
91 } else {
92 false
93 }
94 };
95 {
97 if let Some(s) = TABLE.read().unwrap().get(hash, eq).and_then(Weak::upgrade) {
98 return Self(s);
99 }
100 }
101 {
103 let mut guard = TABLE.write().unwrap();
104 if let Some(s) = guard.get_mut(hash, eq) {
106 cold(); if let Some(s) = Weak::upgrade(s) {
108 return Self(s);
109 } else {
110 let res = Arc::new(TableString(t.into()));
111 *s = Arc::downgrade(&res);
112 return Self(res);
113 }
114 }
115 let res = Arc::new(TableString(t.into()));
117 guard.insert(hash, Arc::downgrade(&res), |s| {
118 let mut hasher = TableHasher::default();
119 if let Some(s) = Weak::upgrade(s) {
120 hasher.write(s.0.as_bytes())
121 }
122 hasher.finish()
123 });
124 return Self(res);
125 }
126 }
127
128 pub fn from_display<T: Display + ?Sized>(t: &T) -> Self {
129 struct IntoString<'a, T: ?Sized>(&'a T);
130 impl<'a, T: Display + ?Sized> From<IntoString<'a, T>> for String {
131 fn from(value: IntoString<'a, T>) -> Self {
132 value.0.to_string()
133 }
134 }
135 impl<'a, T: Display + ?Sized> std::fmt::Display for IntoString<'a, T> {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 self.0.fmt(f)
138 }
139 }
140 Self::intern(IntoString(t))
141 }
142}
143
144impl Deref for InternedString {
145 type Target = str;
146 fn deref(&self) -> &Self::Target {
147 self.0.deref().0.deref()
148 }
149}
150
151impl AsRef<[u8]> for InternedString {
152 fn as_ref(&self) -> &[u8] {
153 self.0.deref().0.as_ref()
154 }
155}
156
157impl AsRef<OsStr> for InternedString {
158 fn as_ref(&self) -> &OsStr {
159 self.0.deref().0.as_ref()
160 }
161}
162
163impl AsRef<Path> for InternedString {
164 fn as_ref(&self) -> &Path {
165 self.0.deref().0.as_ref()
166 }
167}
168
169impl AsRef<str> for InternedString {
170 fn as_ref(&self) -> &str {
171 self.0.deref().0.as_ref()
172 }
173}
174
175impl Borrow<str> for InternedString {
176 fn borrow(&self) -> &str {
177 self.0.deref().0.borrow()
178 }
179}
180
181impl Clone for InternedString {
182 fn clone(&self) -> Self {
183 Self(self.0.clone())
184 }
185}
186
187impl Debug for InternedString {
188 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189 Debug::fmt(&self.0.deref().0, f)
190 }
191}
192
193impl Default for InternedString {
194 fn default() -> Self {
195 Self::intern(String::default())
196 }
197}
198
199impl Display for InternedString {
200 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
201 Display::fmt(&self.0.deref().0, f)
202 }
203}
204
205impl PartialEq for InternedString {
206 fn eq(&self, other: &Self) -> bool {
207 Arc::ptr_eq(&self.0, &other.0)
208 }
209}
210
211impl Eq for InternedString {}
212
213impl PartialOrd for InternedString {
214 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
215 if Arc::ptr_eq(&self.0, &other.0) {
216 Some(std::cmp::Ordering::Equal)
217 } else {
218 self.0.deref().0.partial_cmp(&other.0.deref().0)
219 }
220 }
221}
222
223impl Ord for InternedString {
224 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
225 if Arc::ptr_eq(&self.0, &other.0) {
226 std::cmp::Ordering::Equal
227 } else {
228 self.0.deref().0.cmp(&other.0.deref().0)
229 }
230 }
231}
232
233impl<T: Display + Into<String>> From<T> for InternedString {
234 fn from(value: T) -> Self {
235 Self::intern(value)
236 }
237}
238
239impl FromStr for InternedString {
240 type Err = Infallible;
241 fn from_str(s: &str) -> Result<Self, Self::Err> {
242 Ok(Self::intern(s))
243 }
244}
245
246impl Hash for InternedString {
247 fn hash<H: Hasher>(&self, state: &mut H) {
248 self.0.deref().0.hash(state)
249 }
250}
251
252impl<'a> PartialEq<&'a str> for InternedString {
253 fn eq(&self, other: &&'a str) -> bool {
254 self.0.deref().0.eq(other)
255 }
256}
257
258impl<'a> PartialEq<Cow<'a, str>> for InternedString {
259 fn eq(&self, other: &Cow<'a, str>) -> bool {
260 self.0.deref().0.eq(other)
261 }
262}
263
264impl PartialEq<str> for InternedString {
265 fn eq(&self, other: &str) -> bool {
266 self.0.deref().0.eq(other)
267 }
268}