use { crate::{ CritMatcherId, crit_graph::{CritTarget, CritTargetOwner, WeakCritTargetOwner}, }, ahash::AHashMap, std::{ cell::{RefCell, RefMut}, ops::{Deref, DerefMut}, rc::Weak, }, }; pub struct CritPerTargetData where Target: CritTarget, { id: CritMatcherId, slf: Weak>, data: RefCell>>, } pub struct PerTreeNodeData where Target: CritTarget, { node: Target::Owner, data: T, } pub trait CritDestroyListenerBase: 'static where Target: CritTarget, { type Data; fn data(&self) -> &CritPerTargetData; } pub trait CritDestroyListener: 'static where Target: CritTarget, { fn destroyed(&self, target_id: Target::Id); } impl CritPerTargetData where Target: CritTarget, { pub fn new(slf: &Weak>, id: CritMatcherId) -> Self { Self { id, slf: slf.clone() as _, data: Default::default(), } } pub fn clear(&self) { self.data.borrow_mut().clear(); } pub fn get_or_create(&self, target: &Target, default: impl FnOnce() -> T) -> RefMut<'_, T> { RefMut::map(self.data.borrow_mut(), |d| { &mut d .entry(target.id()) .or_insert_with(|| { target.destroyed().set(self.id, self.slf.clone()); PerTreeNodeData { node: target.owner(), data: default(), } }) .data }) } pub fn get(&self, target: &Target) -> Option> { RefMut::filter_map(self.data.borrow_mut(), |d| { d.get_mut(&target.id()).map(|d| &mut d.data) }) .ok() } pub fn remove(&self, target_id: Target::Id) { if let Some(node) = self.data.borrow_mut().remove(&target_id) && let Some(node) = node.node.upgrade() { node.data().destroyed().remove(&self.id); } } pub fn borrow_mut(&self) -> RefMut<'_, AHashMap>> { self.data.borrow_mut() } } impl Drop for CritPerTargetData where Target: CritTarget, { fn drop(&mut self) { for d in self.data.borrow().values() { if let Some(n) = d.node.upgrade() { n.data().destroyed().remove(&self.id); } } } } impl CritDestroyListener for T where Target: CritTarget, T: CritDestroyListenerBase, { fn destroyed(&self, target_id: Target::Id) { let _v = self.data().data.borrow_mut().remove(&target_id); } } impl Deref for PerTreeNodeData where Target: CritTarget, { type Target = T; fn deref(&self) -> &Self::Target { &self.data } } impl DerefMut for PerTreeNodeData where Target: CritTarget, { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.data } }