use std::hash::Hash; use std::marker::PhantomData; use fxhash::FxHashMap; pub struct Interned { idx: u32, _phantom: PhantomData, } impl Interned { fn new(idx: u32) -> Self { Self { idx, _phantom: PhantomData } } } pub struct Interner { stable_store: Vec, lookup: FxHashMap>, } impl Default for Interner { fn default() -> Self { Self { stable_store: Default::default(), lookup: Default::default() } } } impl Interner where T: Clone + Eq + Hash, { pub fn insert(&mut self, s: T) -> Interned { if let Some(interned) = self.lookup.get(&s) { *interned } else { self.stable_store.push(s.clone()); let interned = Interned::new(self.stable_store.len() as u32 - 1); self.lookup.insert(s, interned); interned } } pub fn get(&self, interned: Interned) -> &T { &self.stable_store[interned.idx as usize] } } // Interned boilerplate implementations impl Hash for Interned { fn hash(&self, state: &mut H) { self.idx.hash(state); } } impl Ord for Interned { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.idx.cmp(&other.idx) } } impl PartialOrd for Interned { fn partial_cmp(&self, other: &Self) -> Option { self.idx.partial_cmp(&other.idx) } } impl Eq for Interned {} impl PartialEq for Interned { fn eq(&self, other: &Self) -> bool { self.idx == other.idx } } impl Clone for Interned { fn clone(&self) -> Self { Self { idx: self.idx, _phantom: PhantomData } } } impl Copy for Interned {}