1#![warn(missing_docs)]
25
26use crate::{
27 parking_lot::Mutex,
28 uuid_provider,
29 visitor::{Visit, VisitResult, Visitor},
30 SafeLock,
31};
32use fxhash::{FxHashMap, FxHasher};
33pub use fyrox_core_derive::TypeUuidProvider;
34use serde::{Deserialize, Serialize};
35use std::{
36 fmt::{Debug, Display, Formatter},
37 hash::{Hash, Hasher},
38 ops::Deref,
39 sync::Arc,
40};
41
42#[derive(Clone, Debug)]
43struct State {
44 string: String,
45 hash: u64,
46}
47
48#[derive(Clone)]
60pub struct ImmutableString(Arc<State>);
61
62uuid_provider!(ImmutableString = "452caac1-19f7-43d6-9e33-92c2c9163332");
63
64impl Display for ImmutableString {
65 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
66 f.write_str(self.0.string.as_ref())
67 }
68}
69
70impl Debug for ImmutableString {
71 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
72 Debug::fmt(&self.0.string, f)
73 }
74}
75
76impl From<ImmutableString> for String {
77 fn from(value: ImmutableString) -> Self {
78 value.0.string.clone()
79 }
80}
81
82impl Visit for ImmutableString {
83 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
84 let mut string = self.0.string.clone();
86 string.visit(name, visitor)?;
87
88 if visitor.is_reading() {
90 *self = SSTORAGE.safe_lock().insert(string);
91 }
92
93 Ok(())
94 }
95}
96
97impl Serialize for ImmutableString {
98 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
99 where
100 S: serde::Serializer,
101 {
102 serializer.serialize_str(self.as_str())
103 }
104}
105
106impl<'de> Deserialize<'de> for ImmutableString {
107 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
108 where
109 D: serde::Deserializer<'de>,
110 {
111 Ok(ImmutableString::new(
112 deserializer.deserialize_string(ImmutableStringVisitor {})?,
113 ))
114 }
115}
116
117struct ImmutableStringVisitor {}
118
119impl serde::de::Visitor<'_> for ImmutableStringVisitor {
120 type Value = ImmutableString;
121
122 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
123 write!(formatter, "a string")
124 }
125
126 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
127 where
128 E: serde::de::Error,
129 {
130 Ok(ImmutableString::new(v))
131 }
132
133 fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
134 where
135 E: serde::de::Error,
136 {
137 Ok(v.into())
138 }
139}
140
141impl Default for ImmutableString {
142 fn default() -> Self {
143 Self::new("")
144 }
145}
146
147impl AsRef<str> for ImmutableString {
148 fn as_ref(&self) -> &str {
149 self.deref()
150 }
151}
152
153impl ImmutableString {
154 #[inline]
162 pub fn new<S: AsRef<str>>(string: S) -> ImmutableString {
163 SSTORAGE.safe_lock().insert(string)
164 }
165
166 #[inline]
169 pub fn cached_hash(&self) -> u64 {
170 self.0.hash
171 }
172
173 #[inline]
175 pub fn to_mutable(&self) -> String {
176 self.0.string.clone()
177 }
178
179 pub fn as_str(&self) -> &str {
181 self.deref()
182 }
183}
184
185impl From<&str> for ImmutableString {
186 fn from(value: &str) -> Self {
187 Self::new(value)
188 }
189}
190
191impl From<String> for ImmutableString {
192 fn from(value: String) -> Self {
193 SSTORAGE.safe_lock().insert_owned(value)
194 }
195}
196
197impl From<&String> for ImmutableString {
198 fn from(value: &String) -> Self {
199 SSTORAGE.safe_lock().insert(value)
200 }
201}
202
203impl Deref for ImmutableString {
204 type Target = str;
205
206 #[inline]
207 fn deref(&self) -> &Self::Target {
208 self.0.string.as_ref()
209 }
210}
211
212impl Hash for ImmutableString {
213 #[inline]
214 fn hash<H: Hasher>(&self, state: &mut H) {
215 state.write_u64(self.cached_hash())
216 }
217}
218
219impl PartialEq for ImmutableString {
220 #[inline]
221 fn eq(&self, other: &Self) -> bool {
222 self.cached_hash() == other.cached_hash()
223 }
224}
225
226impl Eq for ImmutableString {}
227
228#[derive(Default)]
231pub struct ImmutableStringStorage {
232 vec: FxHashMap<u64, Arc<State>>,
233}
234
235impl ImmutableStringStorage {
236 #[inline]
237 fn insert<S: AsRef<str>>(&mut self, string: S) -> ImmutableString {
238 let mut hasher = FxHasher::default();
239 string.as_ref().hash(&mut hasher);
240 let hash = hasher.finish();
241
242 if let Some(existing) = self.vec.get(&hash) {
243 ImmutableString(existing.clone())
244 } else {
245 let immutable = Arc::new(State {
246 string: string.as_ref().to_owned(),
247 hash,
248 });
249 self.vec.insert(hash, immutable.clone());
250 ImmutableString(immutable)
251 }
252 }
253 #[inline]
255 fn insert_owned(&mut self, string: String) -> ImmutableString {
256 let mut hasher = FxHasher::default();
257 string.hash(&mut hasher);
258 let hash = hasher.finish();
259
260 if let Some(existing) = self.vec.get(&hash) {
261 ImmutableString(existing.clone())
262 } else {
263 let immutable = Arc::new(State { string, hash });
264 self.vec.insert(hash, immutable.clone());
265 ImmutableString(immutable)
266 }
267 }
268}
269
270impl ImmutableStringStorage {
271 pub fn entry_count() -> usize {
273 SSTORAGE.safe_lock().vec.len()
274 }
275}
276
277lazy_static! {
278 static ref SSTORAGE: Arc<Mutex<ImmutableStringStorage>> =
279 Arc::new(Mutex::new(ImmutableStringStorage::default()));
280}
281
282#[cfg(test)]
283mod test {
284 use super::*;
285
286 #[test]
287 fn test_immutable_string_distinctness() {
288 let a = ImmutableString::new("Foobar");
289 let b = ImmutableString::new("rabooF");
290
291 assert_ne!(a.cached_hash(), b.cached_hash())
292 }
293
294 #[test]
295 fn test_immutable_string_uniqueness() {
296 let a = ImmutableString::new("Foobar");
297 let b = ImmutableString::new("Foobar");
298
299 assert_eq!(a.cached_hash(), b.cached_hash())
304 }
305
306 #[test]
307 fn test_immutable_string_uniqueness_from_owned() {
308 let a = ImmutableString::new("Foobar");
309 let b = ImmutableString::from("Foobar".to_owned());
310
311 assert_eq!(a.cached_hash(), b.cached_hash())
312 }
313
314 #[test]
315 fn visit_for_immutable_string() {
316 let mut a = ImmutableString::new("Foobar");
317 let mut visitor = Visitor::default();
318
319 assert!(a.visit("name", &mut visitor).is_ok());
320 }
321
322 #[test]
323 fn debug_for_immutable_string() {
324 let a = ImmutableString::new("Foobar");
325
326 assert_eq!(format!("{a:?}"), "\"Foobar\"");
327 }
328
329 #[test]
330 fn debug_for_immutable_string_from_owned() {
331 let a = ImmutableString::from("Foobar".to_owned());
332
333 assert_eq!(format!("{a:?}"), "\"Foobar\"");
334 }
335
336 #[test]
337 fn default_for_immutable_string() {
338 let a = ImmutableString::default();
339
340 assert_eq!(a.0.string, "");
341 }
342
343 #[test]
344 fn immutable_string_to_mutable() {
345 let a = ImmutableString::new("Foobar");
346
347 assert_eq!(a.to_mutable(), String::from("Foobar"));
348 }
349
350 #[test]
351 fn deref_for_immutable_string() {
352 let s = "Foobar";
353 let a = ImmutableString::new(s);
354
355 assert_eq!(a.deref(), s);
356 }
357
358 #[test]
359 fn eq_for_immutable_string() {
360 let a = ImmutableString::new("Foobar");
361 let b = ImmutableString::new("Foobar");
362
363 assert!(a == b);
364 }
365}