1
0
Fork 0
forked from wry/wry
wry/crates/criteria/src/crit_graph/crit_upstream.rs

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
}
}