work on intigrating state with passes
This commit is contained in:
1 parent
4812b5124a
commit
d78af904e6
5 files changed
+137
-108
No files matched your search
@@ -1,3 +1,6 @@
|
|||||||
|
use std::hash::BuildHasherDefault;
|
||||||
|
|
||||||
|
use rustc_hash::FxHasher;
|
||||||
use tree::NodeId;
|
use tree::NodeId;
|
||||||
|
|
||||||
pub mod layout_attributes;
|
pub mod layout_attributes;
|
||||||
@@ -10,7 +13,10 @@ pub mod tree;
|
|||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
/// A id for a node that lives in the real dom.
|
/// 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
|
/// Used in derived state macros
|
||||||
#[derive(Eq, PartialEq)]
|
#[derive(Eq, PartialEq)]
|
||||||
|
|||||||
@@ -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::collections::BTreeMap;
|
||||||
use std::hash::BuildHasherDefault;
|
|
||||||
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign};
|
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign};
|
||||||
|
|
||||||
use std::sync::atomic::{AtomicU64, Ordering};
|
use std::sync::atomic::{AtomicU64, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::tree::{NodeId, TreeView};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||||
pub struct DirtyNodes {
|
pub struct DirtyNodes {
|
||||||
map: BTreeMap<u16, FxHashSet<NodeId>>,
|
map: BTreeMap<u16, FxHashSet<NodeId>>,
|
||||||
@@ -57,8 +55,6 @@ fn dirty_nodes() {
|
|||||||
assert_eq!(dirty_nodes.pop_front(), Some(NodeId(3)));
|
assert_eq!(dirty_nodes.pop_front(), Some(NodeId(3)));
|
||||||
}
|
}
|
||||||
|
|
||||||
type FxDashMap<K, V> = dashmap::DashMap<K, V, BuildHasherDefault<FxHasher>>;
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct DirtyNodeStates {
|
pub struct DirtyNodeStates {
|
||||||
dirty: FxDashMap<NodeId, Vec<AtomicU64>>,
|
dirty: FxDashMap<NodeId, Vec<AtomicU64>>,
|
||||||
@@ -167,7 +163,12 @@ pub trait Pass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait UpwardPass<T>: 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>(
|
fn resolve_upward_pass<T, P: UpwardPass<T> + ?Sized>(
|
||||||
@@ -175,12 +176,15 @@ fn resolve_upward_pass<T, P: UpwardPass<T> + ?Sized>(
|
|||||||
pass: &P,
|
pass: &P,
|
||||||
mut dirty: DirtyNodes,
|
mut dirty: DirtyNodes,
|
||||||
dirty_states: &DirtyNodeStates,
|
dirty_states: &DirtyNodeStates,
|
||||||
|
nodes_updated: &FxDashSet<NodeId>,
|
||||||
|
ctx: &SendAnyMap,
|
||||||
) {
|
) {
|
||||||
while let Some(id) = dirty.pop_back() {
|
while let Some(id) = dirty.pop_back() {
|
||||||
let (node, mut children) = tree.parent_child_mut(id).unwrap();
|
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);
|
drop(children);
|
||||||
if result.progress || result.mark_dirty {
|
if result.progress || result.mark_dirty {
|
||||||
|
nodes_updated.insert(id);
|
||||||
if let Some(id) = tree.parent_id(id) {
|
if let Some(id) = tree.parent_id(id) {
|
||||||
if result.mark_dirty {
|
if result.mark_dirty {
|
||||||
for dependant in pass.dependants() {
|
for dependant in pass.dependants() {
|
||||||
@@ -197,7 +201,7 @@ fn resolve_upward_pass<T, P: UpwardPass<T> + ?Sized>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait DownwardPass<T>: Pass {
|
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>(
|
fn resolve_downward_pass<T, P: DownwardPass<T> + ?Sized>(
|
||||||
@@ -205,11 +209,14 @@ fn resolve_downward_pass<T, P: DownwardPass<T> + ?Sized>(
|
|||||||
pass: &P,
|
pass: &P,
|
||||||
mut dirty: DirtyNodes,
|
mut dirty: DirtyNodes,
|
||||||
dirty_states: &DirtyNodeStates,
|
dirty_states: &DirtyNodeStates,
|
||||||
|
nodes_updated: &FxDashSet<NodeId>,
|
||||||
|
ctx: &SendAnyMap,
|
||||||
) {
|
) {
|
||||||
while let Some(id) = dirty.pop_front() {
|
while let Some(id) = dirty.pop_front() {
|
||||||
let (node, parent) = tree.node_parent_mut(id).unwrap();
|
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 {
|
if result.mark_dirty || result.progress {
|
||||||
|
nodes_updated.insert(id);
|
||||||
for id in tree.children_ids(id).unwrap() {
|
for id in tree.children_ids(id).unwrap() {
|
||||||
if result.mark_dirty {
|
if result.mark_dirty {
|
||||||
for dependant in pass.dependants() {
|
for dependant in pass.dependants() {
|
||||||
@@ -226,7 +233,7 @@ fn resolve_downward_pass<T, P: DownwardPass<T> + ?Sized>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait NodePass<T>: Pass {
|
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>(
|
fn resolve_node_pass<T, P: NodePass<T> + ?Sized>(
|
||||||
@@ -234,10 +241,13 @@ fn resolve_node_pass<T, P: NodePass<T> + ?Sized>(
|
|||||||
pass: &P,
|
pass: &P,
|
||||||
mut dirty: DirtyNodes,
|
mut dirty: DirtyNodes,
|
||||||
dirty_states: &DirtyNodeStates,
|
dirty_states: &DirtyNodeStates,
|
||||||
|
nodes_updated: &FxDashSet<NodeId>,
|
||||||
|
ctx: &SendAnyMap,
|
||||||
) {
|
) {
|
||||||
while let Some(id) = dirty.pop_back() {
|
while let Some(id) = dirty.pop_back() {
|
||||||
let node = tree.get_mut(id).unwrap();
|
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() {
|
for dependant in pass.dependants() {
|
||||||
dirty_states.insert(*dependant, id);
|
dirty_states.insert(*dependant, id);
|
||||||
}
|
}
|
||||||
@@ -245,14 +255,14 @@ fn resolve_node_pass<T, P: NodePass<T> + ?Sized>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum AnyPass<T> {
|
pub enum AnyPass<T: 'static> {
|
||||||
Upward(Box<dyn UpwardPass<T> + Send + Sync>),
|
Upward(&'static (dyn UpwardPass<T> + Send + Sync + 'static)),
|
||||||
Downward(Box<dyn DownwardPass<T> + Send + Sync>),
|
Downward(&'static (dyn DownwardPass<T> + Send + Sync + 'static)),
|
||||||
Node(Box<dyn NodePass<T> + Send + Sync>),
|
Node(&'static (dyn NodePass<T> + Send + Sync + 'static)),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AnyPass<T> {
|
impl<T> AnyPass<T> {
|
||||||
fn pass_id(&self) -> PassId {
|
pub fn pass_id(&self) -> PassId {
|
||||||
match self {
|
match self {
|
||||||
Self::Upward(pass) => pass.pass_id(),
|
Self::Upward(pass) => pass.pass_id(),
|
||||||
Self::Downward(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 {
|
match self {
|
||||||
Self::Upward(pass) => pass.dependancies(),
|
Self::Upward(pass) => pass.dependancies(),
|
||||||
Self::Downward(pass) => pass.dependancies(),
|
Self::Downward(pass) => pass.dependancies(),
|
||||||
@@ -281,11 +291,19 @@ impl<T> AnyPass<T> {
|
|||||||
tree: &mut impl TreeView<T>,
|
tree: &mut impl TreeView<T>,
|
||||||
dirty: DirtyNodes,
|
dirty: DirtyNodes,
|
||||||
dirty_states: &DirtyNodeStates,
|
dirty_states: &DirtyNodeStates,
|
||||||
|
nodes_updated: &FxDashSet<NodeId>,
|
||||||
|
ctx: &SendAnyMap,
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
Self::Downward(pass) => resolve_downward_pass(tree, pass.as_ref(), dirty, dirty_states),
|
Self::Downward(pass) => {
|
||||||
Self::Upward(pass) => resolve_upward_pass(tree, pass.as_ref(), dirty, dirty_states),
|
resolve_downward_pass(tree, *pass, dirty, dirty_states, nodes_updated, ctx)
|
||||||
Self::Node(pass) => resolve_node_pass(tree, pass.as_ref(), dirty, dirty_states),
|
}
|
||||||
|
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>>(
|
pub fn resolve_passes<T, Tr: TreeView<T>>(
|
||||||
tree: &mut Tr,
|
tree: &mut Tr,
|
||||||
dirty_nodes: DirtyNodeStates,
|
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 dirty_states = Arc::new(dirty_nodes);
|
||||||
let mut resolved_passes: FxHashSet<PassId> = FxHashSet::default();
|
let mut resolved_passes: FxHashSet<PassId> = FxHashSet::default();
|
||||||
let mut resolving = Vec::new();
|
let mut resolving = Vec::new();
|
||||||
|
let nodes_updated = Arc::new(FxDashSet::default());
|
||||||
|
let ctx = Arc::new(ctx);
|
||||||
while !passes.is_empty() {
|
while !passes.is_empty() {
|
||||||
let mut currently_borrowed = MemberMask::default();
|
let mut currently_borrowed = MemberMask::default();
|
||||||
std::thread::scope(|s| {
|
std::thread::scope(|s| {
|
||||||
@@ -322,13 +343,16 @@ pub fn resolve_passes<T, Tr: TreeView<T>>(
|
|||||||
let tree_mut = tree as *mut _;
|
let tree_mut = tree as *mut _;
|
||||||
let raw_ptr = RawPointer(tree_mut);
|
let raw_ptr = RawPointer(tree_mut);
|
||||||
let dirty_states = dirty_states.clone();
|
let dirty_states = dirty_states.clone();
|
||||||
|
let nodes_updated = nodes_updated.clone();
|
||||||
|
let ctx = ctx.clone();
|
||||||
s.spawn(move || unsafe {
|
s.spawn(move || unsafe {
|
||||||
// let tree_mut: &mut Tr = &mut *raw_ptr.0;
|
// let tree_mut: &mut Tr = &mut *raw_ptr.0;
|
||||||
let raw = raw_ptr;
|
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 tree_mut: &mut Tr = &mut *raw.0;
|
||||||
let mut dirty = DirtyNodes::default();
|
let mut dirty = DirtyNodes::default();
|
||||||
dirty_states.all_dirty(pass_id, &mut dirty, tree_mut);
|
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 {
|
} else {
|
||||||
i += 1;
|
i += 1;
|
||||||
@@ -339,14 +363,13 @@ pub fn resolve_passes<T, Tr: TreeView<T>>(
|
|||||||
resolved_passes.extend(resolving.iter().copied());
|
resolved_passes.extend(resolving.iter().copied());
|
||||||
resolving.clear()
|
resolving.clear()
|
||||||
}
|
}
|
||||||
|
std::sync::Arc::try_unwrap(nodes_updated).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn node_pass() {
|
fn node_pass() {
|
||||||
use crate::tree::{Tree, TreeLike};
|
use crate::tree::{Tree, TreeLike};
|
||||||
let mut tree = Tree::new(0);
|
let mut tree = Tree::new(0);
|
||||||
let parent = tree.root();
|
|
||||||
println!("{:#?}", tree);
|
|
||||||
|
|
||||||
struct AddPass;
|
struct AddPass;
|
||||||
impl Pass for AddPass {
|
impl Pass for AddPass {
|
||||||
@@ -368,16 +391,17 @@ fn node_pass() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NodePass<i32> for AddPass {
|
impl NodePass<i32> for AddPass {
|
||||||
fn pass(&self, node: &mut i32) -> bool {
|
fn pass(&self, node: &mut i32, _: &SendAnyMap) -> bool {
|
||||||
*node += 1;
|
*node += 1;
|
||||||
true
|
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();
|
let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default();
|
||||||
dirty_nodes.insert(PassId(0), tree.root());
|
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(tree.root()).unwrap(), &1);
|
||||||
}
|
}
|
||||||
@@ -407,8 +431,7 @@ fn dependant_node_pass() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NodePass<i32> for AddPass {
|
impl NodePass<i32> for AddPass {
|
||||||
fn pass(&self, node: &mut i32) -> bool {
|
fn pass(&self, node: &mut i32, _: &SendAnyMap) -> bool {
|
||||||
println!("AddPass: {}", node);
|
|
||||||
*node += 1;
|
*node += 1;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@@ -434,20 +457,18 @@ fn dependant_node_pass() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl NodePass<i32> for SubtractPass {
|
impl NodePass<i32> for SubtractPass {
|
||||||
fn pass(&self, node: &mut i32) -> bool {
|
fn pass(&self, node: &mut i32, _: &SendAnyMap) -> bool {
|
||||||
println!("SubtractPass: {}", node);
|
|
||||||
*node -= 1;
|
*node -= 1;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let passes = vec![
|
let add_pass = AnyPass::Node(&AddPass);
|
||||||
AnyPass::Node(Box::new(AddPass)),
|
let subtract_pass = AnyPass::Node(&SubtractPass);
|
||||||
AnyPass::Node(Box::new(SubtractPass)),
|
let passes = vec![&add_pass, &subtract_pass];
|
||||||
];
|
|
||||||
let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default();
|
let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default();
|
||||||
dirty_nodes.insert(PassId(1), 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(), 0);
|
assert_eq!(*tree.get(tree.root()).unwrap(), 0);
|
||||||
}
|
}
|
||||||
@@ -477,7 +498,7 @@ fn independant_node_pass() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NodePass<(i32, i32)> for AddPass1 {
|
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;
|
node.0 += 1;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@@ -503,20 +524,19 @@ fn independant_node_pass() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NodePass<(i32, i32)> for AddPass2 {
|
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;
|
node.1 += 1;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let passes = vec![
|
let add_pass1 = AnyPass::Node(&AddPass1);
|
||||||
AnyPass::Node(Box::new(AddPass1)),
|
let add_pass2 = AnyPass::Node(&AddPass2);
|
||||||
AnyPass::Node(Box::new(AddPass2)),
|
let passes = vec![&add_pass1, &add_pass2];
|
||||||
];
|
|
||||||
let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default();
|
let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default();
|
||||||
dirty_nodes.insert(PassId(0), tree.root());
|
dirty_nodes.insert(PassId(0), tree.root());
|
||||||
dirty_nodes.insert(PassId(1), 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));
|
assert_eq!(tree.get(tree.root()).unwrap(), &(1, 1));
|
||||||
}
|
}
|
||||||
@@ -555,7 +575,7 @@ fn down_pass() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl DownwardPass<i32> for AddPass {
|
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 {
|
if let Some(parent) = parent {
|
||||||
*node += *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();
|
let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default();
|
||||||
dirty_nodes.insert(PassId(0), tree.root());
|
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(tree.root()).unwrap(), &1);
|
||||||
assert_eq!(tree.get(child1).unwrap(), &2);
|
assert_eq!(tree.get(child1).unwrap(), &2);
|
||||||
@@ -616,12 +637,10 @@ fn dependant_down_pass() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl DownwardPass<i32> for AddPass {
|
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 {
|
if let Some(parent) = parent {
|
||||||
println!("AddPass: {} -> {}", node, *node + *parent);
|
|
||||||
*node += *parent;
|
*node += *parent;
|
||||||
} else {
|
} else {
|
||||||
println!("AddPass: {}", node);
|
|
||||||
}
|
}
|
||||||
PassReturn {
|
PassReturn {
|
||||||
progress: true,
|
progress: true,
|
||||||
@@ -649,12 +668,10 @@ fn dependant_down_pass() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl DownwardPass<i32> for SubtractPass {
|
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 {
|
if let Some(parent) = parent {
|
||||||
println!("SubtractPass: {} -> {}", node, *node - *parent);
|
|
||||||
*node -= *parent;
|
*node -= *parent;
|
||||||
} else {
|
} else {
|
||||||
println!("SubtractPass: {}", node);
|
|
||||||
}
|
}
|
||||||
PassReturn {
|
PassReturn {
|
||||||
progress: true,
|
progress: true,
|
||||||
@@ -663,13 +680,12 @@ fn dependant_down_pass() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let passes = vec![
|
let add_pass = AnyPass::Downward(&AddPass);
|
||||||
AnyPass::Downward(Box::new(AddPass)),
|
let subtract_pass = AnyPass::Downward(&SubtractPass);
|
||||||
AnyPass::Downward(Box::new(SubtractPass)),
|
let passes = vec![&add_pass, &subtract_pass];
|
||||||
];
|
|
||||||
let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default();
|
let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default();
|
||||||
dirty_nodes.insert(PassId(1), 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());
|
||||||
|
|
||||||
// Tree before:
|
// Tree before:
|
||||||
// 1=\
|
// 1=\
|
||||||
@@ -745,6 +761,7 @@ fn up_pass() {
|
|||||||
&self,
|
&self,
|
||||||
node: &mut i32,
|
node: &mut i32,
|
||||||
children: &mut dyn Iterator<Item = &'a mut i32>,
|
children: &mut dyn Iterator<Item = &'a mut i32>,
|
||||||
|
_: &SendAnyMap,
|
||||||
) -> PassReturn {
|
) -> PassReturn {
|
||||||
*node += children.map(|i| *i).sum::<i32>();
|
*node += children.map(|i| *i).sum::<i32>();
|
||||||
PassReturn {
|
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();
|
let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default();
|
||||||
dirty_nodes.insert(PassId(0), grandchild1);
|
dirty_nodes.insert(PassId(0), grandchild1);
|
||||||
dirty_nodes.insert(PassId(0), grandchild2);
|
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(tree.root()).unwrap(), &2);
|
||||||
assert_eq!(tree.get(child1).unwrap(), &1);
|
assert_eq!(tree.get(child1).unwrap(), &1);
|
||||||
@@ -809,6 +827,7 @@ fn dependant_up_pass() {
|
|||||||
&self,
|
&self,
|
||||||
node: &mut i32,
|
node: &mut i32,
|
||||||
children: &mut dyn Iterator<Item = &'a mut i32>,
|
children: &mut dyn Iterator<Item = &'a mut i32>,
|
||||||
|
_: &SendAnyMap,
|
||||||
) -> PassReturn {
|
) -> PassReturn {
|
||||||
*node += children.map(|i| *i).sum::<i32>();
|
*node += children.map(|i| *i).sum::<i32>();
|
||||||
PassReturn {
|
PassReturn {
|
||||||
@@ -841,6 +860,7 @@ fn dependant_up_pass() {
|
|||||||
&self,
|
&self,
|
||||||
node: &mut i32,
|
node: &mut i32,
|
||||||
children: &mut dyn Iterator<Item = &'a mut i32>,
|
children: &mut dyn Iterator<Item = &'a mut i32>,
|
||||||
|
_: &SendAnyMap,
|
||||||
) -> PassReturn {
|
) -> PassReturn {
|
||||||
*node -= children.map(|i| *i).sum::<i32>();
|
*node -= children.map(|i| *i).sum::<i32>();
|
||||||
PassReturn {
|
PassReturn {
|
||||||
@@ -850,14 +870,13 @@ fn dependant_up_pass() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let passes = vec![
|
let add_pass = AnyPass::Upward(&AddPass);
|
||||||
AnyPass::Upward(Box::new(AddPass)),
|
let subtract_pass = AnyPass::Upward(&SubtractPass);
|
||||||
AnyPass::Upward(Box::new(SubtractPass)),
|
let passes = vec![&add_pass, &subtract_pass];
|
||||||
];
|
|
||||||
let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default();
|
let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default();
|
||||||
dirty_nodes.insert(PassId(1), grandchild1);
|
dirty_nodes.insert(PassId(1), grandchild1);
|
||||||
dirty_nodes.insert(PassId(1), grandchild2);
|
dirty_nodes.insert(PassId(1), grandchild2);
|
||||||
resolve_passes(&mut tree, dirty_nodes, passes);
|
resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new());
|
||||||
|
|
||||||
// Tree before:
|
// Tree before:
|
||||||
// 0=\
|
// 0=\
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
use anymap::AnyMap;
|
|
||||||
use dioxus_core::{ElementId, Mutations};
|
use dioxus_core::{ElementId, Mutations};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use std::ops::{Index, IndexMut};
|
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::node_ref::{AttributeMask, NodeMask};
|
||||||
|
use crate::passes::DirtyNodeStates;
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
use crate::tree::{NodeId, Tree, TreeLike, TreeView};
|
use crate::tree::{NodeId, Tree, TreeLike, TreeView};
|
||||||
use crate::RealNodeId;
|
use crate::{FxDashSet, RealNodeId, SendAnyMap};
|
||||||
|
|
||||||
fn mark_dirty(
|
fn mark_dirty(
|
||||||
node_id: NodeId,
|
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.
|
/// 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(
|
pub fn apply_mutations(&mut self, mutations_vec: Vec<Mutations>) -> DirtyNodeStates {
|
||||||
&mut self,
|
|
||||||
mutations_vec: Vec<Mutations>,
|
|
||||||
) -> FxHashMap<RealNodeId, NodeMask> {
|
|
||||||
let mut nodes_updated: FxHashMap<RealNodeId, NodeMask> = FxHashMap::default();
|
let mut nodes_updated: FxHashMap<RealNodeId, NodeMask> = FxHashMap::default();
|
||||||
for mutations in mutations_vec {
|
for mutations in mutations_vec {
|
||||||
for e in mutations.edits {
|
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
|
let dirty_nodes = DirtyNodeStates::default();
|
||||||
nodes_updated.retain(|k, _| self.tree.get(*k).is_some());
|
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.
|
/// 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(
|
pub fn update_state(
|
||||||
&mut self,
|
&mut self,
|
||||||
nodes_updated: FxHashMap<RealNodeId, NodeMask>,
|
nodes_updated: DirtyNodeStates,
|
||||||
ctx: AnyMap,
|
ctx: SendAnyMap,
|
||||||
) -> FxHashSet<RealNodeId> {
|
) -> FxDashSet<RealNodeId> {
|
||||||
let (mut state_tree, node_tree) = self.split();
|
S::update(nodes_updated, &mut self.tree, ctx)
|
||||||
S::update(&nodes_updated, &mut state_tree, &node_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.
|
/// 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()
|
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 {
|
fn clone_node(&mut self, node_id: NodeId) -> RealNodeId {
|
||||||
let node = self.tree.get(node_id).unwrap();
|
let node = self.tree.get(node_id).unwrap();
|
||||||
let new_node = node.clone();
|
let new_node = node.clone();
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
use crate::node::NodeData;
|
use crate::node::Node;
|
||||||
use crate::node_ref::{NodeMask, NodeView};
|
use crate::node_ref::{NodeMask, NodeView};
|
||||||
|
use crate::passes::{resolve_passes, AnyPass, DirtyNodeStates};
|
||||||
use crate::tree::TreeView;
|
use crate::tree::TreeView;
|
||||||
use crate::RealNodeId;
|
use crate::{FxDashSet, RealNodeId, SendAnyMap};
|
||||||
use anymap::AnyMap;
|
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
|
||||||
|
|
||||||
/// Join two sorted iterators
|
/// Join two sorted iterators
|
||||||
pub(crate) fn union_ordered_iter<'a>(
|
pub(crate) fn union_ordered_iter<'a>(
|
||||||
@@ -204,20 +203,29 @@ pub trait NodeDepState {
|
|||||||
fn reduce<'a>(
|
fn reduce<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
node: NodeView,
|
node: NodeView,
|
||||||
siblings: <Self::DepState as ElementBorrowable>::ElementBorrowed<'a>,
|
node_state: <Self::DepState as ElementBorrowable>::ElementBorrowed<'a>,
|
||||||
ctx: &Self::Ctx,
|
ctx: &Self::Ctx,
|
||||||
) -> bool;
|
) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Do not implement this trait. It is only meant to be derived and used through [crate::real_dom::RealDom].
|
/// 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)]
|
#[doc(hidden)]
|
||||||
fn update<'a, T: TreeView<Self>, T2: TreeView<NodeData>>(
|
const PASSES: &'static [AnyPass<Node<Self>>];
|
||||||
dirty: &FxHashMap<RealNodeId, NodeMask>,
|
#[doc(hidden)]
|
||||||
state_tree: &'a mut T,
|
const MASKS: &'static [NodeMask];
|
||||||
rdom: &'a T2,
|
|
||||||
ctx: &AnyMap,
|
#[doc(hidden)]
|
||||||
) -> FxHashSet<RealNodeId>;
|
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 () {
|
impl ChildDepState for () {
|
||||||
|
|||||||
@@ -73,6 +73,10 @@ pub trait TreeView<T>: Sized {
|
|||||||
|
|
||||||
fn root(&self) -> NodeId;
|
fn root(&self) -> NodeId;
|
||||||
|
|
||||||
|
fn contains(&self, id: NodeId) -> bool {
|
||||||
|
self.get(id).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
fn get(&self, id: NodeId) -> Option<&T>;
|
fn get(&self, id: NodeId) -> Option<&T>;
|
||||||
|
|
||||||
fn get_unchecked(&self, id: NodeId) -> &T {
|
fn get_unchecked(&self, id: NodeId) -> &T {
|
||||||
|
|||||||
Reference in new issue
Block a user