use { crate::{ CritDestroyListener, CritMatcherId, crit_graph::{ WeakCritTargetOwner, crit_downstream::CritDownstream, crit_target::{CritTarget, CritTargetOwner}, }, crit_per_target_data::CritPerTargetData, }, jay_utils::copyhashmap::CopyHashMap, std::{ cell::RefMut, mem, ops::{Deref, DerefMut}, rc::{Rc, Weak}, }, }; pub struct CritUpstreamData where Target: CritTarget, { downstream: CopyHashMap>>, pub nodes: CritPerTargetData>, } pub struct CritUpstreamNodeData where Target: CritTarget, { matched: bool, tl: Target::Owner, data: T, } pub trait CritUpstreamNodeBase: 'static where Target: CritTarget, { type Data; fn data(&self) -> &CritUpstreamData; fn not(&self, mgr: &Target::Mgr) -> Rc>; fn pull(&self, target: &Target) -> bool; } pub trait CritUpstreamNode: 'static where Target: CritTarget, { fn attach(&self, id: CritMatcherId, downstream: Rc>); fn detach(&self, id: CritMatcherId); fn not(&self, mgr: &Target::Mgr) -> Rc>; fn pull(&self, target: &Target) -> bool; fn get(&self, target: &Target) -> bool; } impl CritUpstreamNode for T where Target: CritTarget, T: CritUpstreamNodeBase, { fn attach(&self, id: CritMatcherId, downstream: Rc>) { let data = self.data(); for n in data.nodes.borrow_mut().values_mut() { if !n.matched { continue; } let Some(target) = n.tl.upgrade() else { continue; }; downstream.clone().update_matched(target.data(), true); } data.downstream.set(id, Rc::downgrade(&downstream)); } fn detach(&self, id: CritMatcherId) { self.data().downstream.remove(&id); } fn not(&self, mgr: &Target::Mgr) -> Rc> { >::not(self, mgr) } fn pull(&self, target: &Target) -> bool { >::pull(self, target) } fn get(&self, target: &Target) -> bool { >::data(self).matched(target) } } impl Deref for CritUpstreamNodeData where Target: CritTarget, { type Target = T; fn deref(&self) -> &Self::Target { &self.data } } impl DerefMut for CritUpstreamNodeData where Target: CritTarget, { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.data } } impl CritUpstreamData where Target: CritTarget, { pub fn new(slf: &Weak>, id: CritMatcherId) -> Self { Self { downstream: Default::default(), nodes: CritPerTargetData::new(slf, id), } } pub fn clear(&self) { self.nodes.clear() } pub fn update_matched( &self, target: &Target, mut node: RefMut>, matched: bool, remove: bool, ) { let unchanged = mem::replace(&mut node.matched, matched) == matched; drop(node); if remove { self.nodes.remove(target.id()); } if unchanged { return; } for el in self.downstream.lock().values() { if let Some(el) = el.upgrade() { el.update_matched(target, matched); } } } pub fn get_or_create(&self, target: &Target) -> RefMut<'_, CritUpstreamNodeData> where T: Default, { self.nodes.get_or_create(target, || CritUpstreamNodeData { matched: false, tl: target.owner(), data: Default::default(), }) } pub fn get(&self, target: &Target) -> Option>> { self.nodes.get(target) } pub fn has_downstream(&self) -> bool { self.downstream.is_not_empty() } pub fn matched(&self, target: &Target) -> bool { let Some(node) = self.nodes.get(target) else { return false; }; node.matched } }