use std::cell::{RefCell, RefMut}; use std::cmp::Ordering; use std::collections::HashSet; use std::fmt; use std::hash::{Hash, Hasher}; use std::ops::Deref; use std::rc::Rc; pub struct TabledData { table: Rc>>>, pub(crate) module_name: Rc, } impl fmt::Debug for TabledData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("TabledData") .field("table", &self.table) .field("module_name", &self.table) .finish() } } impl Clone for TabledData { fn clone(&self) -> Self { TabledData { table: self.table.clone(), module_name: self.module_name.clone(), } } } impl PartialEq for TabledData { fn eq(&self, other: &TabledData) -> bool { Rc::ptr_eq(&self.table, &other.table) && self.module_name == other.module_name } } impl TabledData { #[inline] pub fn new(module_name: Rc) -> Self { TabledData { table: Rc::new(RefCell::new(HashSet::new())), module_name, } } #[inline] pub fn borrow_mut(&self) -> RefMut>> { self.table.borrow_mut() } } pub struct TabledRc { pub(crate) atom: Rc, pub table: TabledData, } impl fmt::Debug for TabledRc { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("TabledRc") .field("atom", &self.atom) .field("table", &self.table) .finish() } } // this Clone instance is manually defined to prevent the compiler // from complaining when deriving Clone for StringList. impl Clone for TabledRc { fn clone(&self) -> Self { TabledRc { atom: self.atom.clone(), table: self.table.clone(), } } } impl PartialOrd for TabledRc { fn partial_cmp(&self, other: &Self) -> Option { Some(self.atom.cmp(&other.atom)) } } impl Ord for TabledRc { fn cmp(&self, other: &Self) -> Ordering { self.atom.cmp(&other.atom) } } impl PartialEq for TabledRc { fn eq(&self, other: &TabledRc) -> bool { self.atom == other.atom } } impl Eq for TabledRc {} impl Hash for TabledRc { fn hash(&self, state: &mut H) { self.atom.hash(state) } } impl TabledRc { pub fn new(atom: T, table: TabledData) -> Self { let atom = match table.borrow_mut().take(&atom) { Some(atom) => atom, None => Rc::new(atom), }; table.borrow_mut().insert(atom.clone()); TabledRc { atom, table } } #[inline] pub fn inner(&self) -> Rc { self.atom.clone() } #[inline] pub(crate) fn owning_module(&self) -> Rc { self.table.module_name.clone() } } impl Drop for TabledRc { fn drop(&mut self) { if Rc::strong_count(&self.atom) == 2 { self.table.borrow_mut().remove(&self.atom); } } } impl Deref for TabledRc { type Target = T; fn deref(&self) -> &Self::Target { &*self.atom } } impl fmt::Display for TabledRc { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", &*self.atom) } } #[macro_export] macro_rules! tabled_rc { ($e:expr, $tbl:expr) => { $crate::tabled_rc::TabledRc::new(String::from($e), $tbl.clone()) }; }