177 lines
4.4 KiB
Rust
177 lines
4.4 KiB
Rust
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<Target, T>
|
|
where
|
|
Target: CritTarget,
|
|
{
|
|
downstream: CopyHashMap<CritMatcherId, Weak<dyn CritDownstream<Target>>>,
|
|
pub nodes: CritPerTargetData<Target, CritUpstreamNodeData<Target, T>>,
|
|
}
|
|
|
|
pub struct CritUpstreamNodeData<Target, T>
|
|
where
|
|
Target: CritTarget,
|
|
{
|
|
matched: bool,
|
|
tl: Target::Owner,
|
|
data: T,
|
|
}
|
|
|
|
pub trait CritUpstreamNodeBase<Target>: 'static
|
|
where
|
|
Target: CritTarget,
|
|
{
|
|
type Data;
|
|
|
|
fn data(&self) -> &CritUpstreamData<Target, Self::Data>;
|
|
fn not(&self, mgr: &Target::Mgr) -> Rc<dyn CritUpstreamNode<Target>>;
|
|
fn pull(&self, target: &Target) -> bool;
|
|
}
|
|
|
|
pub trait CritUpstreamNode<Target>: 'static
|
|
where
|
|
Target: CritTarget,
|
|
{
|
|
fn attach(&self, id: CritMatcherId, downstream: Rc<dyn CritDownstream<Target>>);
|
|
fn detach(&self, id: CritMatcherId);
|
|
fn not(&self, mgr: &Target::Mgr) -> Rc<dyn CritUpstreamNode<Target>>;
|
|
fn pull(&self, target: &Target) -> bool;
|
|
fn get(&self, target: &Target) -> bool;
|
|
}
|
|
|
|
impl<Target, T> CritUpstreamNode<Target> for T
|
|
where
|
|
Target: CritTarget,
|
|
T: CritUpstreamNodeBase<Target>,
|
|
{
|
|
fn attach(&self, id: CritMatcherId, downstream: Rc<dyn CritDownstream<Target>>) {
|
|
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<dyn CritUpstreamNode<Target>> {
|
|
<T as CritUpstreamNodeBase<Target>>::not(self, mgr)
|
|
}
|
|
|
|
fn pull(&self, target: &Target) -> bool {
|
|
<T as CritUpstreamNodeBase<Target>>::pull(self, target)
|
|
}
|
|
|
|
fn get(&self, target: &Target) -> bool {
|
|
<T as CritUpstreamNodeBase<Target>>::data(self).matched(target)
|
|
}
|
|
}
|
|
|
|
impl<Target, T> Deref for CritUpstreamNodeData<Target, T>
|
|
where
|
|
Target: CritTarget,
|
|
{
|
|
type Target = T;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.data
|
|
}
|
|
}
|
|
|
|
impl<Target, T> DerefMut for CritUpstreamNodeData<Target, T>
|
|
where
|
|
Target: CritTarget,
|
|
{
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
&mut self.data
|
|
}
|
|
}
|
|
|
|
impl<Target, T> CritUpstreamData<Target, T>
|
|
where
|
|
Target: CritTarget,
|
|
{
|
|
pub fn new(slf: &Weak<impl CritDestroyListener<Target>>, 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<CritUpstreamNodeData<Target, T>>,
|
|
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<Target, T>>
|
|
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<RefMut<'_, CritUpstreamNodeData<Target, T>>> {
|
|
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
|
|
}
|
|
}
|