use { crate::criteria::{ CritUpstreamNode, crit_graph::{ CritDownstream, CritDownstreamData, CritTarget, CritUpstreamData, crit_target::CritMgr, crit_upstream::{CritUpstreamNodeBase, CritUpstreamNodeData}, }, crit_per_target_data::{CritDestroyListenerBase, CritPerTargetData}, }, std::rc::Rc, }; pub struct CritMiddle where Target: CritTarget, T: CritMiddleCriterion, { upstream: CritDownstreamData, downstream: CritUpstreamData>, criterion: T, } #[derive(Default)] pub struct CritMiddleData { matches: usize, data: T, } pub trait CritMiddleCriterion: Sized + 'static { type Data: Default; type Not: CritMiddleCriterion; fn update_matched(&self, target: &Target, node: &mut Self::Data, matched: bool) -> bool; fn pull(&self, upstream: &[Rc>], target: &Target) -> bool; fn not(&self) -> Self::Not; } impl CritMiddle where Target: CritTarget, T: CritMiddleCriterion, { pub fn new( mgr: &Target::Mgr, upstream: &[Rc>], criterion: T, ) -> Rc { let id = mgr.id(); let slf = Rc::new_cyclic(|slf| Self { upstream: CritDownstreamData::new(id, upstream), downstream: CritUpstreamData::new(slf, id), criterion, }); slf.upstream.attach(&slf); slf } } impl CritDownstream for CritMiddle where Target: CritTarget, T: CritMiddleCriterion, { fn update_matched(self: Rc, target: &Target, matched: bool) { let mut node = self.downstream.get_or_create(target); let change = self .criterion .update_matched(target, &mut node.data, matched); let matches = match matched { true => node.matches + 1, false => node.matches - 1, }; node.matches = matches; self.downstream .update_matched(target, node, change, matches == 0); } } impl CritUpstreamNodeBase for CritMiddle where Target: CritTarget, T: CritMiddleCriterion, { type Data = CritMiddleData; fn data(&self) -> &CritUpstreamData { &self.downstream } fn not(&self, mgr: &Target::Mgr) -> Rc> { let upstream = self.upstream.not(mgr); CritMiddle::new(mgr, &upstream, self.criterion.not()) } fn pull(&self, target: &Target) -> bool { self.criterion.pull(&self.upstream.upstream, target) } } impl CritDestroyListenerBase for CritMiddle where Target: CritTarget, T: CritMiddleCriterion, { type Data = CritUpstreamNodeData>; fn data(&self) -> &CritPerTargetData { &self.downstream.nodes } }