use std::cell::RefCell; use std::fmt; use std::rc::Rc; use hashbrown::HashMap; use hashbrown::hash_map::Entry; use crate::api; use crate::expr::Expr; #[derive(Default)] pub struct ExprStoreData { exprs: RefCell>, parent: Option, } #[derive(Clone, Default)] pub struct ExprStore(Rc); impl ExprStore { #[must_use] pub fn derive(&self) -> Self { Self(Rc::new(ExprStoreData { exprs: RefCell::default(), parent: Some(self.clone()) })) } pub fn give_expr(&self, expr: Expr) { match self.0.exprs.borrow_mut().entry(expr.id()) { Entry::Occupied(mut oe) => oe.get_mut().0 += 1, Entry::Vacant(v) => { v.insert((1, expr)); }, } } pub fn take_expr(&self, ticket: api::ExprTicket) -> Option { match self.0.exprs.borrow_mut().entry(ticket) { Entry::Vacant(_) => None, Entry::Occupied(oe) if oe.get().0 == 1 => Some(oe.remove().1), Entry::Occupied(mut oe) => { oe.get_mut().0 -= 1; Some(oe.get().1.clone()) }, } } #[must_use] pub fn get_expr(&self, ticket: api::ExprTicket) -> Option { (self.0.exprs.borrow().get(&ticket).map(|(_, expr)| expr.clone())) .or_else(|| self.0.parent.as_ref()?.get_expr(ticket)) } } impl fmt::Display for ExprStore { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let r = self.0.exprs.borrow(); let rc: u32 = r.values().map(|v| v.0).sum(); write!(f, "Store holding {rc} refs to {} exprs", r.len()) } }