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