intern_all/
typed_interner.rs

1use std::borrow::Borrow;
2use std::hash::{BuildHasher, Hash};
3use std::sync::{Arc, RwLock};
4
5use hashbrown::HashMap;
6
7use super::token::{Tok, WeakTok};
8use crate::token::Internable;
9
10/// An interner for any type that implements [Borrow]. Not many optimizations
11/// are employed and the interner uses the default allocator. This and the use
12/// of weak references means that a long-lived instance can be kept around with
13/// regular calls to [TypedInterner::sweep].
14pub struct TypedInterner<T: Internable> {
15  tokens: RwLock<HashMap<Arc<T>, WeakTok<T>>>,
16}
17impl<T: Internable> TypedInterner<T> {
18  /// Create a fresh interner instance
19  #[must_use]
20  pub fn new() -> Arc<Self> { Arc::new(Self { tokens: RwLock::new(HashMap::new()) }) }
21
22  /// Get the number of stored values
23  pub fn size(self: &Arc<Self>) -> usize { self.tokens.read().unwrap().len() }
24
25  /// Remove entries which are no longer referenced anywhere else
26  pub fn sweep(&self) -> usize {
27    (self.tokens.write().unwrap()).extract_if(|_, v| v.upgrade().is_none()).count()
28  }
29
30  /// Intern an object, returning a token
31  #[must_use]
32  pub fn i<Q>(self: &Arc<Self>, q: &Q) -> Tok<T>
33  where
34    Q: ?Sized + Eq + Hash + ToOwned<Owned = T>,
35    T: Borrow<Q>,
36  {
37    let mut tokens = self.tokens.write().unwrap();
38    let hash = tokens.hasher().hash_one(q);
39    let mut ret: Option<Tok<T>> = None;
40    tokens
41      .raw_entry_mut()
42      .from_hash(hash, |k| <T as Borrow<Q>>::borrow(k) == q)
43      .and_replace_entry_with(|_, v| {
44        ret = Some((v.upgrade()?).clone());
45        Some(v)
46      })
47      .or_insert_with(|| {
48        let keyrc = Arc::new(q.to_owned());
49        let token = Tok::<T>::new(keyrc.clone(), self.clone());
50        ret = Some(token.clone());
51        (keyrc, WeakTok::new(&token))
52      });
53    ret.expect("One of the above callbacks must have ran")
54  }
55}