use anymap::AnyMap; use parking_lot::RwLock; use rustc_hash::FxHashSet; use std::any::{self, Any, TypeId}; use std::collections::BTreeMap; use std::marker::PhantomData; use std::sync::Arc; use crate::node::{FromAnyValue, NodeData}; use crate::node_ref::NodeView; use crate::real_dom::RealDom; use crate::tree::{self, Node, TreeStateView}; use crate::{FxDashMap, FxDashSet, SendAnyMap}; use crate::{NodeId, NodeMask}; #[derive(Default)] struct DirtyNodes { passes_dirty: Vec, } impl DirtyNodes { pub fn add_node(&mut self, node_id: NodeId) { let node_id = node_id.0; let index = node_id / 64; let bit = node_id % 64; let encoded = 1 << bit; if let Some(passes) = self.passes_dirty.get_mut(index) { *passes |= encoded; } else { self.passes_dirty.resize(index + 1, 0); self.passes_dirty[index] |= encoded; } } pub fn is_empty(&self) -> bool { self.passes_dirty.iter().all(|dirty| *dirty == 0) } pub fn pop(&mut self) -> Option { let index = self.passes_dirty.iter().position(|dirty| *dirty != 0)?; let passes = self.passes_dirty[index]; let node_id = passes.trailing_zeros(); let encoded = 1 << node_id; self.passes_dirty[index] &= !encoded; Some(NodeId((index * 64) + node_id as usize)) } } #[derive(Default, Clone)] pub struct DirtyNodeStates { dirty: Arc>>>, } impl DirtyNodeStates { pub fn insert(&self, pass_id: TypeId, node_id: NodeId, height: u16) { let mut dirty = self.dirty.write(); if let Some(dirty) = dirty.get_mut(&height) { if let Some(mut entry) = dirty.get_mut(&pass_id) { entry.add_node(node_id); } else { let mut entry = DirtyNodes::default(); entry.add_node(node_id); dirty.insert(pass_id, entry); } } else { let mut entry = DirtyNodes::default(); entry.add_node(node_id); let hm = FxDashMap::default(); hm.insert(pass_id, entry); dirty.insert(height, hm); } } fn pop_front(&self, pass_id: TypeId) -> Option<(u16, NodeId)> { let dirty_read = self.dirty.read(); let (&height, values) = dirty_read .iter() .find(|(_, values)| values.contains_key(&pass_id))?; let mut dirty = values.get_mut(&pass_id)?; let node_id = dirty.pop()?; if dirty.is_empty() { values.remove(&pass_id); } if values.is_empty() { let mut dirty_write = self.dirty.write(); dirty_write.remove(&height); } Some((height, node_id)) } fn pop_back(&self, pass_id: TypeId) -> Option<(u16, NodeId)> { let dirty_read = self.dirty.read(); let (&height, values) = dirty_read .iter() .rev() .find(|(_, values)| values.contains_key(&pass_id))?; let mut dirty = values.get_mut(&pass_id)?; let node_id = dirty.pop()?; if dirty.is_empty() { values.remove(&pass_id); } if values.is_empty() { let mut dirty_write = self.dirty.write(); dirty_write.remove(&height); } Some((height, node_id)) } } pub trait Pass: Any { /// This is a tuple of (T: Any, ..) type ParentDependencies: Dependancy; /// This is a tuple of (T: Any, ..) type ChildDependencies: Dependancy; /// This is a tuple of (T: Any, ..) type NodeDependencies: Dependancy; const NODE_MASK: NodeMask; fn pass<'a>( &mut self, node_view: NodeView, node: ::ElementBorrowed<'a>, parent: Option<::ElementBorrowed<'a>>, children: Option::ElementBorrowed<'a>>>, context: &SendAnyMap, ) -> bool; fn validate() { // no type can be a child and parent dependency for type_id in Self::parent_type_ids().into_iter().copied() { for type_id2 in Self::child_type_ids().into_iter().copied() { if type_id == type_id2 { panic!("type cannot be both a parent and child dependency"); } } } // this type should not be a node dependency for type_id in Self::node_type_ids().into_iter().copied() { if type_id == TypeId::of::() { panic!("The current type cannot be a node dependency"); } } // no states have the same type id if Self::all_dependanices() .into_iter() .collect::>() .len() != Self::all_dependanices().len() { panic!("all states must have unique type ids"); } } fn to_type_erased() -> TypeErasedPass where Self: Sized, { Self::validate(); TypeErasedPass { this_type_id: TypeId::of::(), combined_dependancy_type_ids: Self::all_dependanices().into_iter().copied().collect(), parent_dependant: !Self::parent_type_ids().is_empty(), child_dependant: !Self::child_type_ids().is_empty(), dependants: FxHashSet::default(), mask: Self::NODE_MASK, pass_direction: Self::pass_direction(), pass: Box::new( |node_id: NodeId, tree: &mut TreeStateView, context: &SendAnyMap| { debug_assert!(!Self::NodeDependencies::type_ids() .into_iter() .any(|id| *id == TypeId::of::())); // get all of the states from the tree view // Safety: No node has itself as a parent or child. let node_raw = tree.get_mut::(node_id).unwrap() as *mut Self; let node_data = tree.get_single::>(node_id).unwrap(); let node = tree.get::(node_id).unwrap(); let children = tree.children::(node_id); let parent = tree.parent::(node_id); let myself = unsafe { &mut *node_raw }; myself.pass( NodeView::new(&node_data, Self::NODE_MASK), node, parent, children, context, ) }, ) as PassCallback, phantom: PhantomData, } } fn parent_type_ids() -> Box<[TypeId]> { Self::ParentDependencies::type_ids() } fn child_type_ids() -> Box<[TypeId]> { Self::ChildDependencies::type_ids() } fn node_type_ids() -> Box<[TypeId]> { Self::NodeDependencies::type_ids() } fn all_dependanices() -> Box<[TypeId]> { let mut dependencies = Self::parent_type_ids().to_vec(); dependencies.extend(Self::child_type_ids().into_iter()); dependencies.extend(Self::node_type_ids().into_iter()); dependencies.into_boxed_slice() } fn pass_direction() -> PassDirection { if Self::child_type_ids() .into_iter() .any(|type_id| *type_id == TypeId::of::()) { PassDirection::ChildToParent } else if Self::parent_type_ids() .into_iter() .any(|type_id| *type_id == TypeId::of::()) { PassDirection::ParentToChild } else { PassDirection::AnyOrder } } } pub struct TypeErasedPass { pub(crate) this_type_id: TypeId, pub(crate) parent_dependant: bool, pub(crate) child_dependant: bool, pub(crate) combined_dependancy_type_ids: FxHashSet, pub(crate) dependants: FxHashSet, pub(crate) mask: NodeMask, pass: PassCallback, pub(crate) pass_direction: PassDirection, phantom: PhantomData, } impl TypeErasedPass { fn resolve( &self, mut tree: TreeStateView, dirty: &DirtyNodeStates, nodes_updated: &FxDashSet, ctx: &SendAnyMap, ) { match self.pass_direction { PassDirection::ParentToChild => { while let Some((height, id)) = dirty.pop_front(self.this_type_id) { if (self.pass)(id, &mut tree, ctx) { nodes_updated.insert(id); for id in tree.children_ids(id).unwrap() { for dependant in &self.dependants { dirty.insert(*dependant, id, height + 1); } } } } } PassDirection::ChildToParent => { while let Some((height, id)) = dirty.pop_back(self.this_type_id) { if (self.pass)(id, &mut tree, ctx) { nodes_updated.insert(id); if let Some(id) = tree.parent_id(id) { for dependant in &self.dependants { dirty.insert(*dependant, id, height - 1); } } } } } PassDirection::AnyOrder => { while let Some((height, id)) = dirty.pop_back(self.this_type_id) { if (self.pass)(id, &mut tree, ctx) { nodes_updated.insert(id); for dependant in &self.dependants { dirty.insert(*dependant, id, height); } } } } } } } #[derive(Debug)] pub enum PassDirection { ParentToChild, ChildToParent, AnyOrder, } type PassCallback = Box bool + Send + Sync>; pub trait AnyMapLike<'a> { fn get(self) -> Option<&'a T>; } impl<'a> AnyMapLike<'a> for &'a AnyMap { fn get(self) -> Option<&'a T> { self.get() } } impl<'a> AnyMapLike<'a> for &'a SendAnyMap { fn get(self) -> Option<&'a T> { todo!() } } pub trait Dependancy { type ElementBorrowed<'a> where Self: 'a; fn borrow_elements_from<'a, T: AnyMapLike<'a> + Copy>( map: T, ) -> Option>; fn type_ids() -> Box<[TypeId]>; } macro_rules! impl_dependancy { ($($t:ident),*) => { impl< $($t: Any),* > Dependancy for ($($t,)*) { type ElementBorrowed<'a> = ($(&'a $t,)*) where Self: 'a; #[allow(unused_variables, clippy::unused_unit, non_snake_case)] fn borrow_elements_from<'a, T: AnyMapLike<'a> + Copy>(map: T) -> Option> { Some(($(map.get::<$t>()?,)*)) } fn type_ids() -> Box<[TypeId]> { Box::new([$(TypeId::of::<$t>()),*]) } } }; } impl_dependancy!(); impl_dependancy!(A); impl_dependancy!(A, B); impl_dependancy!(A, B, C); impl_dependancy!(A, B, C, D); impl_dependancy!(A, B, C, D, E); impl_dependancy!(A, B, C, D, E, F); impl_dependancy!(A, B, C, D, E, F, G); impl_dependancy!(A, B, C, D, E, F, G, H); impl_dependancy!(A, B, C, D, E, F, G, H, I); impl_dependancy!(A, B, C, D, E, F, G, H, I, J); impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K); impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L); impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L, M); impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L, M, N); impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O); impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P); pub fn resolve_passes( tree: &mut RealDom, dirty_nodes: DirtyNodeStates, ctx: SendAnyMap, ) -> FxDashSet { let passes = &tree.passes; let mut resolved_passes: FxHashSet = FxHashSet::default(); let mut resolving = Vec::new(); let nodes_updated = Arc::new(FxDashSet::default()); let ctx = Arc::new(ctx); let mut pass_indexes_remaining: Vec<_> = (0..passes.len()).collect::>(); while !pass_indexes_remaining.is_empty() { let mut currently_in_use = FxHashSet::::default(); std::thread::scope(|_| { let mut i = 0; let dynamically_borrowed_tree = tree.tree.dynamically_borrowed(); while i < pass_indexes_remaining.len() { let passes_idx = pass_indexes_remaining[i]; let pass = &passes[passes_idx]; let pass_id = pass.this_type_id; // check if the pass is ready to be run if pass.combined_dependancy_type_ids.iter().all(|d| { (resolved_passes.contains(d) || *d == pass_id) && !currently_in_use.contains(d) }) { pass_indexes_remaining.remove(i); resolving.push(pass_id); currently_in_use.insert(pass.this_type_id); dynamically_borrowed_tree.with_view( pass.combined_dependancy_type_ids.iter().copied(), [pass.this_type_id], |tree_view| { let dirty_nodes = dirty_nodes.clone(); let nodes_updated = nodes_updated.clone(); let ctx = ctx.clone(); // s.spawn(move || { pass.resolve(tree_view, &dirty_nodes, &nodes_updated, &ctx); // }); }, ); } else { i += 1; } } }); resolved_passes.extend(resolving.iter().copied()); resolving.clear() } std::sync::Arc::try_unwrap(nodes_updated).unwrap() } // #[test] // fn node_pass() { // use crate::real_dom::RealDom; // use crate::tree::{Tree, TreeLike}; // #[derive(Debug, Default, Clone, PartialEq)] // struct Number(i32); // impl State for Number { // fn create_passes() -> Box<[TypeErasedPass]> { // Box::new([Number::to_type_erased()]) // } // } // impl AnyMapLike for Number { // fn get(&self) -> Option<&T> { // if TypeId::of::() == TypeId::of::() { // Some(unsafe { &*(self as *const Self as *const T) }) // } else { // None // } // } // fn get_mut(&mut self) -> Option<&mut T> { // if TypeId::of::() == TypeId::of::() { // Some(unsafe { &mut *(self as *mut Self as *mut T) }) // } else { // None // } // } // } // impl Pass for Number { // type ChildDependencies = (); // type NodeDependencies = (); // type ParentDependencies = (); // type Ctx = (); // const MASK: NodeMask = NodeMask::new(); // fn pass<'a>( // &mut self, // node_view: NodeView, // node: ::ElementBorrowed<'a>, // parent: Option<::ElementBorrowed<'a>>, // children: Option< // impl Iterator::ElementBorrowed<'a>>, // >, // context: ::ElementBorrowed<'a>, // ) -> bool { // self.0 += 1; // true // } // } // let mut tree: RealDom = RealDom::new(); // tree.dirty_nodes.insert(TypeId::of::(), NodeId(0)); // tree.update_state(SendAnyMap::new()); // assert_eq!(tree.get(tree.root()).unwrap().state.0, 1); // } // #[test] // fn dependant_node_pass() { // use crate::real_dom::RealDom; // #[derive(Debug, Default, Clone, PartialEq)] // struct AddNumber(i32); // impl Pass for AddNumber { // type ChildDependencies = (); // type NodeDependencies = (SubtractNumber,); // type ParentDependencies = (); // type Ctx = (); // const MASK: NodeMask = NodeMask::new(); // fn pass<'a>( // &mut self, // node_view: NodeView, // node: ::ElementBorrowed<'a>, // parent: Option<::ElementBorrowed<'a>>, // children: Option< // impl Iterator::ElementBorrowed<'a>>, // >, // context: ::ElementBorrowed<'a>, // ) -> bool { // self.0 += 1; // true // } // } // #[derive(Debug, Default, Clone, PartialEq)] // struct SubtractNumber(i32); // impl Pass for SubtractNumber { // type ChildDependencies = (); // type NodeDependencies = (); // type ParentDependencies = (); // type Ctx = (); // const MASK: NodeMask = NodeMask::new(); // fn pass<'a>( // &mut self, // node_view: NodeView, // node: ::ElementBorrowed<'a>, // parent: Option<::ElementBorrowed<'a>>, // children: Option< // impl Iterator::ElementBorrowed<'a>>, // >, // context: ::ElementBorrowed<'a>, // ) -> bool { // self.0 -= 1; // true // } // } // #[derive(Debug, Default, Clone, PartialEq)] // struct NumberState { // add_number: AddNumber, // subtract_number: SubtractNumber, // } // impl AnyMapLike for NumberState { // fn get(&self) -> Option<&T> { // if TypeId::of::() == TypeId::of::() { // Some(unsafe { &*(&self.add_number as *const AddNumber as *const T) }) // } else if TypeId::of::() == TypeId::of::() { // Some(unsafe { &*(&self.subtract_number as *const SubtractNumber as *const T) }) // } else { // None // } // } // fn get_mut(&mut self) -> Option<&mut T> { // if TypeId::of::() == TypeId::of::() { // Some(unsafe { &mut *(&mut self.add_number as *mut AddNumber as *mut T) }) // } else if TypeId::of::() == TypeId::of::() { // Some(unsafe { &mut *(&mut self.subtract_number as *mut SubtractNumber as *mut T) }) // } else { // None // } // } // } // impl State for NumberState { // fn create_passes() -> Box<[TypeErasedPass]> { // Box::new([ // AddNumber::to_type_erased(), // SubtractNumber::to_type_erased(), // ]) // } // } // let mut tree: RealDom = RealDom::new(); // tree.dirty_nodes // .insert(TypeId::of::(), NodeId(0)); // tree.update_state(dirty_nodes, SendAnyMap::new()); // assert_eq!( // tree.get(tree.root()).unwrap().state, // NumberState { // add_number: AddNumber(1), // subtract_number: SubtractNumber(-1) // } // ); // } // #[test] // fn independant_node_pass() { // use crate::real_dom::RealDom; // use crate::tree::{Tree, TreeLike}; // #[derive(Debug, Default, Clone, PartialEq)] // struct AddNumber(i32); // impl Pass for AddNumber { // type ChildDependencies = (); // type NodeDependencies = (); // type ParentDependencies = (); // type Ctx = (); // const MASK: NodeMask = NodeMask::new(); // fn pass<'a>( // &mut self, // node_view: NodeView, // node: ::ElementBorrowed<'a>, // parent: Option<::ElementBorrowed<'a>>, // children: Option< // impl Iterator::ElementBorrowed<'a>>, // >, // context: ::ElementBorrowed<'a>, // ) -> bool { // self.0 += 1; // true // } // } // #[derive(Debug, Default, Clone, PartialEq)] // struct SubtractNumber(i32); // impl Pass for SubtractNumber { // type ChildDependencies = (); // type NodeDependencies = (); // type ParentDependencies = (); // type Ctx = (); // const MASK: NodeMask = NodeMask::new(); // fn pass<'a>( // &mut self, // node_view: NodeView, // node: ::ElementBorrowed<'a>, // parent: Option<::ElementBorrowed<'a>>, // children: Option< // impl Iterator::ElementBorrowed<'a>>, // >, // context: ::ElementBorrowed<'a>, // ) -> bool { // self.0 -= 1; // true // } // } // #[derive(Debug, Default, Clone, PartialEq)] // struct NumberState { // add_number: AddNumber, // subtract_number: SubtractNumber, // } // impl AnyMapLike for NumberState { // fn get(&self) -> Option<&T> { // if TypeId::of::() == TypeId::of::() { // Some(unsafe { &*(&self.add_number as *const AddNumber as *const T) }) // } else if TypeId::of::() == TypeId::of::() { // Some(unsafe { &*(&self.subtract_number as *const SubtractNumber as *const T) }) // } else { // None // } // } // fn get_mut(&mut self) -> Option<&mut T> { // if TypeId::of::() == TypeId::of::() { // Some(unsafe { &mut *(&mut self.add_number as *mut AddNumber as *mut T) }) // } else if TypeId::of::() == TypeId::of::() { // Some(unsafe { &mut *(&mut self.subtract_number as *mut SubtractNumber as *mut T) }) // } else { // None // } // } // } // impl State for NumberState { // fn create_passes() -> Box<[TypeErasedPass]> { // Box::new([ // AddNumber::to_type_erased(), // SubtractNumber::to_type_erased(), // ]) // } // } // let mut tree: RealDom = RealDom::new(); // tree.dirty_nodes // .insert(TypeId::of::(), NodeId(0)); // tree.update_state(SendAnyMap::new()); // assert_eq!( // tree.get(tree.root()).unwrap().state, // NumberState { // add_number: AddNumber(0), // subtract_number: SubtractNumber(-1) // } // ); // } // #[test] // fn down_pass() { // use crate::real_dom::RealDom; // use crate::tree::{Tree, TreeLike}; // #[derive(Debug, Default, Clone, PartialEq)] // struct AddNumber(i32); // impl Pass for AddNumber { // type ChildDependencies = (); // type NodeDependencies = (); // type ParentDependencies = (AddNumber,); // type Ctx = (); // const MASK: NodeMask = NodeMask::new(); // fn pass<'a>( // &mut self, // node_view: NodeView, // node: ::ElementBorrowed<'a>, // parent: Option<::ElementBorrowed<'a>>, // children: Option< // impl Iterator::ElementBorrowed<'a>>, // >, // context: ::ElementBorrowed<'a>, // ) -> bool { // if let Some((parent,)) = parent { // *self.0 += *parent.0; // } // true // } // } // #[derive(Debug, Default, Clone, PartialEq)] // struct NumberState { // add_number: AddNumber, // } // impl AnyMapLike for NumberState { // fn get(&self) -> Option<&T> { // if TypeId::of::() == TypeId::of::() { // Some(unsafe { &*(&self.add_number as *const AddNumber as *const T) }) // } else { // None // } // } // fn get_mut(&mut self) -> Option<&mut T> { // if TypeId::of::() == TypeId::of::() { // Some(unsafe { &mut *(&mut self.add_number as *mut AddNumber as *mut T) }) // } else { // None // } // } // } // impl State for NumberState { // fn create_passes() -> Box<[TypeErasedPass]> { // Box::new([AddNumber::to_type_erased()]) // } // } // let mut tree: RealDom = RealDom::new(); // let parent = tree.root(); // let child1 = tree.create_node(1); // tree.add_child(parent, child1); // let grandchild1 = tree.create_node(1); // tree.add_child(child1, grandchild1); // let child2 = tree.create_node(1); // tree.add_child(parent, child2); // let grandchild2 = tree.create_node(1); // tree.add_child(child2, grandchild2); // tree.dirty_nodes // .insert(TypeId::of::(), NodeId(0)); // tree.update_state(SendAnyMap::new()); // assert_eq!(tree.get(tree.root()).unwrap().state.add_number.0, 1); // assert_eq!(tree.get(child1).unwrap().state.add_number.0, 2); // assert_eq!(tree.get(grandchild1).unwrap().state.add_number.0, 3); // assert_eq!(tree.get(child2).unwrap().state.add_number.0, 2); // assert_eq!(tree.get(grandchild2).unwrap().state.add_number.0, 3); // } // #[test] // fn dependant_down_pass() { // use crate::tree::{Tree, TreeLike}; // // 0 // let mut tree = Tree::new(1); // let parent = tree.root(); // // 1 // let child1 = tree.create_node(1); // tree.add_child(parent, child1); // // 2 // let grandchild1 = tree.create_node(1); // tree.add_child(child1, grandchild1); // // 3 // let child2 = tree.create_node(1); // tree.add_child(parent, child2); // // 4 // let grandchild2 = tree.create_node(1); // tree.add_child(child2, grandchild2); // struct AddPass; // impl Pass for AddPass { // fn pass_id(&self) -> PassId { // PassId(0) // } // fn dependancies(&self) -> &'static [PassId] { // &[PassId(1)] // } // fn dependants(&self) -> &'static [PassId] { // &[] // } // fn mask(&self) -> MemberMask { // MemberMask(0) // } // } // impl DownwardPass for AddPass { // fn pass(&self, node: &mut i32, parent: Option<&mut i32>, _: &SendAnyMap) -> PassReturn { // if let Some(parent) = parent { // *node += *parent; // } else { // } // PassReturn { // progress: true, // mark_dirty: true, // } // } // } // struct SubtractPass; // impl Pass for SubtractPass { // fn pass_id(&self) -> PassId { // PassId(1) // } // fn dependancies(&self) -> &'static [PassId] { // &[] // } // fn dependants(&self) -> &'static [PassId] { // &[PassId(0)] // } // fn mask(&self) -> MemberMask { // MemberMask(0) // } // } // impl DownwardPass for SubtractPass { // fn pass(&self, node: &mut i32, parent: Option<&mut i32>, _: &SendAnyMap) -> PassReturn { // if let Some(parent) = parent { // *node -= *parent; // } else { // } // PassReturn { // progress: true, // mark_dirty: true, // } // } // } // let add_pass = AnyPass::Downward(&AddPass); // let subtract_pass = AnyPass::Downward(&SubtractPass); // let passes = vec![&add_pass, &subtract_pass]; // let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default(); // dirty_nodes.insert(PassId(1), tree.root()); // resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new()); // // Tree before: // // 1=\ // // 1=\ // // 1 // // 1=\ // // 1 // // Tree after subtract: // // 1=\ // // 0=\ // // 1 // // 0=\ // // 1 // // Tree after add: // // 1=\ // // 1=\ // // 2 // // 1=\ // // 2 // assert_eq!(tree.get(tree.root()).unwrap(), &1); // assert_eq!(tree.get(child1).unwrap(), &1); // assert_eq!(tree.get(grandchild1).unwrap(), &2); // assert_eq!(tree.get(child2).unwrap(), &1); // assert_eq!(tree.get(grandchild2).unwrap(), &2); // } // #[test] // fn up_pass() { // use crate::tree::{Tree, TreeLike}; // // Tree before: // // 0=\ // // 0=\ // // 1 // // 0=\ // // 1 // // Tree after: // // 2=\ // // 1=\ // // 1 // // 1=\ // // 1 // let mut tree = Tree::new(0); // let parent = tree.root(); // let child1 = tree.create_node(0); // tree.add_child(parent, child1); // let grandchild1 = tree.create_node(1); // tree.add_child(child1, grandchild1); // let child2 = tree.create_node(0); // tree.add_child(parent, child2); // let grandchild2 = tree.create_node(1); // tree.add_child(child2, grandchild2); // struct AddPass; // impl Pass for AddPass { // fn pass_id(&self) -> PassId { // PassId(0) // } // fn dependancies(&self) -> &'static [PassId] { // &[] // } // fn dependants(&self) -> &'static [PassId] { // &[] // } // fn mask(&self) -> MemberMask { // MemberMask(0) // } // } // impl UpwardPass for AddPass { // fn pass<'a>( // &self, // node: &mut i32, // children: &mut dyn Iterator, // _: &SendAnyMap, // ) -> PassReturn { // *node += children.map(|i| *i).sum::(); // PassReturn { // progress: true, // mark_dirty: true, // } // } // } // let add_pass = AnyPass::Upward(&AddPass); // let passes = vec![&add_pass]; // let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default(); // dirty_nodes.insert(PassId(0), grandchild1); // dirty_nodes.insert(PassId(0), grandchild2); // resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new()); // assert_eq!(tree.get(tree.root()).unwrap(), &2); // assert_eq!(tree.get(child1).unwrap(), &1); // assert_eq!(tree.get(grandchild1).unwrap(), &1); // assert_eq!(tree.get(child2).unwrap(), &1); // assert_eq!(tree.get(grandchild2).unwrap(), &1); // } // #[test] // fn dependant_up_pass() { // use crate::tree::{Tree, TreeLike}; // // 0 // let mut tree = Tree::new(0); // let parent = tree.root(); // // 1 // let child1 = tree.create_node(0); // tree.add_child(parent, child1); // // 2 // let grandchild1 = tree.create_node(1); // tree.add_child(child1, grandchild1); // // 3 // let child2 = tree.create_node(0); // tree.add_child(parent, child2); // // 4 // let grandchild2 = tree.create_node(1); // tree.add_child(child2, grandchild2); // struct AddPass; // impl Pass for AddPass { // fn pass_id(&self) -> PassId { // PassId(0) // } // fn dependancies(&self) -> &'static [PassId] { // &[PassId(1)] // } // fn dependants(&self) -> &'static [PassId] { // &[] // } // fn mask(&self) -> MemberMask { // MemberMask(0) // } // } // impl UpwardPass for AddPass { // fn pass<'a>( // &self, // node: &mut i32, // children: &mut dyn Iterator, // _: &SendAnyMap, // ) -> PassReturn { // *node += children.map(|i| *i).sum::(); // PassReturn { // progress: true, // mark_dirty: true, // } // } // } // struct SubtractPass; // impl Pass for SubtractPass { // fn pass_id(&self) -> PassId { // PassId(1) // } // fn dependancies(&self) -> &'static [PassId] { // &[] // } // fn dependants(&self) -> &'static [PassId] { // &[PassId(0)] // } // fn mask(&self) -> MemberMask { // MemberMask(0) // } // } // impl UpwardPass for SubtractPass { // fn pass<'a>( // &self, // node: &mut i32, // children: &mut dyn Iterator, // _: &SendAnyMap, // ) -> PassReturn { // *node -= children.map(|i| *i).sum::(); // PassReturn { // progress: true, // mark_dirty: true, // } // } // } // let add_pass = AnyPass::Upward(&AddPass); // let subtract_pass = AnyPass::Upward(&SubtractPass); // let passes = vec![&add_pass, &subtract_pass]; // let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default(); // dirty_nodes.insert(PassId(1), grandchild1); // dirty_nodes.insert(PassId(1), grandchild2); // resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new()); // // Tree before: // // 0=\ // // 0=\ // // 1 // // 0=\ // // 1 // // Tree after subtract: // // 2=\ // // -1=\ // // 1 // // -1=\ // // 1 // // Tree after add: // // 2=\ // // 0=\ // // 1 // // 0=\ // // 1 // assert_eq!(tree.get(tree.root()).unwrap(), &2); // assert_eq!(tree.get(child1).unwrap(), &0); // assert_eq!(tree.get(grandchild1).unwrap(), &1); // assert_eq!(tree.get(child2).unwrap(), &0); // assert_eq!(tree.get(grandchild2).unwrap(), &1); // }