intern_all/
interner.rs

1use std::any::{Any, TypeId};
2use std::borrow::Borrow;
3use std::hash::Hash;
4use std::ops::DerefMut;
5use std::sync::{Arc, Mutex};
6
7use hashbrown::HashMap;
8
9use super::token::Tok;
10use super::typed_interner::TypedInterner;
11use crate::token::Internable;
12
13/// Operations that can be executed on [TypedInterner] without knowing its
14/// concrete type
15pub trait AnyInterner: Send + Sync {
16  fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
17  fn sweep(&self) -> usize;
18}
19
20impl<T: Internable> AnyInterner for TypedInterner<T> {
21  fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> { self }
22  fn sweep(&self) -> usize { TypedInterner::sweep(self) }
23}
24
25/// A collection of interners based on their type. Can be used to intern any
26/// object that implements [ToOwned]. Objects of the same type are stored
27/// together in a [TypedInterner]
28pub struct Interner {
29  interners: Mutex<HashMap<TypeId, Arc<dyn AnyInterner>>>,
30}
31impl Interner {
32  /// Create a new interner
33  #[must_use]
34  pub fn new() -> Self { Self { interners: Mutex::new(HashMap::new()) } }
35
36  /// Intern something
37  #[must_use]
38  pub fn i<Q>(&self, q: &Q) -> Tok<Q::Owned>
39  where
40    Q: ?Sized + Eq + Hash + ToOwned,
41    Q::Owned: Internable + Borrow<Q>,
42  {
43    let mut interners = self.interners.lock().unwrap();
44    let interner = get_interner(&mut interners);
45    interner.i(q)
46  }
47
48  /// Sweep values of a specific type. Useful if you just
49  /// constructed a large number of values of a specific type, otherwise use
50  /// [Interner::sweep]
51  pub fn sweep_t<T: Internable>(&self) -> usize {
52    match self.interners.lock().unwrap().get(&TypeId::of::<T>()) {
53      None => 0,
54      Some(interner) => interner.sweep(),
55    }
56  }
57
58  /// Sweep all values not referenced by anything other than the interner.
59  pub fn sweep(&self) -> usize { self.interners.lock().unwrap().values().map(|v| v.sweep()).sum() }
60
61  /// Intern a list and its elements. See also [Interner::ibv]
62  pub fn iv<T: Internable>(&self, s: impl IntoIterator<Item = T>) -> Tok<Vec<Tok<T>>> {
63    self.i(&s.into_iter().map(|t| self.i(&t)).collect::<Vec<_>>())
64  }
65
66  /// Intern a list of borrowed items. See also [Interner::iv]
67  pub fn ibv<'a, Q>(&self, s: impl IntoIterator<Item = &'a Q>) -> Tok<Vec<Tok<Q::Owned>>>
68  where
69    Q: ?Sized + Eq + Hash + ToOwned + 'a,
70    Q::Owned: Internable,
71  {
72    self.i(&s.into_iter().map(|t| self.i(t)).collect::<Vec<_>>())
73  }
74}
75
76impl Default for Interner {
77  fn default() -> Self { Self::new() }
78}
79
80/// Get or create an interner for a given type
81#[must_use]
82fn get_interner<T: Internable>(
83  interners: &mut impl DerefMut<Target = HashMap<TypeId, Arc<dyn AnyInterner>>>,
84) -> Arc<TypedInterner<T>> {
85  let boxed = interners
86    .raw_entry_mut()
87    .from_key(&TypeId::of::<T>())
88    .or_insert_with(|| (TypeId::of::<T>(), TypedInterner::<T>::new()))
89    .1
90    .clone();
91  (Arc::downcast(boxed.as_any_arc())).expect("the typeid is supposed to protect from this")
92}
93
94#[cfg(test)]
95mod test {
96  use super::*;
97
98  #[test]
99  pub fn test_string() {
100    let interner = Interner::new();
101    let key1 = interner.i("foo");
102    let key2 = interner.i(&"foo".to_string());
103    assert_eq!(key1, key2)
104  }
105
106  #[test]
107  pub fn test_slice() {
108    let interner = Interner::new();
109    let key1 = interner.i(&vec![1, 2, 3]);
110    let key2 = interner.i(&[1, 2, 3][..]);
111    assert_eq!(key1, key2);
112  }
113
114  #[test]
115  pub fn test_str_slice() {
116    let interner = Interner::new();
117    let key1 = interner.iv(["a".to_string(), "b".to_string(), "c".to_string()]);
118    let key2 = interner.ibv(vec!["a", "b", "c"]);
119    assert_eq!(key1, key2);
120  }
121}