intern_arc/
global.rs

1//! Convenience functions for managing type-indexed interner pools
2use std::{
3    any::{Any, TypeId},
4    collections::HashMap,
5    hash::Hash,
6};
7
8use once_cell::sync::Lazy;
9use parking_lot::{RwLock, RwLockUpgradableReadGuard};
10
11use crate::{HashInterner, OrdInterner};
12
13static HASH_INTERNERS: Lazy<RwLock<HashInternerPool>> = Lazy::new(Default::default);
14
15/// A lazy map from type to hash-based interner
16///
17/// This is the backing implementation for [`hash_interner()`](fn.hash_interner.html), you
18/// can use it if you want the ability to drop the whole pool (note, though, that this will
19/// not drop the interned values — they are kept alive by the references you keep to them
20/// and are automatically freed when they are no longer references).
21pub struct HashInternerPool {
22    type_map: HashMap<TypeId, Box<dyn Any + Send + Sync + 'static>>,
23}
24
25impl Default for HashInternerPool {
26    fn default() -> Self {
27        Self::new()
28    }
29}
30
31impl HashInternerPool {
32    pub fn new() -> Self {
33        Self {
34            type_map: HashMap::new(),
35        }
36    }
37
38    /// Obtain an interner for the given type if it has been created already.
39    pub fn get<T>(&self) -> Option<HashInterner<T>>
40    where
41        T: Eq + Hash + Send + Sync + Any + ?Sized + 'static,
42    {
43        self.type_map
44            .get(&TypeId::of::<T>())
45            .map(|v| v.downcast_ref::<HashInterner<T>>().unwrap().clone())
46    }
47
48    /// Obtain an interner for the given type, create it if necessary.
49    pub fn get_or_create<T>(&mut self) -> HashInterner<T>
50    where
51        T: Eq + Hash + Send + Sync + Any + ?Sized + 'static,
52    {
53        self.get::<T>().unwrap_or_else(|| {
54            let ret = HashInterner::new();
55            self.type_map
56                .insert(TypeId::of::<T>(), Box::new(ret.clone()));
57            ret
58        })
59    }
60}
61
62/// Obtain an interner for the given type, create it if necessary.
63///
64/// The interner will be stored for the rest of your program’s runtime within the global interner
65/// pool and you will get the same instance when using this method for the same type later again.
66pub fn hash_interner<T>() -> HashInterner<T>
67where
68    T: Eq + Hash + Send + Sync + Any + ?Sized + 'static,
69{
70    let map = HASH_INTERNERS.upgradable_read();
71    if let Some(interner) = map.get::<T>() {
72        return interner;
73    }
74    let mut map = RwLockUpgradableReadGuard::upgrade(map);
75    map.get_or_create::<T>()
76}
77
78static ORD_INTERNERS: Lazy<RwLock<OrdInternerPool>> = Lazy::new(Default::default);
79
80/// A lazy map from type to ord-based interner
81///
82/// This is the backing implementation for [`ord_interner()`](fn.ord_interner.html), you
83/// can use it if you want the ability to drop the whole pool (note, though, that this will
84/// not drop the interned values — they are kept alive by the references you keep to them
85/// and are automatically freed when they are no longer references).
86pub struct OrdInternerPool {
87    type_map: HashMap<TypeId, Box<dyn Any + Send + Sync + 'static>>,
88}
89
90impl Default for OrdInternerPool {
91    fn default() -> Self {
92        Self::new()
93    }
94}
95
96impl OrdInternerPool {
97    pub fn new() -> Self {
98        Self {
99            type_map: HashMap::new(),
100        }
101    }
102
103    /// Obtain an interner for the given type if it has been created already.
104    pub fn get<T>(&self) -> Option<OrdInterner<T>>
105    where
106        T: Ord + Send + Sync + Any + ?Sized + 'static,
107    {
108        self.type_map
109            .get(&TypeId::of::<T>())
110            .map(|v| v.downcast_ref::<OrdInterner<T>>().unwrap().clone())
111    }
112
113    /// Obtain an interner for the given type, create it if necessary.
114    pub fn get_or_create<T>(&mut self) -> OrdInterner<T>
115    where
116        T: Ord + Send + Sync + Any + ?Sized + 'static,
117    {
118        self.get::<T>().unwrap_or_else(|| {
119            let ret = OrdInterner::new();
120            self.type_map
121                .insert(TypeId::of::<T>(), Box::new(ret.clone()));
122            ret
123        })
124    }
125}
126
127/// Obtain an interner for the given type, create it if necessary.
128///
129/// The interner will be stored for the rest of your program’s runtime within the global interner
130/// pool and you will get the same instance when using this method for the same type later again.
131pub fn ord_interner<T>() -> OrdInterner<T>
132where
133    T: Ord + Send + Sync + Any + ?Sized + 'static,
134{
135    let map = ORD_INTERNERS.upgradable_read();
136    if let Some(interner) = map.get::<T>() {
137        return interner;
138    }
139    let mut map = RwLockUpgradableReadGuard::upgrade(map);
140    map.get_or_create::<T>()
141}