work on intigrating state with passes

This commit is contained in:
Evan Almloff committed 2022-11-26 15:25:02 -06:00
1 parent 4812b5124a
commit d78af904e6
5 files changed
+137 -108

No files matched your search

+7 -1
View File
@@ -1,3 +1,6 @@
use std::hash::BuildHasherDefault;
use rustc_hash::FxHasher;
use tree::NodeId;
pub mod layout_attributes;
@@ -10,7 +13,10 @@ pub mod tree;
pub mod utils;
/// A id for a node that lives in the real dom.
type RealNodeId = NodeId;
pub type RealNodeId = NodeId;
pub(crate) type FxDashMap<K, V> = dashmap::DashMap<K, V, BuildHasherDefault<FxHasher>>;
pub(crate) type FxDashSet<K> = dashmap::DashSet<K, BuildHasherDefault<FxHasher>>;
pub(crate) type SendAnyMap = anymap::Map<dyn anymap::any::Any + Send + Sync + 'static>;
/// Used in derived state macros
#[derive(Eq, PartialEq)]
+86 -67
View File
@@ -1,13 +1,11 @@
use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
use crate::tree::{NodeId, TreeView};
use crate::{FxDashMap, FxDashSet, SendAnyMap};
use rustc_hash::{FxHashMap, FxHashSet};
use std::collections::BTreeMap;
use std::hash::BuildHasherDefault;
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign};
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use crate::tree::{NodeId, TreeView};
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct DirtyNodes {
map: BTreeMap<u16, FxHashSet<NodeId>>,
@@ -57,8 +55,6 @@ fn dirty_nodes() {
assert_eq!(dirty_nodes.pop_front(), Some(NodeId(3)));
}
type FxDashMap<K, V> = dashmap::DashMap<K, V, BuildHasherDefault<FxHasher>>;
#[derive(Default)]
pub struct DirtyNodeStates {
dirty: FxDashMap<NodeId, Vec<AtomicU64>>,
@@ -167,7 +163,12 @@ pub trait Pass {
}
pub trait UpwardPass<T>: Pass {
fn pass<'a>(&self, node: &mut T, children: &mut dyn Iterator<Item = &'a mut T>) -> PassReturn;
fn pass<'a>(
&self,
node: &mut T,
children: &mut dyn Iterator<Item = &'a mut T>,
ctx: &SendAnyMap,
) -> PassReturn;
}
fn resolve_upward_pass<T, P: UpwardPass<T> + ?Sized>(
@@ -175,12 +176,15 @@ fn resolve_upward_pass<T, P: UpwardPass<T> + ?Sized>(
pass: &P,
mut dirty: DirtyNodes,
dirty_states: &DirtyNodeStates,
nodes_updated: &FxDashSet<NodeId>,
ctx: &SendAnyMap,
) {
while let Some(id) = dirty.pop_back() {
let (node, mut children) = tree.parent_child_mut(id).unwrap();
let result = pass.pass(node, &mut children);
let result = pass.pass(node, &mut children, ctx);
drop(children);
if result.progress || result.mark_dirty {
nodes_updated.insert(id);
if let Some(id) = tree.parent_id(id) {
if result.mark_dirty {
for dependant in pass.dependants() {
@@ -197,7 +201,7 @@ fn resolve_upward_pass<T, P: UpwardPass<T> + ?Sized>(
}
pub trait DownwardPass<T>: Pass {
fn pass(&self, node: &mut T, parent: Option<&mut T>) -> PassReturn;
fn pass(&self, node: &mut T, parent: Option<&mut T>, ctx: &SendAnyMap) -> PassReturn;
}
fn resolve_downward_pass<T, P: DownwardPass<T> + ?Sized>(
@@ -205,11 +209,14 @@ fn resolve_downward_pass<T, P: DownwardPass<T> + ?Sized>(
pass: &P,
mut dirty: DirtyNodes,
dirty_states: &DirtyNodeStates,
nodes_updated: &FxDashSet<NodeId>,
ctx: &SendAnyMap,
) {
while let Some(id) = dirty.pop_front() {
let (node, parent) = tree.node_parent_mut(id).unwrap();
let result = pass.pass(node, parent);
let result = pass.pass(node, parent, ctx);
if result.mark_dirty || result.progress {
nodes_updated.insert(id);
for id in tree.children_ids(id).unwrap() {
if result.mark_dirty {
for dependant in pass.dependants() {
@@ -226,7 +233,7 @@ fn resolve_downward_pass<T, P: DownwardPass<T> + ?Sized>(
}
pub trait NodePass<T>: Pass {
fn pass(&self, node: &mut T) -> bool;
fn pass(&self, node: &mut T, ctx: &SendAnyMap) -> bool;
}
fn resolve_node_pass<T, P: NodePass<T> + ?Sized>(
@@ -234,10 +241,13 @@ fn resolve_node_pass<T, P: NodePass<T> + ?Sized>(
pass: &P,
mut dirty: DirtyNodes,
dirty_states: &DirtyNodeStates,
nodes_updated: &FxDashSet<NodeId>,
ctx: &SendAnyMap,
) {
while let Some(id) = dirty.pop_back() {
let node = tree.get_mut(id).unwrap();
if pass.pass(node) {
if pass.pass(node, ctx) {
nodes_updated.insert(id);
for dependant in pass.dependants() {
dirty_states.insert(*dependant, id);
}
@@ -245,14 +255,14 @@ fn resolve_node_pass<T, P: NodePass<T> + ?Sized>(
}
}
pub enum AnyPass<T> {
Upward(Box<dyn UpwardPass<T> + Send + Sync>),
Downward(Box<dyn DownwardPass<T> + Send + Sync>),
Node(Box<dyn NodePass<T> + Send + Sync>),
pub enum AnyPass<T: 'static> {
Upward(&'static (dyn UpwardPass<T> + Send + Sync + 'static)),
Downward(&'static (dyn DownwardPass<T> + Send + Sync + 'static)),
Node(&'static (dyn NodePass<T> + Send + Sync + 'static)),
}
impl<T> AnyPass<T> {
fn pass_id(&self) -> PassId {
pub fn pass_id(&self) -> PassId {
match self {
Self::Upward(pass) => pass.pass_id(),
Self::Downward(pass) => pass.pass_id(),
@@ -260,7 +270,7 @@ impl<T> AnyPass<T> {
}
}
fn dependancies(&self) -> &'static [PassId] {
pub fn dependancies(&self) -> &'static [PassId] {
match self {
Self::Upward(pass) => pass.dependancies(),
Self::Downward(pass) => pass.dependancies(),
@@ -281,11 +291,19 @@ impl<T> AnyPass<T> {
tree: &mut impl TreeView<T>,
dirty: DirtyNodes,
dirty_states: &DirtyNodeStates,
nodes_updated: &FxDashSet<NodeId>,
ctx: &SendAnyMap,
) {
match self {
Self::Downward(pass) => resolve_downward_pass(tree, pass.as_ref(), dirty, dirty_states),
Self::Upward(pass) => resolve_upward_pass(tree, pass.as_ref(), dirty, dirty_states),
Self::Node(pass) => resolve_node_pass(tree, pass.as_ref(), dirty, dirty_states),
Self::Downward(pass) => {
resolve_downward_pass(tree, *pass, dirty, dirty_states, nodes_updated, ctx)
}
Self::Upward(pass) => {
resolve_upward_pass(tree, *pass, dirty, dirty_states, nodes_updated, ctx)
}
Self::Node(pass) => {
resolve_node_pass(tree, *pass, dirty, dirty_states, nodes_updated, ctx)
}
}
}
}
@@ -297,11 +315,14 @@ unsafe impl<T> Sync for RawPointer<T> {}
pub fn resolve_passes<T, Tr: TreeView<T>>(
tree: &mut Tr,
dirty_nodes: DirtyNodeStates,
mut passes: Vec<AnyPass<T>>,
) {
mut passes: Vec<&AnyPass<T>>,
ctx: SendAnyMap,
) -> FxDashSet<NodeId> {
let dirty_states = Arc::new(dirty_nodes);
let mut resolved_passes: FxHashSet<PassId> = FxHashSet::default();
let mut resolving = Vec::new();
let nodes_updated = Arc::new(FxDashSet::default());
let ctx = Arc::new(ctx);
while !passes.is_empty() {
let mut currently_borrowed = MemberMask::default();
std::thread::scope(|s| {
@@ -322,13 +343,16 @@ pub fn resolve_passes<T, Tr: TreeView<T>>(
let tree_mut = tree as *mut _;
let raw_ptr = RawPointer(tree_mut);
let dirty_states = dirty_states.clone();
let nodes_updated = nodes_updated.clone();
let ctx = ctx.clone();
s.spawn(move || unsafe {
// let tree_mut: &mut Tr = &mut *raw_ptr.0;
let raw = raw_ptr;
// 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
let tree_mut: &mut Tr = &mut *raw.0;
let mut dirty = DirtyNodes::default();
dirty_states.all_dirty(pass_id, &mut dirty, tree_mut);
pass.resolve(tree_mut, dirty, &dirty_states);
pass.resolve(tree_mut, dirty, &dirty_states, &nodes_updated, &ctx);
});
} else {
i += 1;
@@ -339,14 +363,13 @@ pub fn resolve_passes<T, Tr: TreeView<T>>(
resolved_passes.extend(resolving.iter().copied());
resolving.clear()
}
std::sync::Arc::try_unwrap(nodes_updated).unwrap()
}
#[test]
fn node_pass() {
use crate::tree::{Tree, TreeLike};
let mut tree = Tree::new(0);
let parent = tree.root();
println!("{:#?}", tree);
struct AddPass;
impl Pass for AddPass {
@@ -368,16 +391,17 @@ fn node_pass() {
}
impl NodePass<i32> for AddPass {
fn pass(&self, node: &mut i32) -> bool {
fn pass(&self, node: &mut i32, _: &SendAnyMap) -> bool {
*node += 1;
true
}
}
let passes = vec![AnyPass::Node(Box::new(AddPass))];
let add_pass = AnyPass::Node(&AddPass);
let passes = vec![&add_pass];
let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default();
dirty_nodes.insert(PassId(0), tree.root());
resolve_passes(&mut tree, dirty_nodes, passes);
resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new());
assert_eq!(tree.get(tree.root()).unwrap(), &1);
}
@@ -407,8 +431,7 @@ fn dependant_node_pass() {
}
impl NodePass<i32> for AddPass {
fn pass(&self, node: &mut i32) -> bool {
println!("AddPass: {}", node);
fn pass(&self, node: &mut i32, _: &SendAnyMap) -> bool {
*node += 1;
true
}
@@ -434,20 +457,18 @@ fn dependant_node_pass() {
}
}
impl NodePass<i32> for SubtractPass {
fn pass(&self, node: &mut i32) -> bool {
println!("SubtractPass: {}", node);
fn pass(&self, node: &mut i32, _: &SendAnyMap) -> bool {
*node -= 1;
true
}
}
let passes = vec![
AnyPass::Node(Box::new(AddPass)),
AnyPass::Node(Box::new(SubtractPass)),
];
let add_pass = AnyPass::Node(&AddPass);
let subtract_pass = AnyPass::Node(&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);
resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new());
assert_eq!(*tree.get(tree.root()).unwrap(), 0);
}
@@ -477,7 +498,7 @@ fn independant_node_pass() {
}
impl NodePass<(i32, i32)> for AddPass1 {
fn pass(&self, node: &mut (i32, i32)) -> bool {
fn pass(&self, node: &mut (i32, i32), _: &SendAnyMap) -> bool {
node.0 += 1;
true
}
@@ -503,20 +524,19 @@ fn independant_node_pass() {
}
impl NodePass<(i32, i32)> for AddPass2 {
fn pass(&self, node: &mut (i32, i32)) -> bool {
fn pass(&self, node: &mut (i32, i32), _: &SendAnyMap) -> bool {
node.1 += 1;
true
}
}
let passes = vec![
AnyPass::Node(Box::new(AddPass1)),
AnyPass::Node(Box::new(AddPass2)),
];
let add_pass1 = AnyPass::Node(&AddPass1);
let add_pass2 = AnyPass::Node(&AddPass2);
let passes = vec![&add_pass1, &add_pass2];
let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default();
dirty_nodes.insert(PassId(0), tree.root());
dirty_nodes.insert(PassId(1), tree.root());
resolve_passes(&mut tree, dirty_nodes, passes);
resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new());
assert_eq!(tree.get(tree.root()).unwrap(), &(1, 1));
}
@@ -555,7 +575,7 @@ fn down_pass() {
}
}
impl DownwardPass<i32> for AddPass {
fn pass(&self, node: &mut i32, parent: Option<&mut i32>) -> PassReturn {
fn pass(&self, node: &mut i32, parent: Option<&mut i32>, _: &SendAnyMap) -> PassReturn {
if let Some(parent) = parent {
*node += *parent;
}
@@ -566,10 +586,11 @@ fn down_pass() {
}
}
let passes = vec![AnyPass::Downward(Box::new(AddPass))];
let add_pass = AnyPass::Downward(&AddPass);
let passes = vec![&add_pass];
let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default();
dirty_nodes.insert(PassId(0), tree.root());
resolve_passes(&mut tree, dirty_nodes, passes);
resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new());
assert_eq!(tree.get(tree.root()).unwrap(), &1);
assert_eq!(tree.get(child1).unwrap(), &2);
@@ -616,12 +637,10 @@ fn dependant_down_pass() {
}
}
impl DownwardPass<i32> for AddPass {
fn pass(&self, node: &mut i32, parent: Option<&mut i32>) -> PassReturn {
fn pass(&self, node: &mut i32, parent: Option<&mut i32>, _: &SendAnyMap) -> PassReturn {
if let Some(parent) = parent {
println!("AddPass: {} -> {}", node, *node + *parent);
*node += *parent;
} else {
println!("AddPass: {}", node);
}
PassReturn {
progress: true,
@@ -649,12 +668,10 @@ fn dependant_down_pass() {
}
}
impl DownwardPass<i32> for SubtractPass {
fn pass(&self, node: &mut i32, parent: Option<&mut i32>) -> PassReturn {
fn pass(&self, node: &mut i32, parent: Option<&mut i32>, _: &SendAnyMap) -> PassReturn {
if let Some(parent) = parent {
println!("SubtractPass: {} -> {}", node, *node - *parent);
*node -= *parent;
} else {
println!("SubtractPass: {}", node);
}
PassReturn {
progress: true,
@@ -663,13 +680,12 @@ fn dependant_down_pass() {
}
}
let passes = vec![
AnyPass::Downward(Box::new(AddPass)),
AnyPass::Downward(Box::new(SubtractPass)),
];
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);
resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new());
// Tree before:
// 1=\
@@ -745,6 +761,7 @@ fn up_pass() {
&self,
node: &mut i32,
children: &mut dyn Iterator<Item = &'a mut i32>,
_: &SendAnyMap,
) -> PassReturn {
*node += children.map(|i| *i).sum::<i32>();
PassReturn {
@@ -754,11 +771,12 @@ fn up_pass() {
}
}
let passes = vec![AnyPass::Upward(Box::new(AddPass))];
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);
resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new());
assert_eq!(tree.get(tree.root()).unwrap(), &2);
assert_eq!(tree.get(child1).unwrap(), &1);
@@ -809,6 +827,7 @@ fn dependant_up_pass() {
&self,
node: &mut i32,
children: &mut dyn Iterator<Item = &'a mut i32>,
_: &SendAnyMap,
) -> PassReturn {
*node += children.map(|i| *i).sum::<i32>();
PassReturn {
@@ -841,6 +860,7 @@ fn dependant_up_pass() {
&self,
node: &mut i32,
children: &mut dyn Iterator<Item = &'a mut i32>,
_: &SendAnyMap,
) -> PassReturn {
*node -= children.map(|i| *i).sum::<i32>();
PassReturn {
@@ -850,14 +870,13 @@ fn dependant_up_pass() {
}
}
let passes = vec![
AnyPass::Upward(Box::new(AddPass)),
AnyPass::Upward(Box::new(SubtractPass)),
];
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);
resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new());
// Tree before:
// 0=\
+20 -28
View File
@@ -1,13 +1,13 @@
use anymap::AnyMap;
use dioxus_core::{ElementId, Mutations};
use rustc_hash::{FxHashMap, FxHashSet};
use std::ops::{Index, IndexMut};
use crate::node::{Node, NodeData, NodeType, OwnedAttributeDiscription};
use crate::node::{Node, NodeType, OwnedAttributeDiscription};
use crate::node_ref::{AttributeMask, NodeMask};
use crate::passes::DirtyNodeStates;
use crate::state::State;
use crate::tree::{NodeId, Tree, TreeLike, TreeView};
use crate::RealNodeId;
use crate::{FxDashSet, RealNodeId, SendAnyMap};
fn mark_dirty(
node_id: NodeId,
@@ -96,10 +96,7 @@ impl<S: State> RealDom<S> {
}
/// Updates the dom with some mutations and return a set of nodes that were updated. Pass the dirty nodes to update_state.
pub fn apply_mutations(
&mut self,
mutations_vec: Vec<Mutations>,
) -> FxHashMap<RealNodeId, NodeMask> {
pub fn apply_mutations(&mut self, mutations_vec: Vec<Mutations>) -> DirtyNodeStates {
let mut nodes_updated: FxHashMap<RealNodeId, NodeMask> = FxHashMap::default();
for mutations in mutations_vec {
for e in mutations.edits {
@@ -346,20 +343,28 @@ impl<S: State> RealDom<S> {
}
}
// remove any nodes that were created and then removed in the same mutations from the dirty nodes list
nodes_updated.retain(|k, _| self.tree.get(*k).is_some());
let dirty_nodes = DirtyNodeStates::default();
for (n, 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) {
for (m, p) in S::MASKS.iter().zip(S::PASSES.iter()) {
if mask.overlaps(m) {
dirty_nodes.insert(p.pass_id(), n);
}
}
}
}
nodes_updated
dirty_nodes
}
/// Update the state of the dom, after appling some mutations. This will keep the nodes in the dom up to date with their VNode counterparts.
pub fn update_state(
&mut self,
nodes_updated: FxHashMap<RealNodeId, NodeMask>,
ctx: AnyMap,
) -> FxHashSet<RealNodeId> {
let (mut state_tree, node_tree) = self.split();
S::update(&nodes_updated, &mut state_tree, &node_tree, &ctx)
nodes_updated: DirtyNodeStates,
ctx: SendAnyMap,
) -> FxDashSet<RealNodeId> {
S::update(nodes_updated, &mut self.tree, ctx)
}
/// Find all nodes that are listening for an event, sorted by there height in the dom progressing starting at the bottom and progressing up.
@@ -389,19 +394,6 @@ impl<S: State> RealDom<S> {
self.tree.root()
}
pub fn split(&mut self) -> (impl TreeView<S> + '_, impl TreeView<NodeData> + '_) {
let raw = self as *mut Self;
// this is safe beacuse the treeview trait does not allow mutation of the position of elements, and within elements the access is disjoint.
(
unsafe { &mut *raw }
.tree
.map(|n| &n.state, |n| &mut n.state),
unsafe { &mut *raw }
.tree
.map(|n| &n.node_data, |n| &mut n.node_data),
)
}
fn clone_node(&mut self, node_id: NodeId) -> RealNodeId {
let node = self.tree.get(node_id).unwrap();
let new_node = node.clone();
+20 -12
View File
@@ -1,11 +1,10 @@
use std::cmp::Ordering;
use crate::node::NodeData;
use crate::node::Node;
use crate::node_ref::{NodeMask, NodeView};
use crate::passes::{resolve_passes, AnyPass, DirtyNodeStates};
use crate::tree::TreeView;
use crate::RealNodeId;
use anymap::AnyMap;
use rustc_hash::{FxHashMap, FxHashSet};
use crate::{FxDashSet, RealNodeId, SendAnyMap};
/// Join two sorted iterators
pub(crate) fn union_ordered_iter<'a>(
@@ -204,20 +203,29 @@ pub trait NodeDepState {
fn reduce<'a>(
&mut self,
node: NodeView,
siblings: <Self::DepState as ElementBorrowable>::ElementBorrowed<'a>,
node_state: <Self::DepState as ElementBorrowable>::ElementBorrowed<'a>,
ctx: &Self::Ctx,
) -> bool;
}
/// Do not implement this trait. It is only meant to be derived and used through [crate::real_dom::RealDom].
pub trait State: Default + Clone {
pub trait State: Default + Clone + 'static {
#[doc(hidden)]
fn update<'a, T: TreeView<Self>, T2: TreeView<NodeData>>(
dirty: &FxHashMap<RealNodeId, NodeMask>,
state_tree: &'a mut T,
rdom: &'a T2,
ctx: &AnyMap,
) -> FxHashSet<RealNodeId>;
const PASSES: &'static [AnyPass<Node<Self>>];
#[doc(hidden)]
const MASKS: &'static [NodeMask];
#[doc(hidden)]
fn update<T: TreeView<Node<Self>>>(
dirty: DirtyNodeStates,
tree: &mut T,
ctx: SendAnyMap,
) -> FxDashSet<RealNodeId> {
let set = FxDashSet::default();
let passes = Self::PASSES.iter().collect();
resolve_passes(tree, dirty, passes, ctx);
set
}
}
impl ChildDepState for () {
+4
View File
@@ -73,6 +73,10 @@ pub trait TreeView<T>: Sized {
fn root(&self) -> NodeId;
fn contains(&self, id: NodeId) -> bool {
self.get(id).is_some()
}
fn get(&self, id: NodeId) -> Option<&T>;
fn get_unchecked(&self, id: NodeId) -> &T {