jrsonnet_interner/
lib.rs

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		// It is ok, since all IStr should be inlined into same pool
30		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		// First reference - current object, second - POOL
49		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}