1use jrsonnet_gc::{unsafe_empty_trace, Finalize, Trace};
2use rustc_hash::FxHashMap;
3use serde::{Deserialize, Serialize};
4use std::{
5 cell::RefCell,
6 fmt::{self, Display},
7 hash::{BuildHasherDefault, Hash, Hasher},
8 ops::Deref,
9 rc::Rc,
10};
11
12#[derive(Clone, PartialOrd, Ord, Eq)]
13pub struct IStr(Rc<str>);
14impl Finalize for IStr {}
15unsafe impl Trace for IStr {
16 unsafe_empty_trace!();
17}
18
19impl Deref for IStr {
20 type Target = str;
21
22 fn deref(&self) -> &Self::Target {
23 &self.0
24 }
25}
26
27impl PartialEq for IStr {
28 fn eq(&self, other: &Self) -> bool {
29 Rc::ptr_eq(&self.0, &other.0)
31 }
32}
33
34impl PartialEq<str> for IStr {
35 fn eq(&self, other: &str) -> bool {
36 &self.0 as &str == other
37 }
38}
39
40impl Hash for IStr {
41 fn hash<H: Hasher>(&self, state: &mut H) {
42 state.write_usize(Rc::as_ptr(&self.0) as *const () as usize)
43 }
44}
45
46impl Drop for IStr {
47 fn drop(&mut self) {
48 if Rc::strong_count(&self.0) <= 2 {
50 let _result = STR_POOL.try_with(|pool| pool.borrow_mut().remove(&self.0));
51 }
52 }
53}
54
55impl fmt::Debug for IStr {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 write!(f, "{:?}", &self.0)
58 }
59}
60
61impl Display for IStr {
62 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63 f.write_str(&self.0)
64 }
65}
66
67thread_local! {
68 static STR_POOL: RefCell<FxHashMap<Rc<str>, ()>> = RefCell::new(FxHashMap::with_capacity_and_hasher(200, BuildHasherDefault::default()));
69}
70
71impl From<&str> for IStr {
72 fn from(str: &str) -> Self {
73 IStr(STR_POOL.with(|pool| {
74 let mut pool = pool.borrow_mut();
75 if let Some((k, _)) = pool.get_key_value(str) {
76 k.clone()
77 } else {
78 let rc: Rc<str> = str.into();
79 pool.insert(rc.clone(), ());
80 rc
81 }
82 }))
83 }
84}
85
86impl From<String> for IStr {
87 fn from(str: String) -> Self {
88 (&str as &str).into()
89 }
90}
91
92impl Serialize for IStr {
93 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
94 where
95 S: serde::Serializer,
96 {
97 (&self.0 as &str).serialize(serializer)
98 }
99}
100
101impl<'de> Deserialize<'de> for IStr {
102 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
103 where
104 D: serde::Deserializer<'de>,
105 {
106 let s = <&str>::deserialize(deserializer)?;
107 Ok(s.into())
108 }
109}