create new state system
This commit is contained in:
1 parent
3cfaaea7ea
commit
e76cd63ee3
6 files changed
+413
-301
No files matched your search
@@ -1,16 +1,14 @@
|
|||||||
use std::hash::BuildHasherDefault;
|
use std::hash::BuildHasherDefault;
|
||||||
|
|
||||||
pub use node_ref::NodeMask;
|
pub use node_ref::NodeMask;
|
||||||
pub use passes::{
|
pub use passes::Pass;
|
||||||
AnyPass, DownwardPass, MemberMask, NodePass, Pass, PassId, PassReturn, UpwardPass,
|
|
||||||
};
|
|
||||||
use rustc_hash::FxHasher;
|
use rustc_hash::FxHasher;
|
||||||
pub use tree::NodeId;
|
pub use tree::NodeId;
|
||||||
|
|
||||||
pub mod layout_attributes;
|
pub mod layout_attributes;
|
||||||
pub mod node;
|
pub mod node;
|
||||||
pub mod node_ref;
|
pub mod node_ref;
|
||||||
pub mod passes;
|
mod passes;
|
||||||
pub mod real_dom;
|
pub mod real_dom;
|
||||||
pub mod state;
|
pub mod state;
|
||||||
pub mod tree;
|
pub mod tree;
|
||||||
|
|||||||
+336
-258
@@ -1,11 +1,308 @@
|
|||||||
use crate::tree::{NodeId, TreeView};
|
use anymap::any;
|
||||||
use crate::{FxDashMap, FxDashSet, SendAnyMap};
|
use anymap::AnyMap;
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::FxHashMap;
|
||||||
|
use rustc_hash::FxHashSet;
|
||||||
|
use std::any::{Any, TypeId};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
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::node::Node;
|
||||||
|
use crate::node_ref::NodeView;
|
||||||
|
use crate::state::State;
|
||||||
|
use crate::tree::{Tree, TreeView};
|
||||||
|
use crate::{FxDashMap, FxDashSet, SendAnyMap};
|
||||||
|
use crate::{NodeId, NodeMask};
|
||||||
|
|
||||||
|
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;
|
||||||
|
/// This is a tuple of (T: Any, ..)
|
||||||
|
type Ctx: Dependancy;
|
||||||
|
const MASK: NodeMask;
|
||||||
|
|
||||||
|
fn pass<'a>(
|
||||||
|
&mut self,
|
||||||
|
node_view: NodeView,
|
||||||
|
node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
|
||||||
|
parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
|
||||||
|
children: Option<
|
||||||
|
impl Iterator<Item = <Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>,
|
||||||
|
>,
|
||||||
|
context: <Self::Ctx as Dependancy>::ElementBorrowed<'a>,
|
||||||
|
) -> bool;
|
||||||
|
|
||||||
|
fn is_valid(&self) -> bool {
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// this type should not be a node dependency
|
||||||
|
for type_id in Self::node_type_ids() {
|
||||||
|
if type_id == TypeId::of::<Self>() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// no states have the same type id
|
||||||
|
if Self::all_dependanices()
|
||||||
|
.into_iter()
|
||||||
|
.collect::<FxDashSet<_>>()
|
||||||
|
.len()
|
||||||
|
!= Self::all_dependanices().len()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_type_erased<T: AnyMapLike + State>() -> TypeErasedPass<T>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
TypeErasedPass {
|
||||||
|
this_type_id: TypeId::of::<Self>(),
|
||||||
|
parent_type_ids: Self::parent_type_ids().into_iter().collect(),
|
||||||
|
child_type_ids: Self::child_type_ids().into_iter().collect(),
|
||||||
|
node_type_ids: Self::node_type_ids().into_iter().collect(),
|
||||||
|
combined_dependancy_type_ids: Self::all_dependanices().into_iter().collect(),
|
||||||
|
dependants: FxHashSet::default(),
|
||||||
|
mask: Self::MASK,
|
||||||
|
pass_direction: Self::pass_direction(),
|
||||||
|
pass: Box::new(
|
||||||
|
|node_id: NodeId, any_map: &mut Tree<Node<T>>, context: &SendAnyMap| {
|
||||||
|
let (current_node, parent, children) = any_map
|
||||||
|
.node_parent_children_mut(node_id)
|
||||||
|
.expect("tried to run pass on node that does not exist");
|
||||||
|
let current_node_raw = current_node as *mut Node<T>;
|
||||||
|
let node = Self::NodeDependencies::borrow_elements_from(¤t_node.state)
|
||||||
|
.expect("tried to get a pass that does not exist");
|
||||||
|
let parent = parent.map(|parent| {
|
||||||
|
Self::ParentDependencies::borrow_elements_from(&parent.state)
|
||||||
|
.expect("tried to get a pass that does not exist")
|
||||||
|
});
|
||||||
|
let children = children.map(|children| {
|
||||||
|
children.map(|child| {
|
||||||
|
Self::ChildDependencies::borrow_elements_from(&child.state)
|
||||||
|
.expect("tried to get a pass that does not exist")
|
||||||
|
})
|
||||||
|
});
|
||||||
|
// safety: we have varified the pass is valid in the is_valid function
|
||||||
|
let myself: &mut Self = unsafe {
|
||||||
|
(*current_node_raw)
|
||||||
|
.state
|
||||||
|
.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::MASK),
|
||||||
|
node,
|
||||||
|
parent,
|
||||||
|
children,
|
||||||
|
context,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
as Box<dyn Fn(NodeId, &mut Tree<Node<T>>, &SendAnyMap) -> bool + Send + Sync>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parent_type_ids() -> Vec<TypeId> {
|
||||||
|
Self::ParentDependencies::type_ids()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn child_type_ids() -> Vec<TypeId> {
|
||||||
|
Self::ChildDependencies::type_ids()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn node_type_ids() -> Vec<TypeId> {
|
||||||
|
Self::NodeDependencies::type_ids()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn all_dependanices() -> Vec<TypeId> {
|
||||||
|
let mut dependencies = Self::parent_type_ids();
|
||||||
|
dependencies.extend(Self::child_type_ids());
|
||||||
|
dependencies.extend(Self::node_type_ids());
|
||||||
|
dependencies
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pass_direction() -> PassDirection {
|
||||||
|
if Self::child_type_ids()
|
||||||
|
.into_iter()
|
||||||
|
.any(|type_id| type_id == TypeId::of::<Self>())
|
||||||
|
{
|
||||||
|
PassDirection::ChildToParent
|
||||||
|
} else if Self::parent_type_ids()
|
||||||
|
.into_iter()
|
||||||
|
.any(|type_id| type_id == TypeId::of::<Self>())
|
||||||
|
{
|
||||||
|
PassDirection::ParentToChild
|
||||||
|
} else {
|
||||||
|
PassDirection::AnyOrder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TypeErasedPass<T: AnyMapLike + State> {
|
||||||
|
pub(crate) this_type_id: TypeId,
|
||||||
|
parent_type_ids: FxHashSet<TypeId>,
|
||||||
|
child_type_ids: FxHashSet<TypeId>,
|
||||||
|
node_type_ids: FxHashSet<TypeId>,
|
||||||
|
combined_dependancy_type_ids: FxHashSet<TypeId>,
|
||||||
|
pub(crate) dependants: FxHashSet<TypeId>,
|
||||||
|
pub(crate) mask: NodeMask,
|
||||||
|
pass: PassCallback<T>,
|
||||||
|
pass_direction: PassDirection,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: AnyMapLike + State> TypeErasedPass<T> {
|
||||||
|
fn resolve(
|
||||||
|
&self,
|
||||||
|
tree: &mut Tree<Node<T>>,
|
||||||
|
mut dirty: DirtyNodes,
|
||||||
|
dirty_states: &DirtyNodeStates,
|
||||||
|
nodes_updated: &FxDashSet<NodeId>,
|
||||||
|
ctx: &SendAnyMap,
|
||||||
|
) {
|
||||||
|
match self.pass_direction {
|
||||||
|
PassDirection::ParentToChild => {
|
||||||
|
while let Some(id) = dirty.pop_front() {
|
||||||
|
if (self.pass)(id, tree, ctx) {
|
||||||
|
nodes_updated.insert(id);
|
||||||
|
for id in tree.children_ids(id).unwrap() {
|
||||||
|
for dependant in &self.dependants {
|
||||||
|
dirty_states.insert(*dependant, *id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let height = tree.height(*id).unwrap();
|
||||||
|
dirty.insert(height, *id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PassDirection::ChildToParent => {
|
||||||
|
while let Some(id) = dirty.pop_back() {
|
||||||
|
if (self.pass)(id, tree, ctx) {
|
||||||
|
nodes_updated.insert(id);
|
||||||
|
if let Some(id) = tree.parent_id(id) {
|
||||||
|
for dependant in &self.dependants {
|
||||||
|
dirty_states.insert(*dependant, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let height = tree.height(id).unwrap();
|
||||||
|
dirty.insert(height, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PassDirection::AnyOrder => {
|
||||||
|
while let Some(id) = dirty.pop_back() {
|
||||||
|
if (self.pass)(id, tree, ctx) {
|
||||||
|
nodes_updated.insert(id);
|
||||||
|
for dependant in &self.dependants {
|
||||||
|
dirty_states.insert(*dependant, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum PassDirection {
|
||||||
|
ParentToChild,
|
||||||
|
ChildToParent,
|
||||||
|
AnyOrder,
|
||||||
|
}
|
||||||
|
|
||||||
|
type PassCallback<T> = Box<dyn Fn(NodeId, &mut Tree<Node<T>>, &SendAnyMap) -> bool + Send + Sync>;
|
||||||
|
|
||||||
|
pub trait AnyMapLike {
|
||||||
|
fn get<T: Any>(&self) -> Option<&T>;
|
||||||
|
fn get_mut<T: Any>(&mut self) -> Option<&mut T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnyMapLike for AnyMap {
|
||||||
|
fn get<T: Any>(&self) -> Option<&T> {
|
||||||
|
self.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mut<T: Any>(&mut self) -> Option<&mut T> {
|
||||||
|
self.get_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnyMapLike for SendAnyMap {
|
||||||
|
fn get<T: Any>(&self) -> Option<&T> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mut<T: Any>(&mut self) -> Option<&mut T> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Dependancy {
|
||||||
|
type ElementBorrowed<'a>
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
|
|
||||||
|
fn borrow_elements(&self) -> Self::ElementBorrowed<'_>;
|
||||||
|
fn borrow_elements_from<T: AnyMapLike>(map: &T) -> Option<Self::ElementBorrowed<'_>>;
|
||||||
|
fn type_ids() -> Vec<TypeId>;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_dependancy {
|
||||||
|
($($t:ident),*) => {
|
||||||
|
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<T: AnyMapLike>(map: &T) -> Option<Self::ElementBorrowed<'_>> {
|
||||||
|
Some(($(map.get::<$t>()?,)*))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_ids() -> Vec<TypeId> {
|
||||||
|
vec![$(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);
|
||||||
|
|
||||||
#[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,11 +354,11 @@ fn dirty_nodes() {
|
|||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct DirtyNodeStates {
|
pub struct DirtyNodeStates {
|
||||||
dirty: FxDashMap<NodeId, Vec<AtomicU64>>,
|
dirty: FxDashMap<NodeId, FxHashSet<TypeId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DirtyNodeStates {
|
impl DirtyNodeStates {
|
||||||
pub fn new(starting_nodes: FxHashMap<NodeId, FxHashSet<PassId>>) -> Self {
|
pub fn new(starting_nodes: FxHashMap<NodeId, FxHashSet<TypeId>>) -> Self {
|
||||||
let this = Self::default();
|
let this = Self::default();
|
||||||
for (node, nodes) in starting_nodes {
|
for (node, nodes) in starting_nodes {
|
||||||
for pass_id in nodes {
|
for pass_id in nodes {
|
||||||
@@ -71,290 +368,71 @@ impl DirtyNodeStates {
|
|||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&self, pass_id: PassId, node_id: NodeId) {
|
pub fn insert(&self, pass_id: TypeId, node_id: NodeId) {
|
||||||
let pass_id = pass_id.0;
|
if let Some(mut dirty) = self.dirty.get_mut(&node_id) {
|
||||||
let index = pass_id / 64;
|
dirty.insert(pass_id);
|
||||||
let bit = pass_id % 64;
|
|
||||||
let encoded = 1 << bit;
|
|
||||||
if let Some(dirty) = self.dirty.get(&node_id) {
|
|
||||||
if let Some(atomic) = dirty.get(index as usize) {
|
|
||||||
atomic.fetch_or(encoded, Ordering::Relaxed);
|
|
||||||
} else {
|
|
||||||
drop(dirty);
|
|
||||||
let mut write = self.dirty.get_mut(&node_id).unwrap();
|
|
||||||
write.resize_with(index as usize + 1, || AtomicU64::new(0));
|
|
||||||
write[index as usize].fetch_or(encoded, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let mut v = Vec::with_capacity(index as usize + 1);
|
let mut v = FxHashSet::default();
|
||||||
v.resize_with(index as usize + 1, || AtomicU64::new(0));
|
v.insert(pass_id);
|
||||||
v[index as usize].fetch_or(encoded, Ordering::Relaxed);
|
|
||||||
self.dirty.insert(node_id, v);
|
self.dirty.insert(node_id, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_dirty<T>(&self, pass_id: PassId, dirty_nodes: &mut DirtyNodes, tree: &impl TreeView<T>) {
|
fn all_dirty<T>(&self, pass_id: TypeId, dirty_nodes: &mut DirtyNodes, tree: &impl TreeView<T>) {
|
||||||
let pass_id = pass_id.0;
|
|
||||||
let index = pass_id / 64;
|
|
||||||
let bit = pass_id % 64;
|
|
||||||
let encoded = 1 << bit;
|
|
||||||
for entry in self.dirty.iter() {
|
for entry in self.dirty.iter() {
|
||||||
let node_id = entry.key();
|
let node_id = entry.key();
|
||||||
let dirty = entry.value();
|
let dirty = entry.value();
|
||||||
if let Some(atomic) = dirty.get(index as usize) {
|
if dirty.contains(&pass_id) {
|
||||||
if atomic.load(Ordering::Relaxed) & encoded != 0 {
|
dirty_nodes.insert(tree.height(*node_id).unwrap(), *node_id);
|
||||||
dirty_nodes.insert(tree.height(*node_id).unwrap(), *node_id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, PartialOrd, Ord)]
|
pub fn resolve_passes<T: AnyMapLike + State + Send>(
|
||||||
pub struct PassId(pub u64);
|
tree: &mut Tree<Node<T>>,
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Default)]
|
|
||||||
pub struct MemberMask(pub u64);
|
|
||||||
|
|
||||||
impl MemberMask {
|
|
||||||
pub fn overlaps(&self, other: Self) -> bool {
|
|
||||||
(*self & other).0 != 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitAndAssign for MemberMask {
|
|
||||||
fn bitand_assign(&mut self, rhs: Self) {
|
|
||||||
self.0 &= rhs.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitAnd for MemberMask {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn bitand(self, rhs: Self) -> Self::Output {
|
|
||||||
MemberMask(self.0 & rhs.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitOrAssign for MemberMask {
|
|
||||||
fn bitor_assign(&mut self, rhs: Self) {
|
|
||||||
self.0 |= rhs.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitOr for MemberMask {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn bitor(self, rhs: Self) -> Self::Output {
|
|
||||||
Self(self.0 | rhs.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct PassReturn {
|
|
||||||
pub progress: bool,
|
|
||||||
pub mark_dirty: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Pass {
|
|
||||||
fn pass_id(&self) -> PassId;
|
|
||||||
fn dependancies(&self) -> &'static [PassId];
|
|
||||||
fn dependants(&self) -> &'static [PassId];
|
|
||||||
fn mask(&self) -> MemberMask;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait UpwardPass<T>: Pass {
|
|
||||||
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>(
|
|
||||||
tree: &mut impl TreeView<T>,
|
|
||||||
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, 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() {
|
|
||||||
dirty_states.insert(*dependant, id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if result.progress {
|
|
||||||
let height = tree.height(id).unwrap();
|
|
||||||
dirty.insert(height, id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait DownwardPass<T>: Pass {
|
|
||||||
fn pass(&self, node: &mut T, parent: Option<&mut T>, ctx: &SendAnyMap) -> PassReturn;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_downward_pass<T, P: DownwardPass<T> + ?Sized>(
|
|
||||||
tree: &mut impl TreeView<T>,
|
|
||||||
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, ctx);
|
|
||||||
if result.mark_dirty {
|
|
||||||
nodes_updated.insert(id);
|
|
||||||
}
|
|
||||||
if result.mark_dirty || result.progress {
|
|
||||||
for id in tree.children_ids(id).unwrap() {
|
|
||||||
if result.mark_dirty {
|
|
||||||
for dependant in pass.dependants() {
|
|
||||||
dirty_states.insert(*dependant, *id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if result.progress {
|
|
||||||
let height = tree.height(*id).unwrap();
|
|
||||||
dirty.insert(height, *id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait NodePass<T>: Pass {
|
|
||||||
fn pass(&self, node: &mut T, ctx: &SendAnyMap) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_node_pass<T, P: NodePass<T> + ?Sized>(
|
|
||||||
tree: &mut impl TreeView<T>,
|
|
||||||
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, ctx) {
|
|
||||||
nodes_updated.insert(id);
|
|
||||||
for dependant in pass.dependants() {
|
|
||||||
dirty_states.insert(*dependant, id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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> {
|
|
||||||
pub fn pass_id(&self) -> PassId {
|
|
||||||
match self {
|
|
||||||
Self::Upward(pass) => pass.pass_id(),
|
|
||||||
Self::Downward(pass) => pass.pass_id(),
|
|
||||||
Self::Node(pass) => pass.pass_id(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dependancies(&self) -> &'static [PassId] {
|
|
||||||
match self {
|
|
||||||
Self::Upward(pass) => pass.dependancies(),
|
|
||||||
Self::Downward(pass) => pass.dependancies(),
|
|
||||||
Self::Node(pass) => pass.dependancies(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mask(&self) -> MemberMask {
|
|
||||||
match self {
|
|
||||||
Self::Upward(pass) => pass.mask(),
|
|
||||||
Self::Downward(pass) => pass.mask(),
|
|
||||||
Self::Node(pass) => pass.mask(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve(
|
|
||||||
&self,
|
|
||||||
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, 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct RawPointer<T>(*mut T);
|
|
||||||
unsafe impl<T> Send for RawPointer<T> {}
|
|
||||||
unsafe impl<T> Sync for RawPointer<T> {}
|
|
||||||
|
|
||||||
pub fn resolve_passes<T, Tr: TreeView<T>>(
|
|
||||||
tree: &mut Tr,
|
|
||||||
dirty_nodes: DirtyNodeStates,
|
dirty_nodes: DirtyNodeStates,
|
||||||
mut passes: Vec<&AnyPass<T>>,
|
mut passes: &[TypeErasedPass<T>],
|
||||||
ctx: SendAnyMap,
|
ctx: SendAnyMap,
|
||||||
) -> FxDashSet<NodeId> {
|
) -> 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<TypeId> = FxHashSet::default();
|
||||||
let mut resolving = Vec::new();
|
let mut resolving = Vec::new();
|
||||||
let nodes_updated = Arc::new(FxDashSet::default());
|
let nodes_updated = Arc::new(FxDashSet::default());
|
||||||
let ctx = Arc::new(ctx);
|
let ctx = Arc::new(ctx);
|
||||||
while !passes.is_empty() {
|
let mut pass_indexes_remaining: Vec<_> = (0..passes.len()).collect::<Vec<_>>();
|
||||||
let mut currently_borrowed = MemberMask::default();
|
while !pass_indexes_remaining.is_empty() {
|
||||||
|
let mut currently_in_use = FxHashSet::<TypeId>::default();
|
||||||
std::thread::scope(|s| {
|
std::thread::scope(|s| {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < passes.len() {
|
while i < pass_indexes_remaining.len() {
|
||||||
let pass = &passes[i];
|
let passes_idx = pass_indexes_remaining[i];
|
||||||
let pass_id = pass.pass_id();
|
let pass = &passes[passes_idx];
|
||||||
let pass_mask = pass.mask();
|
let pass_id = pass.this_type_id;
|
||||||
|
// check if the pass is ready to be run
|
||||||
if pass
|
if pass
|
||||||
.dependancies()
|
.combined_dependancy_type_ids
|
||||||
.iter()
|
.iter()
|
||||||
.all(|d| resolved_passes.contains(d) || *d == pass_id)
|
.all(|d| resolved_passes.contains(d) || *d == pass_id)
|
||||||
&& !pass_mask.overlaps(currently_borrowed)
|
|
||||||
{
|
{
|
||||||
let pass = passes.remove(i);
|
pass_indexes_remaining.remove(i);
|
||||||
resolving.push(pass_id);
|
resolving.push(pass_id);
|
||||||
currently_borrowed |= pass_mask;
|
currently_in_use.insert(pass.this_type_id);
|
||||||
let tree_mut = tree as *mut _;
|
// 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 raw_ptr = RawPointer(tree_mut);
|
let tree_unbounded_mut = unsafe { &mut *(tree as *mut _) };
|
||||||
let dirty_states = dirty_states.clone();
|
let dirty_states = dirty_states.clone();
|
||||||
let nodes_updated = nodes_updated.clone();
|
let nodes_updated = nodes_updated.clone();
|
||||||
let ctx = ctx.clone();
|
let ctx = ctx.clone();
|
||||||
s.spawn(move || unsafe {
|
s.spawn(move || {
|
||||||
// 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();
|
let mut dirty = DirtyNodes::default();
|
||||||
dirty_states.all_dirty(pass_id, &mut dirty, tree_mut);
|
dirty_states.all_dirty(pass_id, &mut dirty, tree_unbounded_mut);
|
||||||
pass.resolve(tree_mut, dirty, &dirty_states, &nodes_updated, &ctx);
|
pass.resolve(
|
||||||
|
tree_unbounded_mut,
|
||||||
|
dirty,
|
||||||
|
&dirty_states,
|
||||||
|
&nodes_updated,
|
||||||
|
&ctx,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use std::ops::{Deref, DerefMut, Index, IndexMut};
|
|||||||
|
|
||||||
use crate::node::{Node, NodeType, OwnedAttributeDiscription, OwnedAttributeValue};
|
use crate::node::{Node, NodeType, OwnedAttributeDiscription, OwnedAttributeValue};
|
||||||
use crate::node_ref::{AttributeMask, NodeMask};
|
use crate::node_ref::{AttributeMask, NodeMask};
|
||||||
use crate::passes::DirtyNodeStates;
|
use crate::passes::{resolve_passes, DirtyNodeStates, TypeErasedPass};
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
use crate::tree::{NodeId, Tree, TreeLike, TreeView};
|
use crate::tree::{NodeId, Tree, TreeLike, TreeView};
|
||||||
use crate::{FxDashSet, RealNodeId, SendAnyMap};
|
use crate::{FxDashSet, RealNodeId, SendAnyMap};
|
||||||
@@ -25,8 +25,7 @@ fn mark_dirty(
|
|||||||
/// A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers.
|
/// A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers.
|
||||||
/// The render state passes from parent to children and or accumulates state from children to parents.
|
/// The render state passes from parent to children and or accumulates state from children to parents.
|
||||||
/// To get started implement [crate::state::ParentDepState], [crate::state::NodeDepState], or [crate::state::ChildDepState] and call [RealDom::apply_mutations] to update the dom and [RealDom::update_state] to update the state of the nodes.
|
/// To get started implement [crate::state::ParentDepState], [crate::state::NodeDepState], or [crate::state::ChildDepState] and call [RealDom::apply_mutations] to update the dom and [RealDom::update_state] to update the state of the nodes.
|
||||||
#[derive(Debug)]
|
pub struct RealDom<S: State + Send> {
|
||||||
pub struct RealDom<S: State> {
|
|
||||||
pub tree: Tree<Node<S>>,
|
pub tree: Tree<Node<S>>,
|
||||||
/// a map from element id to real node id
|
/// a map from element id to real node id
|
||||||
node_id_mapping: Vec<Option<RealNodeId>>,
|
node_id_mapping: Vec<Option<RealNodeId>>,
|
||||||
@@ -34,15 +33,29 @@ pub struct RealDom<S: State> {
|
|||||||
stack: Vec<RealNodeId>,
|
stack: Vec<RealNodeId>,
|
||||||
templates: FxHashMap<String, Vec<RealNodeId>>,
|
templates: FxHashMap<String, Vec<RealNodeId>>,
|
||||||
root_initialized: bool,
|
root_initialized: bool,
|
||||||
|
pub(crate) passes: Box<[TypeErasedPass<S>]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: State> Default for RealDom<S> {
|
impl<S: State + Send + Debug> Debug for RealDom<S> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("RealDom")
|
||||||
|
.field("tree", &self.tree)
|
||||||
|
.field("node_id_mapping", &self.node_id_mapping)
|
||||||
|
.field("nodes_listening", &self.nodes_listening)
|
||||||
|
.field("stack", &self.stack)
|
||||||
|
.field("templates", &self.templates)
|
||||||
|
.field("root_initialized", &self.root_initialized)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: State + Send> Default for RealDom<S> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: State> RealDom<S> {
|
impl<S: State + Send> RealDom<S> {
|
||||||
pub fn new() -> RealDom<S> {
|
pub fn new() -> RealDom<S> {
|
||||||
let mut root = Node::new(NodeType::Element {
|
let mut root = Node::new(NodeType::Element {
|
||||||
tag: "Root".to_string(),
|
tag: "Root".to_string(),
|
||||||
@@ -55,6 +68,8 @@ impl<S: State> RealDom<S> {
|
|||||||
let root_id = tree.root();
|
let root_id = tree.root();
|
||||||
tree.get_mut(root_id).unwrap().node_data.node_id = root_id;
|
tree.get_mut(root_id).unwrap().node_data.node_id = root_id;
|
||||||
|
|
||||||
|
let passes = S::create_passes();
|
||||||
|
|
||||||
RealDom {
|
RealDom {
|
||||||
tree,
|
tree,
|
||||||
node_id_mapping: vec![Some(root_id)],
|
node_id_mapping: vec![Some(root_id)],
|
||||||
@@ -62,6 +77,7 @@ impl<S: State> RealDom<S> {
|
|||||||
stack: vec![root_id],
|
stack: vec![root_id],
|
||||||
templates: FxHashMap::default(),
|
templates: FxHashMap::default(),
|
||||||
root_initialized: false,
|
root_initialized: false,
|
||||||
|
passes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,9 +362,9 @@ impl<S: State> RealDom<S> {
|
|||||||
for (&n, mask) in &nodes_updated {
|
for (&n, mask) in &nodes_updated {
|
||||||
// remove any nodes that were created and then removed in the same mutations from the dirty nodes list
|
// 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(n) {
|
||||||
for (m, p) in S::MASKS.iter().zip(S::PASSES.iter()) {
|
for pass in &*self.passes {
|
||||||
if mask.overlaps(m) {
|
if mask.overlaps(&pass.mask) {
|
||||||
dirty_nodes.insert(p.pass_id(), n);
|
dirty_nodes.insert(pass.this_type_id, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -363,7 +379,9 @@ impl<S: State> RealDom<S> {
|
|||||||
nodes_updated: DirtyNodeStates,
|
nodes_updated: DirtyNodeStates,
|
||||||
ctx: SendAnyMap,
|
ctx: SendAnyMap,
|
||||||
) -> FxDashSet<RealNodeId> {
|
) -> FxDashSet<RealNodeId> {
|
||||||
S::update(nodes_updated, &mut self.tree, ctx)
|
let tree = &mut self.tree;
|
||||||
|
let passes = &self.passes;
|
||||||
|
resolve_passes(tree, nodes_updated, passes, 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.
|
||||||
@@ -415,7 +433,7 @@ impl<S: State> RealDom<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: State> Deref for RealDom<S> {
|
impl<S: State + Send> Deref for RealDom<S> {
|
||||||
type Target = Tree<Node<S>>;
|
type Target = Tree<Node<S>>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
@@ -423,13 +441,13 @@ impl<S: State> Deref for RealDom<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: State> DerefMut for RealDom<S> {
|
impl<S: State + Send> DerefMut for RealDom<S> {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
&mut self.tree
|
&mut self.tree
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: State> Index<ElementId> for RealDom<S> {
|
impl<S: State + Send> Index<ElementId> for RealDom<S> {
|
||||||
type Output = Node<S>;
|
type Output = Node<S>;
|
||||||
|
|
||||||
fn index(&self, id: ElementId) -> &Self::Output {
|
fn index(&self, id: ElementId) -> &Self::Output {
|
||||||
@@ -437,7 +455,7 @@ impl<S: State> Index<ElementId> for RealDom<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: State> Index<RealNodeId> for RealDom<S> {
|
impl<S: State + Send> Index<RealNodeId> for RealDom<S> {
|
||||||
type Output = Node<S>;
|
type Output = Node<S>;
|
||||||
|
|
||||||
fn index(&self, idx: RealNodeId) -> &Self::Output {
|
fn index(&self, idx: RealNodeId) -> &Self::Output {
|
||||||
@@ -445,13 +463,13 @@ impl<S: State> Index<RealNodeId> for RealDom<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: State> IndexMut<ElementId> for RealDom<S> {
|
impl<S: State + Send> IndexMut<ElementId> for RealDom<S> {
|
||||||
fn index_mut(&mut self, id: ElementId) -> &mut Self::Output {
|
fn index_mut(&mut self, id: ElementId) -> &mut Self::Output {
|
||||||
self.tree.get_mut(self.element_to_node_id(id)).unwrap()
|
self.tree.get_mut(self.element_to_node_id(id)).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: State> IndexMut<RealNodeId> for RealDom<S> {
|
impl<S: State + Send> IndexMut<RealNodeId> for RealDom<S> {
|
||||||
fn index_mut(&mut self, idx: RealNodeId) -> &mut Self::Output {
|
fn index_mut(&mut self, idx: RealNodeId) -> &mut Self::Output {
|
||||||
self.tree.get_mut(idx).unwrap()
|
self.tree.get_mut(idx).unwrap()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ use std::cmp::Ordering;
|
|||||||
|
|
||||||
use crate::node::Node;
|
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::passes::{resolve_passes, AnyMapLike, DirtyNodeStates, Pass, TypeErasedPass};
|
||||||
use crate::tree::TreeView;
|
use crate::tree::{Tree, TreeView};
|
||||||
use crate::{FxDashSet, RealNodeId, SendAnyMap};
|
use crate::{FxDashSet, RealNodeId, SendAnyMap};
|
||||||
|
|
||||||
/// Join two sorted iterators
|
/// Join two sorted iterators
|
||||||
@@ -210,21 +210,9 @@ pub trait NodeDepState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 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 + 'static {
|
pub trait State: Default + Clone + AnyMapLike + 'static {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
const PASSES: &'static [AnyPass<Node<Self>>];
|
fn create_passes() -> Box<[TypeErasedPass<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 passes = Self::PASSES.iter().collect();
|
|
||||||
resolve_passes(tree, dirty, passes, ctx)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChildDepState for () {
|
impl ChildDepState for () {
|
||||||
|
|||||||
@@ -121,6 +121,19 @@ pub trait TreeView<T>: Sized {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn node_parent_children_mut(
|
||||||
|
&mut self,
|
||||||
|
id: NodeId,
|
||||||
|
) -> Option<(&mut T, Option<&mut T>, Option<Self::IteratorMut<'_>>)> {
|
||||||
|
let mut_ptr: *mut Self = self;
|
||||||
|
unsafe {
|
||||||
|
// Safety: No node has itself as a parent or child.
|
||||||
|
(*mut_ptr)
|
||||||
|
.get_mut(id)
|
||||||
|
.map(|node| (node, (*mut_ptr).parent_mut(id), (*mut_ptr).children_mut(id)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parent_id(&self, id: NodeId) -> Option<NodeId>;
|
fn parent_id(&self, id: NodeId) -> Option<NodeId>;
|
||||||
|
|
||||||
fn height(&self, id: NodeId) -> Option<u16>;
|
fn height(&self, id: NodeId) -> Option<u16>;
|
||||||
@@ -824,6 +837,7 @@ fn map() {
|
|||||||
Self { value }
|
Self { value }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut tree = Tree::new(Value::new(1));
|
let mut tree = Tree::new(Value::new(1));
|
||||||
let parent = tree.root();
|
let parent = tree.root();
|
||||||
let child = tree.create_node(Value::new(0));
|
let child = tree.create_node(Value::new(0));
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
use crate::{node::NodeType, real_dom::RealDom, state::State, tree::TreeView, NodeId, RealNodeId};
|
use crate::{
|
||||||
|
node::NodeType,
|
||||||
|
passes::{AnyMapLike, TypeErasedPass},
|
||||||
|
real_dom::RealDom,
|
||||||
|
state::State,
|
||||||
|
tree::TreeView,
|
||||||
|
NodeId, RealNodeId,
|
||||||
|
};
|
||||||
use dioxus_core::{Mutation, Mutations};
|
use dioxus_core::{Mutation, Mutations};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
@@ -67,7 +74,7 @@ impl PersistantElementIter {
|
|||||||
|
|
||||||
/// remove stale element refreneces
|
/// remove stale element refreneces
|
||||||
/// returns true if the focused element is removed
|
/// returns true if the focused element is removed
|
||||||
pub fn prune<S: State>(&mut self, mutations: &Mutations, rdom: &RealDom<S>) -> bool {
|
pub fn prune<S: State + Send>(&mut self, mutations: &Mutations, rdom: &RealDom<S>) -> bool {
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
let ids_removed: Vec<_> = mutations
|
let ids_removed: Vec<_> = mutations
|
||||||
.edits
|
.edits
|
||||||
@@ -124,7 +131,7 @@ impl PersistantElementIter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// get the next element
|
/// get the next element
|
||||||
pub fn next<S: State>(&mut self, rdom: &RealDom<S>) -> ElementProduced {
|
pub fn next<S: State + Send>(&mut self, rdom: &RealDom<S>) -> ElementProduced {
|
||||||
if self.stack.is_empty() {
|
if self.stack.is_empty() {
|
||||||
let id = NodeId(0);
|
let id = NodeId(0);
|
||||||
let new = (id, NodePosition::AtNode);
|
let new = (id, NodePosition::AtNode);
|
||||||
@@ -160,9 +167,9 @@ impl PersistantElementIter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// get the previous element
|
/// get the previous element
|
||||||
pub fn prev<S: State>(&mut self, rdom: &RealDom<S>) -> ElementProduced {
|
pub fn prev<S: State + Send>(&mut self, rdom: &RealDom<S>) -> ElementProduced {
|
||||||
// recursively add the last child element to the stack
|
// recursively add the last child element to the stack
|
||||||
fn push_back<S: State>(
|
fn push_back<S: State + Send>(
|
||||||
stack: &mut smallvec::SmallVec<[(RealNodeId, NodePosition); 5]>,
|
stack: &mut smallvec::SmallVec<[(RealNodeId, NodePosition); 5]>,
|
||||||
new_node: RealNodeId,
|
new_node: RealNodeId,
|
||||||
rdom: &RealDom<S>,
|
rdom: &RealDom<S>,
|
||||||
@@ -228,10 +235,19 @@ impl PersistantElementIter {
|
|||||||
|
|
||||||
#[derive(Default, Clone, Debug)]
|
#[derive(Default, Clone, Debug)]
|
||||||
struct Empty {}
|
struct Empty {}
|
||||||
impl State for Empty {
|
impl AnyMapLike for Empty {
|
||||||
const PASSES: &'static [crate::AnyPass<crate::node::Node<Self>>] = &[];
|
fn get<T: std::any::Any>(&self) -> Option<&T> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
const MASKS: &'static [crate::NodeMask] = &[];
|
fn get_mut<T: std::any::Any>(&mut self) -> Option<&mut T> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl State for Empty {
|
||||||
|
fn create_passes() -> Box<[TypeErasedPass<Self>]> {
|
||||||
|
Box::new([])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in new issue
Block a user