diff --git a/packages/native-core/src/passes.rs b/packages/native-core/src/passes.rs index 3f0ac6e58..8dd275575 100644 --- a/packages/native-core/src/passes.rs +++ b/packages/native-core/src/passes.rs @@ -19,8 +19,6 @@ pub trait Pass: Any { type ChildDependencies: Dependancy; /// This is a tuple of (T: Any, ..) type NodeDependencies: Dependancy; - /// This is a tuple of (T: Any, ..) - type Ctx: Dependancy; const NODE_MASK: NodeMask; fn pass<'a>( @@ -31,22 +29,22 @@ pub trait Pass: Any { children: Option< impl Iterator::ElementBorrowed<'a>>, >, - context: ::ElementBorrowed<'a>, + context: &SendAnyMap, ) -> bool; - fn is_valid(&self) -> bool { + fn validate() { // no type can be a child and parent dependency for type_id in Self::parent_type_ids() { for type_id2 in Self::child_type_ids() { if type_id == type_id2 { - return false; + 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() { if type_id == TypeId::of::() { - return false; + panic!("The current type cannot be a node dependency"); } } // no states have the same type id @@ -56,18 +54,20 @@ pub trait Pass: Any { .len() != Self::all_dependanices().len() { - return false; + panic!("all states must have unique type ids"); } - true } 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().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(), @@ -96,8 +96,6 @@ pub trait Pass: Any { .get_mut() .expect("tried to get a pass that does not exist") }; - let context = Self::Ctx::borrow_elements_from(context) - .expect("tried to get a pass that does not exist"); myself.pass( NodeView::new(¤t_node.node_data, Self::NODE_MASK), node, @@ -149,11 +147,13 @@ pub trait Pass: Any { 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, - pass_direction: PassDirection, + pub(crate) pass_direction: PassDirection, } impl TypeErasedPass { @@ -183,6 +183,7 @@ impl TypeErasedPass { } PassDirection::ChildToParent => { while let Some(id) = dirty.pop_back() { + println!("running pass {:?} on {:?}", self.this_type_id, id); if (self.pass)(id, tree, ctx) { nodes_updated.insert(id); if let Some(id) = tree.parent_id(id) { @@ -210,6 +211,7 @@ impl TypeErasedPass { } } +#[derive(Debug)] pub enum PassDirection { ParentToChild, ChildToParent, @@ -248,7 +250,6 @@ pub trait Dependancy { where Self: 'a; - fn borrow_elements(&self) -> Self::ElementBorrowed<'_>; fn borrow_elements_from(map: &T) -> Option>; fn type_ids() -> Vec; } @@ -258,12 +259,6 @@ macro_rules! impl_dependancy { impl< $($t: Any),* > Dependancy for ($($t,)*) { type ElementBorrowed<'a> = ($(&'a $t,)*) where Self: 'a; - #[allow(clippy::unused_unit, non_snake_case)] - fn borrow_elements<'a>(&'a self) -> Self::ElementBorrowed<'a> { - let ($($t,)*) = self; - ($($t,)*) - } - #[allow(unused_variables, clippy::unused_unit, non_snake_case)] fn borrow_elements_from(map: &T) -> Option> { Some(($(map.get::<$t>()?,)*)) @@ -391,15 +386,13 @@ pub fn resolve_passes( 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) - { + 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); - // this is safe because the member_mask acts as a per-member mutex and we have verified that the pass does not overlap with any other pass + // this is safe because each pass only has mutable access to the member associated with this_type_id and we have verified that the pass does not overlap with any other pass currently running let tree_unbounded_mut = unsafe { &mut *(tree as *mut _) }; let dirty_states = dirty_states.clone(); let nodes_updated = nodes_updated.clone(); diff --git a/packages/native-core/src/real_dom.rs b/packages/native-core/src/real_dom.rs index a106bc1ab..2093a4359 100644 --- a/packages/native-core/src/real_dom.rs +++ b/packages/native-core/src/real_dom.rs @@ -1,6 +1,5 @@ use dioxus_core::{ElementId, Mutations, TemplateNode}; use rustc_hash::{FxHashMap, FxHashSet}; -use std::any::TypeId; use std::fmt::Debug; use std::ops::{Index, IndexMut}; @@ -25,9 +24,10 @@ pub struct RealDom { templates: FxHashMap>, pub(crate) passes: Box<[TypeErasedPass]>, pub(crate) nodes_updated: FxHashMap, - passes_updated: FxHashMap>, + passes_updated: DirtyNodeStates, parent_changed_nodes: FxHashSet, child_changed_nodes: FxHashSet, + nodes_created: FxHashSet, } impl Debug for RealDom { @@ -75,6 +75,14 @@ impl RealDom { } } } + + for pass in passes.iter_mut() { + println!("{:?}: {:?}", pass.this_type_id, pass.dependants); + println!("{:?}", pass.child_dependant); + println!("{:?}", pass.parent_dependant); + println!("{:?}", pass.pass_direction); + } + let mut nodes_updated = FxHashMap::default(); let root_id = NodeId(0); nodes_updated.insert(root_id, NodeMask::ALL); @@ -87,9 +95,10 @@ impl RealDom { templates: FxHashMap::default(), passes, nodes_updated, - passes_updated: FxHashMap::default(), + passes_updated: DirtyNodeStates::default(), parent_changed_nodes: FxHashSet::default(), child_changed_nodes: FxHashSet::default(), + nodes_created: FxHashSet::default(), } } @@ -140,7 +149,7 @@ impl RealDom { let node = self.tree.get_mut(node_id).unwrap(); node.node_data.node_id = node_id; if mark_dirty { - self.nodes_updated.insert(node_id, NodeMask::ALL); + self.nodes_created.insert(node_id); } node_id } @@ -370,22 +379,50 @@ impl RealDom { &mut self, ctx: SendAnyMap, ) -> (FxDashSet, FxHashMap) { - let tree = &mut self.tree; let passes = &self.passes; - let dirty_nodes = DirtyNodeStates::default(); + let dirty_nodes = std::mem::take(&mut self.passes_updated); let nodes_updated = std::mem::take(&mut self.nodes_updated); - for (&n, mask) in &nodes_updated { + for (&node, mask) in &nodes_updated { // remove any nodes that were created and then removed in the same mutations from the dirty nodes list - if self.tree.contains(n) { + if self.tree.contains(node) { for pass in &*self.passes { if mask.overlaps(&pass.mask) { - dirty_nodes.insert(pass.this_type_id, n); + dirty_nodes.insert(pass.this_type_id, node); } } } } + for node in std::mem::take(&mut self.child_changed_nodes) { + // remove any nodes that were created and then removed in the same mutations from the dirty nodes list + if self.tree.contains(node) { + for pass in &*self.passes { + if pass.child_dependant { + dirty_nodes.insert(pass.this_type_id, node); + } + } + } + } + for node in std::mem::take(&mut self.parent_changed_nodes) { + // remove any nodes that were created and then removed in the same mutations from the dirty nodes list + if self.tree.contains(node) { + for pass in &*self.passes { + if pass.parent_dependant { + dirty_nodes.insert(pass.this_type_id, node); + } + } + } + } + for node in std::mem::take(&mut self.nodes_created) { + // remove any nodes that were created and then removed in the same mutations from the dirty nodes list + if self.tree.contains(node) { + for pass in &*self.passes { + dirty_nodes.insert(pass.this_type_id, node); + } + } + } + + let tree = &mut self.tree; - todo!("incorporate other update members"); ( resolve_passes(tree, dirty_nodes, passes, ctx), nodes_updated, @@ -428,10 +465,7 @@ impl RealDom { let new_id = self.create_node(new_node, false); let passes = S::non_clone_members(); for pass_id in &*passes { - self.passes_updated - .entry(node_id) - .or_default() - .insert(*pass_id); + self.passes_updated.insert(*pass_id, node_id); } let self_ptr = self as *mut Self; diff --git a/packages/native-core/src/tree.rs b/packages/native-core/src/tree.rs index 5c14d159f..0d965ae09 100644 --- a/packages/native-core/src/tree.rs +++ b/packages/native-core/src/tree.rs @@ -1,11 +1,6 @@ -use core::panic; -use parking_lot::lock_api::RawMutex as _; -use parking_lot::{RawMutex, RwLock}; use slab::Slab; -use std::cell::UnsafeCell; use std::collections::VecDeque; use std::marker::PhantomData; -use std::sync::Arc; #[derive(Hash, PartialEq, Eq, Clone, Copy, Debug, PartialOrd, Ord)] pub struct NodeId(pub usize); diff --git a/packages/tui/src/focus.rs b/packages/tui/src/focus.rs index 6e403f986..1529c61da 100644 --- a/packages/tui/src/focus.rs +++ b/packages/tui/src/focus.rs @@ -3,7 +3,7 @@ use crate::{node::PreventDefault, TuiDom}; use dioxus_native_core::{ tree::TreeView, utils::{ElementProduced, PersistantElementIter}, - NodeId, Pass, + NodeId, Pass, SendAnyMap, }; use dioxus_native_core_macro::sorted_str_slice; @@ -62,7 +62,6 @@ pub(crate) struct Focus { } impl Pass for Focus { - type Ctx = (); const NODE_MASK: NodeMask = NodeMask::new_with_attrs(AttributeMask::Static(FOCUS_ATTRIBUTES)).with_listeners(); @@ -73,18 +72,18 @@ impl Pass for Focus { fn pass<'a>( &mut self, node_view: NodeView, - node: ::ElementBorrowed<'a>, - parent: Option< + _: ::ElementBorrowed<'a>, + _: Option< ::ElementBorrowed<'a>, >, - children: Option< + _: Option< impl Iterator< Item = ::ElementBorrowed< 'a, >, >, >, - context: ::ElementBorrowed<'a>, + _: &SendAnyMap, ) -> bool { let new = Focus { level: if let Some(a) = node_view diff --git a/packages/tui/src/layout.rs b/packages/tui/src/layout.rs index ad709f6e6..eaa7b6139 100644 --- a/packages/tui/src/layout.rs +++ b/packages/tui/src/layout.rs @@ -3,7 +3,7 @@ use std::sync::{Arc, Mutex}; use dioxus_native_core::layout_attributes::apply_layout_attributes; use dioxus_native_core::node::OwnedAttributeView; use dioxus_native_core::node_ref::{AttributeMask, NodeMask, NodeView}; -use dioxus_native_core::Pass; +use dioxus_native_core::{Pass, SendAnyMap}; use dioxus_native_core_macro::sorted_str_slice; use taffy::prelude::*; @@ -14,6 +14,7 @@ pub(crate) enum PossiblyUninitalized { Uninitalized, Initialized(T), } + impl PossiblyUninitalized { pub fn unwrap(self) -> T { match self { @@ -41,7 +42,6 @@ pub(crate) struct TaffyLayout { } impl Pass for TaffyLayout { - type Ctx = (Arc>,); type ChildDependencies = (Self,); type ParentDependencies = (); type NodeDependencies = (); @@ -52,8 +52,8 @@ impl Pass for TaffyLayout { fn pass<'a>( &mut self, node_view: NodeView, - node: ::ElementBorrowed<'a>, - parent: Option< + _: ::ElementBorrowed<'a>, + _: Option< ::ElementBorrowed<'a>, >, children: Option< @@ -63,9 +63,11 @@ impl Pass for TaffyLayout { >, >, >, - (taffy,): ::ElementBorrowed<'a>, + ctx: &SendAnyMap, ) -> bool { + println!("running layout pass on node: \n{:#?}", node_view); let mut changed = false; + let taffy: &Arc> = ctx.get().unwrap(); let mut taffy = taffy.lock().expect("poisoned taffy"); let mut style = Style::default(); if let Some(text) = node_view.text() { diff --git a/packages/tui/src/node.rs b/packages/tui/src/node.rs index 1321f6040..759424d62 100644 --- a/packages/tui/src/node.rs +++ b/packages/tui/src/node.rs @@ -1,7 +1,7 @@ use crate::focus::Focus; use crate::layout::TaffyLayout; use crate::style_attributes::StyleModifier; -use dioxus_native_core::{real_dom::RealDom, Dependancy, Pass}; +use dioxus_native_core::{real_dom::RealDom, Dependancy, Pass, SendAnyMap}; use dioxus_native_core_macro::{sorted_str_slice, AnyMapLike, State}; pub(crate) type TuiDom = RealDom; @@ -48,8 +48,6 @@ impl Pass for PreventDefault { type ChildDependencies = (); type NodeDependencies = (); - type Ctx = (); - const NODE_MASK: dioxus_native_core::node_ref::NodeMask = dioxus_native_core::node_ref::NodeMask::new_with_attrs( dioxus_native_core::node_ref::AttributeMask::Static(&sorted_str_slice!([ @@ -66,7 +64,7 @@ impl Pass for PreventDefault { children: Option< impl Iterator::ElementBorrowed<'a>>, >, - context: ::ElementBorrowed<'a>, + context: &SendAnyMap, ) -> bool { let new = match node_view.attributes().and_then(|mut attrs| { attrs diff --git a/packages/tui/src/style_attributes.rs b/packages/tui/src/style_attributes.rs index 484b1c52c..e6f5d5527 100644 --- a/packages/tui/src/style_attributes.rs +++ b/packages/tui/src/style_attributes.rs @@ -33,7 +33,7 @@ use dioxus_native_core::{ layout_attributes::parse_value, node::OwnedAttributeView, node_ref::{AttributeMask, NodeMask, NodeView}, - Pass, + Pass, SendAnyMap, }; use dioxus_native_core_macro::sorted_str_slice; use taffy::prelude::*; @@ -47,7 +47,6 @@ pub struct StyleModifier { } impl Pass for StyleModifier { - type Ctx = (); type ParentDependencies = (Self,); type ChildDependencies = (); type NodeDependencies = (); @@ -59,18 +58,18 @@ impl Pass for StyleModifier { fn pass<'a>( &mut self, node_view: NodeView, - node: ::ElementBorrowed<'a>, + _: ::ElementBorrowed<'a>, parent: Option< ::ElementBorrowed<'a>, >, - children: Option< + _: Option< impl Iterator< Item = ::ElementBorrowed< 'a, >, >, >, - context: ::ElementBorrowed<'a>, + _: &SendAnyMap, ) -> bool { let mut new = StyleModifier::default(); if parent.is_some() {