WIP make ECS work with reactive system
This commit is contained in:
1 parent
e36874d86e
commit
1587b41829
10 files changed
+564
-685
No files matched your search
@@ -20,7 +20,7 @@ smallvec = "1.6"
|
|||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
anymap = "1.0.0-beta.2"
|
anymap = "1.0.0-beta.2"
|
||||||
slab = "0.4"
|
slab = "0.4"
|
||||||
parking_lot = "0.12.1"
|
parking_lot = { version = "0.12.1", features = ["send_guard"] }
|
||||||
crossbeam-deque = "0.8.2"
|
crossbeam-deque = "0.8.2"
|
||||||
dashmap = "5.4.0"
|
dashmap = "5.4.0"
|
||||||
hashbrown = { version = "0.13.2", features = ["raw"] }
|
hashbrown = { version = "0.13.2", features = ["raw"] }
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ pub use node_ref::NodeMask;
|
|||||||
pub use passes::AnyMapLike;
|
pub use passes::AnyMapLike;
|
||||||
pub use passes::{Dependancy, Pass, TypeErasedPass};
|
pub use passes::{Dependancy, Pass, TypeErasedPass};
|
||||||
use rustc_hash::FxHasher;
|
use rustc_hash::FxHasher;
|
||||||
pub use state::State;
|
|
||||||
pub use tree::NodeId;
|
pub use tree::NodeId;
|
||||||
|
|
||||||
pub mod layout_attributes;
|
pub mod layout_attributes;
|
||||||
@@ -13,7 +12,6 @@ pub mod node;
|
|||||||
pub mod node_ref;
|
pub mod node_ref;
|
||||||
mod passes;
|
mod passes;
|
||||||
pub mod real_dom;
|
pub mod real_dom;
|
||||||
pub mod state;
|
|
||||||
pub mod tree;
|
pub mod tree;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,8 @@
|
|||||||
use crate::{state::State, tree::NodeId};
|
use crate::tree::NodeId;
|
||||||
use dioxus_core::{AnyValue, BorrowedAttributeValue, ElementId};
|
use dioxus_core::{AnyValue, BorrowedAttributeValue, ElementId};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
/// The node is stored client side and stores only basic data about the node.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Node<S: State<V>, V: FromAnyValue = ()> {
|
|
||||||
/// The transformed state of the node.
|
|
||||||
pub state: S,
|
|
||||||
/// The raw data for the node
|
|
||||||
pub node_data: NodeData<V>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct NodeData<V: FromAnyValue = ()> {
|
pub struct NodeData<V: FromAnyValue = ()> {
|
||||||
/// The id of the node
|
/// The id of the node
|
||||||
@@ -38,21 +29,18 @@ pub enum NodeType<V: FromAnyValue = ()> {
|
|||||||
Placeholder,
|
Placeholder,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: State<V>, V: FromAnyValue> Node<S, V> {
|
impl<V: FromAnyValue> NodeData<V> {
|
||||||
pub(crate) fn new(node_type: NodeType<V>) -> Self {
|
pub(crate) fn new(node_type: NodeType<V>) -> Self {
|
||||||
Node {
|
NodeData {
|
||||||
state: S::default(),
|
element_id: None,
|
||||||
node_data: NodeData {
|
node_type,
|
||||||
element_id: None,
|
node_id: NodeId(0),
|
||||||
node_type,
|
|
||||||
node_id: NodeId(0),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get the mounted id of the node
|
/// get the mounted id of the node
|
||||||
pub fn mounted_id(&self) -> Option<ElementId> {
|
pub fn mounted_id(&self) -> Option<ElementId> {
|
||||||
self.node_data.element_id
|
self.element_id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,47 @@
|
|||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
use dioxus_core::ElementId;
|
use dioxus_core::ElementId;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
node::{ElementNode, FromAnyValue, NodeData, NodeType, OwnedAttributeView},
|
node::{ElementNode, FromAnyValue, NodeData, NodeType, OwnedAttributeView},
|
||||||
state::union_ordered_iter,
|
|
||||||
NodeId,
|
NodeId,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Join two sorted iterators
|
||||||
|
pub(crate) fn union_ordered_iter<'a>(
|
||||||
|
s_iter: impl Iterator<Item = &'a str>,
|
||||||
|
o_iter: impl Iterator<Item = &'a str>,
|
||||||
|
new_len_guess: usize,
|
||||||
|
) -> Vec<String> {
|
||||||
|
let mut s_peekable = s_iter.peekable();
|
||||||
|
let mut o_peekable = o_iter.peekable();
|
||||||
|
let mut v = Vec::with_capacity(new_len_guess);
|
||||||
|
while let Some(s_i) = s_peekable.peek() {
|
||||||
|
while let Some(o_i) = o_peekable.peek() {
|
||||||
|
match o_i.cmp(s_i) {
|
||||||
|
Ordering::Greater => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Ordering::Less => {
|
||||||
|
v.push(o_peekable.next().unwrap().to_string());
|
||||||
|
}
|
||||||
|
Ordering::Equal => {
|
||||||
|
o_peekable.next();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v.push(s_peekable.next().unwrap().to_string());
|
||||||
|
}
|
||||||
|
for o_i in o_peekable {
|
||||||
|
v.push(o_i.to_string());
|
||||||
|
}
|
||||||
|
for w in v.windows(2) {
|
||||||
|
debug_assert!(w[1] > w[0]);
|
||||||
|
}
|
||||||
|
v
|
||||||
|
}
|
||||||
|
|
||||||
/// A view into a [VNode] with limited access.
|
/// A view into a [VNode] with limited access.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct NodeView<'a, V: FromAnyValue = ()> {
|
pub struct NodeView<'a, V: FromAnyValue = ()> {
|
||||||
|
|||||||
+173
-193
@@ -1,18 +1,115 @@
|
|||||||
use anymap::AnyMap;
|
use anymap::AnyMap;
|
||||||
|
use parking_lot::RwLock;
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
use std::any::{Any, TypeId};
|
use std::any::{self, Any, TypeId};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
use std::marker::PhantomData;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::node::{FromAnyValue, Node};
|
use crate::node::{FromAnyValue, NodeData};
|
||||||
use crate::node_ref::NodeView;
|
use crate::node_ref::NodeView;
|
||||||
use crate::state::State;
|
use crate::real_dom::RealDom;
|
||||||
use crate::tree::TreeViewMut;
|
use crate::tree::{Node, TreeStateView};
|
||||||
use crate::tree::{Tree, TreeView};
|
|
||||||
use crate::{FxDashMap, FxDashSet, SendAnyMap};
|
use crate::{FxDashMap, FxDashSet, SendAnyMap};
|
||||||
use crate::{NodeId, NodeMask};
|
use crate::{NodeId, NodeMask};
|
||||||
|
|
||||||
pub trait Pass<V: FromAnyValue = ()>: Any {
|
#[derive(Default)]
|
||||||
|
struct DirtyNodes {
|
||||||
|
passes_dirty: Vec<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DirtyNodes {
|
||||||
|
pub fn add_node(&mut self, node_id: NodeId) {
|
||||||
|
let node_id = node_id.0;
|
||||||
|
let index = node_id / 64;
|
||||||
|
let bit = node_id % 64;
|
||||||
|
let encoded = 1 << bit;
|
||||||
|
if let Some(passes) = self.passes_dirty.get_mut(index) {
|
||||||
|
*passes |= encoded;
|
||||||
|
} else {
|
||||||
|
self.passes_dirty.resize(index + 1, 0);
|
||||||
|
self.passes_dirty[index] |= encoded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.passes_dirty.iter().all(|dirty| *dirty == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop(&mut self) -> Option<NodeId> {
|
||||||
|
let index = self.passes_dirty.iter().position(|dirty| *dirty != 0)?;
|
||||||
|
let passes = self.passes_dirty[index];
|
||||||
|
let node_id = passes.trailing_zeros();
|
||||||
|
let encoded = 1 << node_id;
|
||||||
|
self.passes_dirty[index] &= !encoded;
|
||||||
|
Some(NodeId((index * 64) + node_id as usize))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
pub struct DirtyNodeStates {
|
||||||
|
dirty: Arc<RwLock<BTreeMap<u16, FxDashMap<TypeId, DirtyNodes>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DirtyNodeStates {
|
||||||
|
pub fn insert(&self, pass_id: TypeId, node_id: NodeId, height: u16) {
|
||||||
|
let mut dirty = self.dirty.write();
|
||||||
|
if let Some(dirty) = dirty.get_mut(&height) {
|
||||||
|
if let Some(mut entry) = dirty.get_mut(&pass_id) {
|
||||||
|
entry.add_node(node_id);
|
||||||
|
} else {
|
||||||
|
let mut entry = DirtyNodes::default();
|
||||||
|
entry.add_node(node_id);
|
||||||
|
dirty.insert(pass_id, entry);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mut entry = DirtyNodes::default();
|
||||||
|
entry.add_node(node_id);
|
||||||
|
let hm = FxDashMap::default();
|
||||||
|
hm.insert(pass_id, entry);
|
||||||
|
dirty.insert(height, hm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_front(&self, pass_id: TypeId) -> Option<(u16, NodeId)> {
|
||||||
|
let dirty_read = self.dirty.read();
|
||||||
|
let (&height, values) = dirty_read
|
||||||
|
.iter()
|
||||||
|
.find(|(_, values)| values.contains_key(&pass_id))?;
|
||||||
|
let mut dirty = values.get_mut(&pass_id)?;
|
||||||
|
let node_id = dirty.pop()?;
|
||||||
|
if dirty.is_empty() {
|
||||||
|
values.remove(&pass_id);
|
||||||
|
}
|
||||||
|
if values.is_empty() {
|
||||||
|
let mut dirty_write = self.dirty.write();
|
||||||
|
dirty_write.remove(&height);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some((height, node_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_back(&self, pass_id: TypeId) -> Option<(u16, NodeId)> {
|
||||||
|
let dirty_read = self.dirty.read();
|
||||||
|
let (&height, values) = dirty_read
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.find(|(_, values)| values.contains_key(&pass_id))?;
|
||||||
|
let mut dirty = values.get_mut(&pass_id)?;
|
||||||
|
let node_id = dirty.pop()?;
|
||||||
|
if dirty.is_empty() {
|
||||||
|
values.remove(&pass_id);
|
||||||
|
}
|
||||||
|
if values.is_empty() {
|
||||||
|
let mut dirty_write = self.dirty.write();
|
||||||
|
dirty_write.remove(&height);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some((height, node_id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Pass<V: FromAnyValue + Send = ()>: Any {
|
||||||
/// This is a tuple of (T: Any, ..)
|
/// This is a tuple of (T: Any, ..)
|
||||||
type ParentDependencies: Dependancy;
|
type ParentDependencies: Dependancy;
|
||||||
/// This is a tuple of (T: Any, ..)
|
/// This is a tuple of (T: Any, ..)
|
||||||
@@ -26,23 +123,21 @@ pub trait Pass<V: FromAnyValue = ()>: Any {
|
|||||||
node_view: NodeView<V>,
|
node_view: NodeView<V>,
|
||||||
node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
|
node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
|
||||||
parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
|
parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
|
||||||
children: Option<
|
children: Option<Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>>,
|
||||||
impl Iterator<Item = <Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>,
|
|
||||||
>,
|
|
||||||
context: &SendAnyMap,
|
context: &SendAnyMap,
|
||||||
) -> bool;
|
) -> bool;
|
||||||
|
|
||||||
fn validate() {
|
fn validate() {
|
||||||
// no type can be a child and parent dependency
|
// no type can be a child and parent dependency
|
||||||
for type_id in Self::parent_type_ids() {
|
for type_id in Self::parent_type_ids().into_iter().copied() {
|
||||||
for type_id2 in Self::child_type_ids() {
|
for type_id2 in Self::child_type_ids().into_iter().copied() {
|
||||||
if type_id == type_id2 {
|
if type_id == type_id2 {
|
||||||
panic!("type cannot be both a parent and child dependency");
|
panic!("type cannot be both a parent and child dependency");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// this type should not be a node dependency
|
// this type should not be a node dependency
|
||||||
for type_id in Self::node_type_ids() {
|
for type_id in Self::node_type_ids().into_iter().copied() {
|
||||||
if type_id == TypeId::of::<Self>() {
|
if type_id == TypeId::of::<Self>() {
|
||||||
panic!("The current type cannot be a node dependency");
|
panic!("The current type cannot be a node dependency");
|
||||||
}
|
}
|
||||||
@@ -58,85 +153,74 @@ pub trait Pass<V: FromAnyValue = ()>: Any {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_type_erased<T: AnyMapLike + State<V>>() -> TypeErasedPass<T, V>
|
fn to_type_erased() -> TypeErasedPass<V>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
Self::validate();
|
Self::validate();
|
||||||
TypeErasedPass {
|
TypeErasedPass {
|
||||||
this_type_id: TypeId::of::<Self>(),
|
this_type_id: TypeId::of::<Self>(),
|
||||||
combined_dependancy_type_ids: Self::all_dependanices().into_iter().collect(),
|
combined_dependancy_type_ids: Self::all_dependanices().into_iter().copied().collect(),
|
||||||
parent_dependant: !Self::parent_type_ids().is_empty(),
|
parent_dependant: !Self::parent_type_ids().is_empty(),
|
||||||
child_dependant: !Self::child_type_ids().is_empty(),
|
child_dependant: !Self::child_type_ids().is_empty(),
|
||||||
dependants: FxHashSet::default(),
|
dependants: FxHashSet::default(),
|
||||||
mask: Self::NODE_MASK,
|
mask: Self::NODE_MASK,
|
||||||
pass_direction: Self::pass_direction(),
|
pass_direction: Self::pass_direction(),
|
||||||
pass: Box::new(
|
pass: Box::new(
|
||||||
|node_id: NodeId, any_map: &mut Tree<Node<T, V>>, context: &SendAnyMap| {
|
|node_id: NodeId, tree: &mut TreeStateView, context: &SendAnyMap| {
|
||||||
let (current_node, parent, children) = any_map
|
debug_assert!(!Self::NodeDependencies::type_ids()
|
||||||
.node_parent_children_mut(node_id)
|
.into_iter()
|
||||||
.expect("tried to run pass on node that does not exist");
|
.any(|id| *id == TypeId::of::<Self>()));
|
||||||
let current_node_raw = current_node as *mut Node<T, V>;
|
// get all of the states from the tree view
|
||||||
let node = Self::NodeDependencies::borrow_elements_from(¤t_node.state)
|
// Safety: No node has itself as a parent or child.
|
||||||
.expect("tried to get a pass that does not exist");
|
let node_raw = tree.get_mut::<Self>(node_id).unwrap() as *mut Self;
|
||||||
let parent = parent.map(|parent| {
|
let node_data = tree.get_single::<NodeData<V>>(node_id).unwrap();
|
||||||
Self::ParentDependencies::borrow_elements_from(&parent.state)
|
let node = tree.get::<Self::NodeDependencies>(node_id).unwrap();
|
||||||
.expect("tried to get a pass that does not exist")
|
let children = tree.children::<Self::ChildDependencies>(node_id);
|
||||||
});
|
let parent = tree.parent::<Self::ParentDependencies>(node_id);
|
||||||
let children = children.map(|children| {
|
let myself = unsafe { &mut *node_raw };
|
||||||
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")
|
|
||||||
};
|
|
||||||
myself.pass(
|
myself.pass(
|
||||||
NodeView::new(¤t_node.node_data, Self::NODE_MASK),
|
NodeView::new(&node_data, Self::NODE_MASK),
|
||||||
node,
|
node,
|
||||||
parent,
|
parent,
|
||||||
children,
|
children,
|
||||||
context,
|
context,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
) as PassCallback,
|
||||||
as Box<dyn Fn(NodeId, &mut Tree<Node<T, V>>, &SendAnyMap) -> bool + Send + Sync>,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parent_type_ids() -> Vec<TypeId> {
|
fn parent_type_ids() -> Box<[TypeId]> {
|
||||||
Self::ParentDependencies::type_ids()
|
Self::ParentDependencies::type_ids()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn child_type_ids() -> Vec<TypeId> {
|
fn child_type_ids() -> Box<[TypeId]> {
|
||||||
Self::ChildDependencies::type_ids()
|
Self::ChildDependencies::type_ids()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_type_ids() -> Vec<TypeId> {
|
fn node_type_ids() -> Box<[TypeId]> {
|
||||||
Self::NodeDependencies::type_ids()
|
Self::NodeDependencies::type_ids()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_dependanices() -> Vec<TypeId> {
|
fn all_dependanices() -> Box<[TypeId]> {
|
||||||
let mut dependencies = Self::parent_type_ids();
|
let mut dependencies = Self::parent_type_ids().to_vec();
|
||||||
dependencies.extend(Self::child_type_ids());
|
dependencies.extend(Self::child_type_ids().into_iter());
|
||||||
dependencies.extend(Self::node_type_ids());
|
dependencies.extend(Self::node_type_ids().into_iter());
|
||||||
dependencies
|
dependencies.into_boxed_slice()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pass_direction() -> PassDirection {
|
fn pass_direction() -> PassDirection {
|
||||||
if Self::child_type_ids()
|
if Self::child_type_ids()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.any(|type_id| type_id == TypeId::of::<Self>())
|
.any(|type_id| *type_id == TypeId::of::<Self>())
|
||||||
{
|
{
|
||||||
PassDirection::ChildToParent
|
PassDirection::ChildToParent
|
||||||
} else if Self::parent_type_ids()
|
} else if Self::parent_type_ids()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.any(|type_id| type_id == TypeId::of::<Self>())
|
.any(|type_id| *type_id == TypeId::of::<Self>())
|
||||||
{
|
{
|
||||||
PassDirection::ParentToChild
|
PassDirection::ParentToChild
|
||||||
} else {
|
} else {
|
||||||
@@ -145,63 +229,57 @@ pub trait Pass<V: FromAnyValue = ()>: Any {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TypeErasedPass<T: AnyMapLike + State<V>, V: FromAnyValue = ()> {
|
pub struct TypeErasedPass<V: FromAnyValue + Send = ()> {
|
||||||
pub(crate) this_type_id: TypeId,
|
pub(crate) this_type_id: TypeId,
|
||||||
pub(crate) parent_dependant: bool,
|
pub(crate) parent_dependant: bool,
|
||||||
pub(crate) child_dependant: bool,
|
pub(crate) child_dependant: bool,
|
||||||
pub(crate) combined_dependancy_type_ids: FxHashSet<TypeId>,
|
pub(crate) combined_dependancy_type_ids: FxHashSet<TypeId>,
|
||||||
pub(crate) dependants: FxHashSet<TypeId>,
|
pub(crate) dependants: FxHashSet<TypeId>,
|
||||||
pub(crate) mask: NodeMask,
|
pub(crate) mask: NodeMask,
|
||||||
pass: PassCallback<T, V>,
|
pass: PassCallback,
|
||||||
pub(crate) pass_direction: PassDirection,
|
pub(crate) pass_direction: PassDirection,
|
||||||
|
phantom: PhantomData<V>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: AnyMapLike + State<V>, V: FromAnyValue> TypeErasedPass<T, V> {
|
impl<V: FromAnyValue + Send> TypeErasedPass<V> {
|
||||||
fn resolve(
|
fn resolve(
|
||||||
&self,
|
&self,
|
||||||
tree: &mut Tree<Node<T, V>>,
|
mut tree: TreeStateView,
|
||||||
mut dirty: DirtyNodes,
|
dirty: &DirtyNodeStates,
|
||||||
dirty_states: &DirtyNodeStates,
|
|
||||||
nodes_updated: &FxDashSet<NodeId>,
|
nodes_updated: &FxDashSet<NodeId>,
|
||||||
ctx: &SendAnyMap,
|
ctx: &SendAnyMap,
|
||||||
) {
|
) {
|
||||||
match self.pass_direction {
|
match self.pass_direction {
|
||||||
PassDirection::ParentToChild => {
|
PassDirection::ParentToChild => {
|
||||||
while let Some(id) = dirty.pop_front() {
|
while let Some((height, id)) = dirty.pop_front(self.this_type_id) {
|
||||||
if (self.pass)(id, tree, ctx) {
|
if (self.pass)(id, &mut tree, ctx) {
|
||||||
nodes_updated.insert(id);
|
nodes_updated.insert(id);
|
||||||
for id in tree.children_ids(id).unwrap() {
|
for id in tree.children_ids(id).unwrap() {
|
||||||
for dependant in &self.dependants {
|
for dependant in &self.dependants {
|
||||||
dirty_states.insert(*dependant, *id);
|
dirty.insert(*dependant, id, height + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
let height = tree.height(*id).unwrap();
|
|
||||||
dirty.insert(height, *id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PassDirection::ChildToParent => {
|
PassDirection::ChildToParent => {
|
||||||
while let Some(id) = dirty.pop_back() {
|
while let Some((height, id)) = dirty.pop_back(self.this_type_id) {
|
||||||
if (self.pass)(id, tree, ctx) {
|
if (self.pass)(id, &mut tree, ctx) {
|
||||||
nodes_updated.insert(id);
|
nodes_updated.insert(id);
|
||||||
if let Some(id) = tree.parent_id(id) {
|
if let Some(id) = tree.parent_id(id) {
|
||||||
for dependant in &self.dependants {
|
for dependant in &self.dependants {
|
||||||
dirty_states.insert(*dependant, id);
|
dirty.insert(*dependant, id, height - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
let height = tree.height(id).unwrap();
|
|
||||||
dirty.insert(height, id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PassDirection::AnyOrder => {
|
PassDirection::AnyOrder => {
|
||||||
while let Some(id) = dirty.pop_back() {
|
while let Some((height, id)) = dirty.pop_back(self.this_type_id) {
|
||||||
if (self.pass)(id, tree, ctx) {
|
if (self.pass)(id, &mut tree, ctx) {
|
||||||
nodes_updated.insert(id);
|
nodes_updated.insert(id);
|
||||||
for dependant in &self.dependants {
|
for dependant in &self.dependants {
|
||||||
dirty_states.insert(*dependant, id);
|
dirty.insert(*dependant, id, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,30 +295,20 @@ pub enum PassDirection {
|
|||||||
AnyOrder,
|
AnyOrder,
|
||||||
}
|
}
|
||||||
|
|
||||||
type PassCallback<T, V> =
|
type PassCallback = Box<dyn Fn(NodeId, &mut TreeStateView, &SendAnyMap) -> bool + Send + Sync>;
|
||||||
Box<dyn Fn(NodeId, &mut Tree<Node<T, V>>, &SendAnyMap) -> bool + Send + Sync>;
|
|
||||||
|
|
||||||
pub trait AnyMapLike {
|
pub trait AnyMapLike<'a> {
|
||||||
fn get<T: Any>(&self) -> Option<&T>;
|
fn get<T: Any>(self) -> Option<&'a T>;
|
||||||
fn get_mut<T: Any>(&mut self) -> Option<&mut T>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AnyMapLike for AnyMap {
|
impl<'a> AnyMapLike<'a> for &'a AnyMap {
|
||||||
fn get<T: Any>(&self) -> Option<&T> {
|
fn get<T: Any>(self) -> Option<&'a T> {
|
||||||
self.get()
|
self.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_mut<T: Any>(&mut self) -> Option<&mut T> {
|
|
||||||
self.get_mut()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AnyMapLike for SendAnyMap {
|
impl<'a> AnyMapLike<'a> for &'a SendAnyMap {
|
||||||
fn get<T: Any>(&self) -> Option<&T> {
|
fn get<T: Any>(self) -> Option<&'a T> {
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_mut<T: Any>(&mut self) -> Option<&mut T> {
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -250,8 +318,10 @@ pub trait Dependancy {
|
|||||||
where
|
where
|
||||||
Self: 'a;
|
Self: 'a;
|
||||||
|
|
||||||
fn borrow_elements_from<T: AnyMapLike>(map: &T) -> Option<Self::ElementBorrowed<'_>>;
|
fn borrow_elements_from<'a, T: AnyMapLike<'a> + Copy>(
|
||||||
fn type_ids() -> Vec<TypeId>;
|
map: T,
|
||||||
|
) -> Option<Self::ElementBorrowed<'a>>;
|
||||||
|
fn type_ids() -> Box<[TypeId]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_dependancy {
|
macro_rules! impl_dependancy {
|
||||||
@@ -260,12 +330,12 @@ macro_rules! impl_dependancy {
|
|||||||
type ElementBorrowed<'a> = ($(&'a $t,)*) where Self: 'a;
|
type ElementBorrowed<'a> = ($(&'a $t,)*) where Self: 'a;
|
||||||
|
|
||||||
#[allow(unused_variables, clippy::unused_unit, non_snake_case)]
|
#[allow(unused_variables, clippy::unused_unit, non_snake_case)]
|
||||||
fn borrow_elements_from<T: AnyMapLike>(map: &T) -> Option<Self::ElementBorrowed<'_>> {
|
fn borrow_elements_from<'a, T: AnyMapLike<'a> + Copy>(map: T) -> Option<Self::ElementBorrowed<'a>> {
|
||||||
Some(($(map.get::<$t>()?,)*))
|
Some(($(map.get::<$t>()?,)*))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_ids() -> Vec<TypeId> {
|
fn type_ids() -> Box<[TypeId]> {
|
||||||
vec![$(TypeId::of::<$t>()),*]
|
Box::new([$(TypeId::of::<$t>()),*])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -289,96 +359,12 @@ 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);
|
||||||
impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
|
impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
pub fn resolve_passes<V: FromAnyValue + Send + Sync>(
|
||||||
pub struct DirtyNodes {
|
tree: &mut RealDom<V>,
|
||||||
map: BTreeMap<u16, FxHashSet<NodeId>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DirtyNodes {
|
|
||||||
fn add_node(&mut self, node_id: NodeId) {
|
|
||||||
let node_id = node_id.0;
|
|
||||||
let index = node_id / 64;
|
|
||||||
let bit = node_id % 64;
|
|
||||||
let encoded = 1 << bit;
|
|
||||||
if let Some(passes) = self.passes_dirty.get_mut(index) {
|
|
||||||
*passes |= encoded;
|
|
||||||
} else {
|
|
||||||
self.passes_dirty.resize(index + 1, 0);
|
|
||||||
self.passes_dirty[index] |= encoded;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_empty(&self) -> bool {
|
|
||||||
self.passes_dirty.iter().all(|dirty| *dirty == 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pop(&mut self) -> Option<NodeId> {
|
|
||||||
let index = self.passes_dirty.iter().position(|dirty| *dirty != 0)?;
|
|
||||||
let passes = self.passes_dirty[index];
|
|
||||||
let node_id = passes.trailing_zeros();
|
|
||||||
let encoded = 1 << node_id;
|
|
||||||
self.passes_dirty[index] &= !encoded;
|
|
||||||
Some(NodeId((index * 64) + node_id as usize))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct DirtyNodeStates {
|
|
||||||
dirty: FxDashMap<NodeId, FxHashSet<TypeId>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DirtyNodeStates {
|
|
||||||
pub fn insert(&self, pass_id: TypeId, node_id: NodeId) {
|
|
||||||
if let Some(mut dirty) = self.dirty.get_mut(&node_id) {
|
|
||||||
dirty.insert(pass_id);
|
|
||||||
} else {
|
|
||||||
let mut v = FxHashSet::default();
|
|
||||||
v.insert(pass_id);
|
|
||||||
self.dirty.insert(node_id, v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn all_dirty<T>(&self, pass_id: TypeId, dirty_nodes: &mut DirtyNodes, tree: &impl TreeView<T>) {
|
|
||||||
for entry in self.dirty.iter() {
|
|
||||||
let node_id = entry.key();
|
|
||||||
let dirty = entry.value();
|
|
||||||
if dirty.contains(&pass_id) {
|
|
||||||
dirty_nodes.insert(tree.height(*node_id).unwrap(), *node_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if values.is_empty() {
|
|
||||||
self.dirty.remove(&height);
|
|
||||||
}
|
|
||||||
|
|
||||||
Some((height, node_id))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pop_back(&mut self, pass_id: PassId) -> Option<(u16, NodeId)> {
|
|
||||||
let (&height, values) = self
|
|
||||||
.dirty
|
|
||||||
.iter_mut()
|
|
||||||
.rev()
|
|
||||||
.find(|(_, values)| values.contains_key(&pass_id))?;
|
|
||||||
let dirty = values.get_mut(&pass_id)?;
|
|
||||||
let node_id = dirty.pop()?;
|
|
||||||
if dirty.is_empty() {
|
|
||||||
values.remove(&pass_id);
|
|
||||||
}
|
|
||||||
if values.is_empty() {
|
|
||||||
self.dirty.remove(&height);
|
|
||||||
}
|
|
||||||
|
|
||||||
Some((height, node_id))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resolve_passes<T: AnyMapLike + State<V> + Send, V: FromAnyValue + Send>(
|
|
||||||
tree: &mut Tree<Node<T, V>>,
|
|
||||||
dirty_nodes: DirtyNodeStates,
|
dirty_nodes: DirtyNodeStates,
|
||||||
passes: &[TypeErasedPass<T, V>],
|
|
||||||
ctx: SendAnyMap,
|
ctx: SendAnyMap,
|
||||||
) -> FxDashSet<NodeId> {
|
) -> FxDashSet<NodeId> {
|
||||||
let dirty_states = Arc::new(dirty_nodes);
|
let passes = &tree.passes;
|
||||||
let mut resolved_passes: FxHashSet<TypeId> = 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());
|
||||||
@@ -399,21 +385,15 @@ pub fn resolve_passes<T: AnyMapLike + State<V> + Send, V: FromAnyValue + Send>(
|
|||||||
pass_indexes_remaining.remove(i);
|
pass_indexes_remaining.remove(i);
|
||||||
resolving.push(pass_id);
|
resolving.push(pass_id);
|
||||||
currently_in_use.insert(pass.this_type_id);
|
currently_in_use.insert(pass.this_type_id);
|
||||||
// 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_view = tree.tree.state_views(
|
||||||
let tree_unbounded_mut = unsafe { &mut *(tree as *mut _) };
|
[pass.this_type_id],
|
||||||
let dirty_states = dirty_states.clone();
|
pass.combined_dependancy_type_ids.iter().copied(),
|
||||||
|
);
|
||||||
|
let dirty_nodes = dirty_nodes.clone();
|
||||||
let nodes_updated = nodes_updated.clone();
|
let nodes_updated = nodes_updated.clone();
|
||||||
let ctx = ctx.clone();
|
let ctx = ctx.clone();
|
||||||
s.spawn(move || {
|
s.spawn(move || {
|
||||||
let mut dirty = DirtyNodes::default();
|
pass.resolve(tree_view, &dirty_nodes, &nodes_updated, &ctx);
|
||||||
dirty_states.all_dirty(pass_id, &mut dirty, tree_unbounded_mut);
|
|
||||||
pass.resolve(
|
|
||||||
tree_unbounded_mut,
|
|
||||||
dirty,
|
|
||||||
&dirty_states,
|
|
||||||
&nodes_updated,
|
|
||||||
&ctx,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
use dioxus_core::{BorrowedAttributeValue, ElementId, Mutations, TemplateNode};
|
use dioxus_core::{BorrowedAttributeValue, ElementId, Mutations, TemplateNode};
|
||||||
|
use parking_lot::{MappedRwLockReadGuard, MappedRwLockWriteGuard};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use std::ops::{Index, IndexMut};
|
use std::any::Any;
|
||||||
|
|
||||||
use crate::node::{
|
use crate::node::{
|
||||||
ElementNode, FromAnyValue, Node, NodeData, NodeType, OwnedAttributeDiscription,
|
ElementNode, FromAnyValue, NodeData, NodeType, OwnedAttributeDiscription, OwnedAttributeValue,
|
||||||
OwnedAttributeValue,
|
|
||||||
};
|
};
|
||||||
use crate::node_ref::{AttributeMask, NodeMask};
|
use crate::node_ref::{AttributeMask, NodeMask};
|
||||||
use crate::passes::{resolve_passes, DirtyNodeStates, TypeErasedPass};
|
use crate::passes::{resolve_passes, DirtyNodeStates, TypeErasedPass};
|
||||||
use crate::state::State;
|
use crate::tree::{EntryBuilder, NodeId, Tree};
|
||||||
use crate::tree::{NodeId, Tree, TreeLike, TreeView, TreeViewMut};
|
|
||||||
use crate::{FxDashSet, SendAnyMap};
|
use crate::{FxDashSet, SendAnyMap};
|
||||||
|
|
||||||
/// 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.
|
||||||
@@ -18,41 +17,36 @@ use crate::{FxDashSet, SendAnyMap};
|
|||||||
///
|
///
|
||||||
/// # Custom values
|
/// # Custom values
|
||||||
/// To allow custom values to be passed into attributes implement FromAnyValue on a type that can represent your custom value and specify the V generic to be that type. If you have many different custom values, it can be useful to use a enum type to represent the varients.
|
/// To allow custom values to be passed into attributes implement FromAnyValue on a type that can represent your custom value and specify the V generic to be that type. If you have many different custom values, it can be useful to use a enum type to represent the varients.
|
||||||
pub struct RealDom<S: State<V>, V: FromAnyValue = ()> {
|
pub struct RealDom<V: FromAnyValue + Send = ()> {
|
||||||
tree: Tree<Node<S, V>>,
|
pub(crate) tree: Tree,
|
||||||
/// a map from element id to real node id
|
/// a map from element id to real node id
|
||||||
node_id_mapping: Vec<Option<NodeId>>,
|
node_id_mapping: Vec<Option<NodeId>>,
|
||||||
nodes_listening: FxHashMap<String, FxHashSet<NodeId>>,
|
nodes_listening: FxHashMap<String, FxHashSet<NodeId>>,
|
||||||
stack: Vec<NodeId>,
|
stack: Vec<NodeId>,
|
||||||
templates: FxHashMap<String, Vec<NodeId>>,
|
templates: FxHashMap<String, Vec<NodeId>>,
|
||||||
pub(crate) passes: Box<[TypeErasedPass<S, V>]>,
|
pub(crate) passes: Box<[TypeErasedPass<V>]>,
|
||||||
pub(crate) nodes_updated: FxHashMap<NodeId, NodeMask>,
|
pub(crate) nodes_updated: FxHashMap<NodeId, NodeMask>,
|
||||||
passes_updated: DirtyNodeStates,
|
passes_updated: DirtyNodeStates,
|
||||||
parent_changed_nodes: FxHashSet<NodeId>,
|
parent_changed_nodes: FxHashSet<NodeId>,
|
||||||
child_changed_nodes: FxHashSet<NodeId>,
|
child_changed_nodes: FxHashSet<NodeId>,
|
||||||
nodes_created: FxHashSet<NodeId>,
|
nodes_created: FxHashSet<NodeId>,
|
||||||
|
phantom: std::marker::PhantomData<V>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: State<V>, V: FromAnyValue> Default for RealDom<S, V> {
|
impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
||||||
fn default() -> Self {
|
pub fn new(mut passes: Box<[TypeErasedPass<V>]>) -> RealDom<V> {
|
||||||
Self::new()
|
let tree = Tree::new();
|
||||||
}
|
let root_id = tree.root();
|
||||||
}
|
let root = tree.get_node(root_id);
|
||||||
|
let mut root_node: NodeData<V> = NodeData::new(NodeType::Element(ElementNode {
|
||||||
impl<S: State<V>, V: FromAnyValue> RealDom<S, V> {
|
|
||||||
pub fn new() -> RealDom<S, V> {
|
|
||||||
let mut root = Node::new(NodeType::Element(ElementNode {
|
|
||||||
tag: "Root".to_string(),
|
tag: "Root".to_string(),
|
||||||
namespace: Some("Root".to_string()),
|
namespace: Some("Root".to_string()),
|
||||||
attributes: FxHashMap::default(),
|
attributes: FxHashMap::default(),
|
||||||
listeners: FxHashSet::default(),
|
listeners: FxHashSet::default(),
|
||||||
}));
|
}));
|
||||||
root.node_data.element_id = Some(ElementId(0));
|
root_node.element_id = Some(ElementId(0));
|
||||||
let mut tree = Tree::new(root);
|
root_node.node_id = root_id;
|
||||||
let root_id = tree.root();
|
root.insert(root_node);
|
||||||
tree.get_mut(root_id).unwrap().node_data.node_id = root_id;
|
|
||||||
|
|
||||||
let mut passes = S::create_passes();
|
|
||||||
|
|
||||||
// resolve dependants for each pass
|
// resolve dependants for each pass
|
||||||
for i in 1..passes.len() {
|
for i in 1..passes.len() {
|
||||||
@@ -83,6 +77,7 @@ impl<S: State<V>, V: FromAnyValue> RealDom<S, V> {
|
|||||||
parent_changed_nodes: FxHashSet::default(),
|
parent_changed_nodes: FxHashSet::default(),
|
||||||
child_changed_nodes: FxHashSet::default(),
|
child_changed_nodes: FxHashSet::default(),
|
||||||
nodes_created: FxHashSet::default(),
|
nodes_created: FxHashSet::default(),
|
||||||
|
phantom: std::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,9 +102,9 @@ impl<S: State<V>, V: FromAnyValue> RealDom<S, V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_element_id(&mut self, node_id: NodeId, element_id: ElementId) {
|
fn set_element_id(&mut self, node_id: NodeId, element_id: ElementId) {
|
||||||
let node = self.tree.get_mut(node_id).unwrap();
|
let mut node = self.tree.write::<NodeData>(node_id).unwrap();
|
||||||
let node_id = node.node_data.node_id;
|
let node_id = node.node_id;
|
||||||
node.node_data.element_id = Some(element_id);
|
node.element_id = Some(element_id);
|
||||||
if self.node_id_mapping.len() <= element_id.0 {
|
if self.node_id_mapping.len() <= element_id.0 {
|
||||||
self.node_id_mapping.resize(element_id.0 + 1, None);
|
self.node_id_mapping.resize(element_id.0 + 1, None);
|
||||||
}
|
}
|
||||||
@@ -124,14 +119,21 @@ impl<S: State<V>, V: FromAnyValue> RealDom<S, V> {
|
|||||||
current
|
current
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_node(&mut self, node: Node<S, V>, mark_dirty: bool) -> NodeId {
|
fn create_node(
|
||||||
let node_id = self.tree.create_node(node);
|
&mut self,
|
||||||
let node = self.tree.get_mut(node_id).unwrap();
|
mut node: NodeData<V>,
|
||||||
node.node_data.node_id = node_id;
|
id: Option<ElementId>,
|
||||||
|
mark_dirty: bool,
|
||||||
|
) -> EntryBuilder<'_> {
|
||||||
|
let mut node_entry = self.tree.create_node();
|
||||||
|
let node_id = node_entry.id();
|
||||||
|
node.node_id = node_id;
|
||||||
|
node.element_id = id;
|
||||||
|
node_entry.insert(node);
|
||||||
if mark_dirty {
|
if mark_dirty {
|
||||||
self.nodes_created.insert(node_id);
|
self.nodes_created.insert(node_id);
|
||||||
}
|
}
|
||||||
node_id
|
node_entry
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_child(&mut self, node_id: NodeId, child_id: NodeId) {
|
fn add_child(&mut self, node_id: NodeId, child_id: NodeId) {
|
||||||
@@ -146,7 +148,7 @@ impl<S: State<V>, V: FromAnyValue> RealDom<S, V> {
|
|||||||
attrs,
|
attrs,
|
||||||
children,
|
children,
|
||||||
} => {
|
} => {
|
||||||
let node = Node::new(NodeType::Element(ElementNode {
|
let node = NodeData::new(NodeType::Element(ElementNode {
|
||||||
tag: tag.to_string(),
|
tag: tag.to_string(),
|
||||||
namespace: namespace.map(|s| s.to_string()),
|
namespace: namespace.map(|s| s.to_string()),
|
||||||
attributes: attrs
|
attributes: attrs
|
||||||
@@ -169,22 +171,22 @@ impl<S: State<V>, V: FromAnyValue> RealDom<S, V> {
|
|||||||
.collect(),
|
.collect(),
|
||||||
listeners: FxHashSet::default(),
|
listeners: FxHashSet::default(),
|
||||||
}));
|
}));
|
||||||
let node_id = self.create_node(node, true);
|
let node_id = self.create_node(node, None, true).id();
|
||||||
for child in *children {
|
for child in *children {
|
||||||
let child_id = self.create_template_node(child);
|
let child_id = self.create_template_node(child);
|
||||||
self.add_child(node_id, child_id);
|
self.add_child(node_id, child_id);
|
||||||
}
|
}
|
||||||
node_id
|
node_id
|
||||||
}
|
}
|
||||||
TemplateNode::Text { text } => {
|
TemplateNode::Text { text } => self
|
||||||
self.create_node(Node::new(NodeType::Text(text.to_string())), true)
|
.create_node(NodeData::new(NodeType::Text(text.to_string())), None, true)
|
||||||
}
|
.id(),
|
||||||
TemplateNode::Dynamic { .. } => {
|
TemplateNode::Dynamic { .. } => self
|
||||||
self.create_node(Node::new(NodeType::Placeholder), true)
|
.create_node(NodeData::new(NodeType::Placeholder), None, true)
|
||||||
}
|
.id(),
|
||||||
TemplateNode::DynamicText { .. } => {
|
TemplateNode::DynamicText { .. } => self
|
||||||
self.create_node(Node::new(NodeType::Text(String::new())), true)
|
.create_node(NodeData::new(NodeType::Text(String::new())), None, true)
|
||||||
}
|
.id(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,29 +216,26 @@ impl<S: State<V>, V: FromAnyValue> RealDom<S, V> {
|
|||||||
self.set_element_id(self.load_child(path), id);
|
self.set_element_id(self.load_child(path), id);
|
||||||
}
|
}
|
||||||
CreatePlaceholder { id } => {
|
CreatePlaceholder { id } => {
|
||||||
let node = Node::new(NodeType::Placeholder);
|
let node = NodeData::new(NodeType::Placeholder);
|
||||||
let node_id = self.create_node(node, true);
|
let node_id = self.create_node(node, None, true).id();
|
||||||
self.set_element_id(node_id, id);
|
self.set_element_id(node_id, id);
|
||||||
self.stack.push(node_id);
|
self.stack.push(node_id);
|
||||||
}
|
}
|
||||||
CreateTextNode { value, id } => {
|
CreateTextNode { value, id } => {
|
||||||
let node = Node::new(NodeType::Text(value.to_string()));
|
let node_data = NodeData::new(NodeType::Text(value.to_string()));
|
||||||
let node_id = self.create_node(node, true);
|
let node_id = self.create_node(node_data, None, true).id();
|
||||||
let node = self.tree.get_mut(node_id).unwrap();
|
self.set_element_id(node_id, id);
|
||||||
node.node_data.element_id = Some(id);
|
|
||||||
self.stack.push(node_id);
|
self.stack.push(node_id);
|
||||||
}
|
}
|
||||||
HydrateText { path, value, id } => {
|
HydrateText { path, value, id } => {
|
||||||
let node_id = self.load_child(path);
|
let node_id = self.load_child(path);
|
||||||
self.set_element_id(node_id, id);
|
self.set_element_id(node_id, id);
|
||||||
let node = self.tree.get_mut(node_id).unwrap();
|
let mut node = self.get_mut(node_id).unwrap();
|
||||||
if let NodeType::Text(text) = &mut node.node_data.node_type {
|
if let NodeTypeMut::Text(text) = node.node_type_mut() {
|
||||||
*text = value.to_string();
|
*text = value.to_string();
|
||||||
} else {
|
} else {
|
||||||
node.node_data.node_type = NodeType::Text(value.to_string());
|
node.set_type(NodeType::Text(value.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.mark_dirty(node_id, NodeMask::new().with_text());
|
|
||||||
}
|
}
|
||||||
LoadTemplate { name, index, id } => {
|
LoadTemplate { name, index, id } => {
|
||||||
let template_id = self.templates[name][index];
|
let template_id = self.templates[name][index];
|
||||||
@@ -350,15 +349,14 @@ impl<S: State<V>, V: FromAnyValue> RealDom<S, V> {
|
|||||||
|
|
||||||
/// 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.
|
||||||
/// This can be useful to avoid creating duplicate events.
|
/// This can be useful to avoid creating duplicate events.
|
||||||
pub fn get_listening_sorted(&self, event: &'static str) -> Vec<&Node<S, V>> {
|
pub fn get_listening_sorted(&self, event: &'static str) -> Vec<NodeId> {
|
||||||
if let Some(nodes) = self.nodes_listening.get(event) {
|
if let Some(nodes) = self.nodes_listening.get(event) {
|
||||||
let mut listening: Vec<_> = nodes.iter().map(|id| self.get(*id).unwrap()).collect();
|
let mut listening: Vec<_> = nodes
|
||||||
listening.sort_by(|n1, n2| {
|
.iter()
|
||||||
(self.tree.height(n1.node_data.node_id))
|
.map(|id| (*id, self.tree.height(*id).unwrap()))
|
||||||
.cmp(&self.tree.height(n2.node_data.node_id))
|
.collect();
|
||||||
.reverse()
|
listening.sort_by(|(_, h1), (_, h2)| h1.cmp(h2).reverse());
|
||||||
});
|
listening.into_iter().map(|(id, _)| id).collect()
|
||||||
listening
|
|
||||||
} else {
|
} else {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
@@ -376,160 +374,94 @@ impl<S: State<V>, V: FromAnyValue> RealDom<S, V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn clone_node(&mut self, node_id: NodeId) -> NodeId {
|
fn clone_node(&mut self, node_id: NodeId) -> NodeId {
|
||||||
let node = self.tree.get(node_id).unwrap();
|
let node = self.get(node_id).unwrap();
|
||||||
let new_node = Node {
|
let new_node = node.node_data().clone();
|
||||||
state: node.state.clone(),
|
let new_id = self.create_node(new_node, None, true).id();
|
||||||
node_data: node.node_data.clone(),
|
|
||||||
};
|
|
||||||
let new_id = self.create_node(new_node, true);
|
|
||||||
|
|
||||||
let self_ptr = self as *mut Self;
|
|
||||||
for child in self.tree.children_ids(node_id).unwrap() {
|
for child in self.tree.children_ids(node_id).unwrap() {
|
||||||
unsafe {
|
let child_id = self.clone_node(child);
|
||||||
// this is safe because no node has itself as a child
|
self.add_child(new_id, child_id);
|
||||||
let self_mut = &mut *self_ptr;
|
|
||||||
let child_id = self_mut.clone_node(*child);
|
|
||||||
self_mut.add_child(new_id, child_id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
new_id
|
new_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn root(&self) -> NodeId {
|
||||||
|
self.tree.root()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(&self, id: NodeId) -> Option<NodeRef<'_, V>> {
|
||||||
|
self.tree.contains(id).then(|| NodeRef { id, dom: &self })
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_mut(&mut self, id: NodeId) -> Option<NodeMut<'_, V>> {
|
pub fn get_mut(&mut self, id: NodeId) -> Option<NodeMut<'_, V>> {
|
||||||
self.tree.get_mut(id).map(|node| NodeMut {
|
self.tree.contains(id).then(|| NodeMut {
|
||||||
node: &mut node.node_data,
|
id,
|
||||||
dirty: NodeMask::new(),
|
dirty: NodeMask::new(),
|
||||||
nodes_updated: &mut self.nodes_updated,
|
dom: self,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// WARNING: This escapes the reactive system that the real dom uses. Any changes made with this method will not trigger updates in states when [RealDom::update_state] is called.
|
/// WARNING: This escapes the reactive system that the real dom uses. Any changes made with this method will not trigger updates in states when [RealDom::update_state] is called.
|
||||||
pub fn get_mut_raw(&mut self, id: NodeId) -> Option<&mut Node<S, V>> {
|
pub fn get_mut_raw(&mut self, id: NodeId) -> Option<&mut NodeData<V>> {
|
||||||
self.tree.get_mut(id)
|
self.tree.write(id)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: State<V> + Send, V: FromAnyValue + Send> RealDom<S, V> {
|
|
||||||
/// 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,
|
||||||
ctx: SendAnyMap,
|
ctx: SendAnyMap,
|
||||||
) -> (FxDashSet<NodeId>, FxHashMap<NodeId, NodeMask>) {
|
) -> (FxDashSet<NodeId>, FxHashMap<NodeId, NodeMask>) {
|
||||||
let passes = &self.passes;
|
|
||||||
let dirty_nodes = std::mem::take(&mut self.passes_updated);
|
let dirty_nodes = std::mem::take(&mut self.passes_updated);
|
||||||
let nodes_updated = std::mem::take(&mut self.nodes_updated);
|
let nodes_updated = std::mem::take(&mut self.nodes_updated);
|
||||||
for (&node, 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
|
// remove any nodes that were created and then removed in the same mutations from the dirty nodes list
|
||||||
if self.tree.contains(node) {
|
if let Some(height) = self.tree.height(node) {
|
||||||
for pass in &*self.passes {
|
for pass in &*self.passes {
|
||||||
if mask.overlaps(&pass.mask) {
|
if mask.overlaps(&pass.mask) {
|
||||||
dirty_nodes.insert(pass.this_type_id, node);
|
dirty_nodes.insert(pass.this_type_id, node, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for node in std::mem::take(&mut self.child_changed_nodes) {
|
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
|
// remove any nodes that were created and then removed in the same mutations from the dirty nodes list
|
||||||
if self.tree.contains(node) {
|
if let Some(height) = self.tree.height(node) {
|
||||||
for pass in &*self.passes {
|
for pass in &*self.passes {
|
||||||
if pass.child_dependant {
|
if pass.child_dependant {
|
||||||
dirty_nodes.insert(pass.this_type_id, node);
|
dirty_nodes.insert(pass.this_type_id, node, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for node in std::mem::take(&mut self.parent_changed_nodes) {
|
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
|
// remove any nodes that were created and then removed in the same mutations from the dirty nodes list
|
||||||
if self.tree.contains(node) {
|
if let Some(height) = self.tree.height(node) {
|
||||||
for pass in &*self.passes {
|
for pass in &*self.passes {
|
||||||
if pass.parent_dependant {
|
if pass.parent_dependant {
|
||||||
dirty_nodes.insert(pass.this_type_id, node);
|
dirty_nodes.insert(pass.this_type_id, node, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for node in std::mem::take(&mut self.nodes_created) {
|
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
|
// remove any nodes that were created and then removed in the same mutations from the dirty nodes list
|
||||||
if self.tree.contains(node) {
|
if let Some(height) = self.tree.height(node) {
|
||||||
for pass in &*self.passes {
|
for pass in &*self.passes {
|
||||||
dirty_nodes.insert(pass.this_type_id, node);
|
dirty_nodes.insert(pass.this_type_id, node, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let tree = &mut self.tree;
|
(resolve_passes(self, dirty_nodes, ctx), nodes_updated)
|
||||||
|
|
||||||
(
|
|
||||||
resolve_passes(tree, dirty_nodes, passes, ctx),
|
|
||||||
nodes_updated,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: State<V>, V: FromAnyValue> TreeView<Node<S, V>> for RealDom<S, V> {
|
|
||||||
type Iterator<'a> = <Tree<Node<S, V>> as TreeView<Node<S, V>>>::Iterator<'a>;
|
|
||||||
|
|
||||||
fn root(&self) -> NodeId {
|
|
||||||
self.tree.root()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self, id: NodeId) -> Option<&Node<S, V>> {
|
fn remove(&mut self, id: NodeId) {
|
||||||
self.tree.get(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn children(&self, id: NodeId) -> Option<Self::Iterator<'_>> {
|
|
||||||
self.tree.children(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn children_ids(&self, id: NodeId) -> Option<&[NodeId]> {
|
|
||||||
self.tree.children_ids(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent(&self, id: NodeId) -> Option<&Node<S, V>> {
|
|
||||||
self.tree.parent(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_id(&self, id: NodeId) -> Option<NodeId> {
|
|
||||||
self.tree.parent_id(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn height(&self, id: NodeId) -> Option<u16> {
|
|
||||||
self.tree.height(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size(&self) -> usize {
|
|
||||||
self.tree.size()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: State<V>, V: FromAnyValue> TreeLike<Node<S, V>> for RealDom<S, V> {
|
|
||||||
fn create_node(&mut self, node: Node<S, V>) -> NodeId {
|
|
||||||
let id = self.tree.create_node(node);
|
|
||||||
self.tree.get_mut(id).unwrap().node_data.node_id = id;
|
|
||||||
self.nodes_created.insert(id);
|
|
||||||
id
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_child(&mut self, parent: NodeId, child: NodeId) {
|
|
||||||
// mark the parent's children changed
|
|
||||||
self.mark_child_changed(parent);
|
|
||||||
// mark the child's parent changed
|
|
||||||
self.mark_parent_added_or_removed(child);
|
|
||||||
self.tree.add_child(parent, child);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove(&mut self, id: NodeId) -> Option<Node<S, V>> {
|
|
||||||
if let Some(parent_id) = self.tree.parent_id(id) {
|
if let Some(parent_id) = self.tree.parent_id(id) {
|
||||||
self.mark_child_changed(parent_id);
|
self.mark_child_changed(parent_id);
|
||||||
}
|
}
|
||||||
self.tree.remove(id)
|
self.tree.remove(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_all_children(&mut self, id: NodeId) -> Vec<Node<S, V>> {
|
|
||||||
self.mark_child_changed(id);
|
|
||||||
self.tree.remove_all_children(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn replace(&mut self, old: NodeId, new: NodeId) {
|
fn replace(&mut self, old: NodeId, new: NodeId) {
|
||||||
if let Some(parent_id) = self.tree.parent_id(old) {
|
if let Some(parent_id) = self.tree.parent_id(old) {
|
||||||
self.mark_child_changed(parent_id);
|
self.mark_child_changed(parent_id);
|
||||||
@@ -555,68 +487,108 @@ impl<S: State<V>, V: FromAnyValue> TreeLike<Node<S, V>> for RealDom<S, V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: State<V> + Send, V: FromAnyValue> Index<ElementId> for RealDom<S, V> {
|
// impl<V: FromAnyValue> Index<ElementId> for RealDom<V> {
|
||||||
type Output = Node<S, V>;
|
// type Output = Node<V>;
|
||||||
|
|
||||||
fn index(&self, id: ElementId) -> &Self::Output {
|
// fn index(&self, id: ElementId) -> &Self::Output {
|
||||||
self.tree.get(self.element_to_node_id(id)).unwrap()
|
// self.tree.get(self.element_to_node_id(id)).unwrap()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl<V: FromAnyValue> Index<NodeId> for RealDom<V> {
|
||||||
|
// type Output = Node<V>;
|
||||||
|
|
||||||
|
// fn index(&self, idx: NodeId) -> &Self::Output {
|
||||||
|
// self.tree.get(idx).unwrap()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl<V: FromAnyValue> IndexMut<ElementId> for RealDom<V> {
|
||||||
|
// fn index_mut(&mut self, id: ElementId) -> &mut Self::Output {
|
||||||
|
// self.tree.get_mut(self.element_to_node_id(id)).unwrap()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl<V: FromAnyValue> IndexMut<NodeId> for RealDom<V> {
|
||||||
|
// fn index_mut(&mut self, idx: NodeId) -> &mut Self::Output {
|
||||||
|
// self.tree.get_mut(idx).unwrap()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub struct NodeRef<'a, V: FromAnyValue + Send = ()> {
|
||||||
|
id: NodeId,
|
||||||
|
dom: &'a RealDom<V>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, V: FromAnyValue + Send> NodeRef<'a, V> {
|
||||||
|
pub fn node_data(&self) -> &NodeData<V> {
|
||||||
|
self.read().unwrap()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: State<V> + Send, V: FromAnyValue> Index<NodeId> for RealDom<S, V> {
|
|
||||||
type Output = Node<S, V>;
|
|
||||||
|
|
||||||
fn index(&self, idx: NodeId) -> &Self::Output {
|
|
||||||
self.tree.get(idx).unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: State<V> + Send, V: FromAnyValue> IndexMut<ElementId> for RealDom<S, V> {
|
|
||||||
fn index_mut(&mut self, id: ElementId) -> &mut Self::Output {
|
|
||||||
self.tree.get_mut(self.element_to_node_id(id)).unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: State<V> + Send, V: FromAnyValue> IndexMut<NodeId> for RealDom<S, V> {
|
|
||||||
fn index_mut(&mut self, idx: NodeId) -> &mut Self::Output {
|
|
||||||
self.tree.get_mut(idx).unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct NodeMut<'a, V: FromAnyValue = ()> {
|
|
||||||
node: &'a mut NodeData<V>,
|
|
||||||
dirty: NodeMask,
|
|
||||||
nodes_updated: &'a mut FxHashMap<NodeId, NodeMask>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, V: FromAnyValue> NodeMut<'a, V> {
|
|
||||||
pub fn node_type(&self) -> &NodeType<V> {
|
pub fn node_type(&self) -> &NodeType<V> {
|
||||||
&self.node.node_type
|
&self.node_data().node_type
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read<T: Any>(&self) -> Option<&T> {
|
||||||
|
self.dom.tree.read(self.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NodeMut<'a, V: FromAnyValue + Send = ()> {
|
||||||
|
id: NodeId,
|
||||||
|
dom: &'a mut RealDom<V>,
|
||||||
|
dirty: NodeMask,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, V: FromAnyValue + Send> NodeMut<'a, V> {
|
||||||
|
fn node_data(&self) -> &NodeData<V> {
|
||||||
|
self.read().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn node_data_mut(&mut self) -> &mut NodeData<V> {
|
||||||
|
self.dom.tree.write(self.id).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn node_type(&self) -> &NodeType<V> {
|
||||||
|
&self.node_data().node_type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn node_type_mut(&mut self) -> NodeTypeMut<'_, V> {
|
pub fn node_type_mut(&mut self) -> NodeTypeMut<'_, V> {
|
||||||
match &mut self.node.node_type {
|
let Self { id, dom, dirty } = self;
|
||||||
NodeType::Element(element) => NodeTypeMut::Element(ElementNodeMut {
|
let node_type = &mut dom.tree.write::<NodeData<V>>(*id).unwrap().node_type;
|
||||||
element,
|
match node_type {
|
||||||
dirty: &mut self.dirty,
|
NodeType::Element(element) => NodeTypeMut::Element(ElementNodeMut { element, dirty }),
|
||||||
}),
|
|
||||||
NodeType::Text(text) => {
|
NodeType::Text(text) => {
|
||||||
self.dirty.set_text();
|
dirty.set_text();
|
||||||
NodeTypeMut::Text(text)
|
NodeTypeMut::Text(text)
|
||||||
}
|
}
|
||||||
NodeType::Placeholder => NodeTypeMut::Placeholder,
|
NodeType::Placeholder => NodeTypeMut::Placeholder,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_type(&mut self, new: NodeType<V>) {
|
||||||
|
self.node_data_mut().node_type = new;
|
||||||
|
self.dirty = NodeMask::ALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read<T: Any>(&self) -> Option<&T> {
|
||||||
|
self.dom.tree.read(self.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write<T: Any>(&mut self) -> Option<&T> {
|
||||||
|
todo!("get_mut with mark as dirty")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: FromAnyValue> Drop for NodeMut<'_, V> {
|
impl<V: FromAnyValue + Send> Drop for NodeMut<'_, V> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let node_id = self.node.node_id;
|
let node_id = self.node_data().node_id;
|
||||||
let mask = std::mem::take(&mut self.dirty);
|
let mask = std::mem::take(&mut self.dirty);
|
||||||
if let Some(node) = self.nodes_updated.get_mut(&node_id) {
|
let nodes_updated = &mut self.dom.nodes_updated;
|
||||||
|
if let Some(node) = nodes_updated.get_mut(&node_id) {
|
||||||
*node = node.union(&mask);
|
*node = node.union(&mask);
|
||||||
} else {
|
} else {
|
||||||
self.nodes_updated.insert(node_id, mask);
|
nodes_updated.insert(node_id, mask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
node::FromAnyValue,
|
|
||||||
passes::{AnyMapLike, TypeErasedPass},
|
|
||||||
};
|
|
||||||
use std::cmp::Ordering;
|
|
||||||
|
|
||||||
/// Join two sorted iterators
|
|
||||||
pub(crate) fn union_ordered_iter<'a>(
|
|
||||||
s_iter: impl Iterator<Item = &'a str>,
|
|
||||||
o_iter: impl Iterator<Item = &'a str>,
|
|
||||||
new_len_guess: usize,
|
|
||||||
) -> Vec<String> {
|
|
||||||
let mut s_peekable = s_iter.peekable();
|
|
||||||
let mut o_peekable = o_iter.peekable();
|
|
||||||
let mut v = Vec::with_capacity(new_len_guess);
|
|
||||||
while let Some(s_i) = s_peekable.peek() {
|
|
||||||
while let Some(o_i) = o_peekable.peek() {
|
|
||||||
match o_i.cmp(s_i) {
|
|
||||||
Ordering::Greater => {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Ordering::Less => {
|
|
||||||
v.push(o_peekable.next().unwrap().to_string());
|
|
||||||
}
|
|
||||||
Ordering::Equal => {
|
|
||||||
o_peekable.next();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
v.push(s_peekable.next().unwrap().to_string());
|
|
||||||
}
|
|
||||||
for o_i in o_peekable {
|
|
||||||
v.push(o_i.to_string());
|
|
||||||
}
|
|
||||||
for w in v.windows(2) {
|
|
||||||
debug_assert!(w[1] > w[0]);
|
|
||||||
}
|
|
||||||
v
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Do not implement this trait. It is only meant to be derived and used through [crate::real_dom::RealDom].
|
|
||||||
pub trait State<V: FromAnyValue = ()>: Default + Clone + AnyMapLike + 'static {
|
|
||||||
#[doc(hidden)]
|
|
||||||
fn create_passes() -> Box<[TypeErasedPass<Self, V>]>;
|
|
||||||
}
|
|
||||||
+174
-221
@@ -7,17 +7,19 @@ use std::collections::VecDeque;
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::hash::BuildHasherDefault;
|
use std::hash::BuildHasherDefault;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
use crate::{AnyMapLike, Dependancy};
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Hash)]
|
||||||
pub struct NodeId(pub usize);
|
pub struct NodeId(pub usize);
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
pub struct Node {
|
pub(crate) struct Node {
|
||||||
parent: Option<NodeId>,
|
parent: Option<NodeId>,
|
||||||
children: Vec<NodeId>,
|
children: Vec<NodeId>,
|
||||||
height: u16,
|
height: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NodeView<'a> {
|
pub(crate) struct NodeView<'a> {
|
||||||
tree: &'a Tree,
|
tree: &'a Tree,
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
}
|
}
|
||||||
@@ -27,25 +29,21 @@ impl NodeView<'_> {
|
|||||||
where
|
where
|
||||||
T: Any,
|
T: Any,
|
||||||
{
|
{
|
||||||
self.tree.nodes.get_slab_mut::<T>().insert(self.id, data);
|
self.tree.nodes.write_slab::<T>().insert(self.id, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get<T>(&self) -> MappedRwLockReadGuard<'_, T>
|
pub fn get<T>(&self) -> &T
|
||||||
where
|
where
|
||||||
T: Any,
|
T: Any,
|
||||||
{
|
{
|
||||||
MappedRwLockReadGuard::map(self.tree.nodes.get_slab::<T>(), |slab| {
|
self.tree.nodes.read_slab::<T>().get(self.id).unwrap()
|
||||||
slab.get(self.id).unwrap()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut<T>(&self) -> MappedRwLockWriteGuard<'_, T>
|
pub fn get_mut<T>(&self) -> &mut T
|
||||||
where
|
where
|
||||||
T: Any,
|
T: Any,
|
||||||
{
|
{
|
||||||
MappedRwLockWriteGuard::map(self.tree.nodes.get_slab_mut::<T>(), |slab| {
|
self.tree.nodes.write_slab::<T>().get_mut(self.id).unwrap()
|
||||||
slab.get_mut(self.id).unwrap()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn height(&self) -> u16 {
|
pub fn height(&self) -> u16 {
|
||||||
@@ -66,7 +64,7 @@ impl NodeView<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Tree {
|
pub(crate) struct Tree {
|
||||||
nodes: AnySlab,
|
nodes: AnySlab,
|
||||||
root: NodeId,
|
root: NodeId,
|
||||||
}
|
}
|
||||||
@@ -84,20 +82,20 @@ impl Tree {
|
|||||||
Self { nodes, root }
|
Self { nodes, root }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_slab(&self) -> MappedRwLockReadGuard<'_, SlabStorage<Node>> {
|
fn node_slab(&self) -> &SlabStorage<Node> {
|
||||||
self.nodes.get_slab()
|
self.nodes.read_slab()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_node_data(&self, id: NodeId) -> MappedRwLockReadGuard<'_, Node> {
|
pub fn get_node_data(&self, id: NodeId) -> &Node {
|
||||||
MappedRwLockReadGuard::map(self.node_slab(), |slab| slab.get(id).unwrap())
|
self.node_slab().get(id).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_slab_mut(&self) -> MappedRwLockWriteGuard<'_, SlabStorage<Node>> {
|
fn node_slab_mut(&self) -> &mut SlabStorage<Node> {
|
||||||
self.nodes.get_slab_mut()
|
self.nodes.write_slab()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_node_data_mut(&self, id: NodeId) -> MappedRwLockWriteGuard<'_, Node> {
|
pub fn get_node_data_mut(&self, id: NodeId) -> &mut Node {
|
||||||
MappedRwLockWriteGuard::map(self.node_slab_mut(), |slab| slab.get_mut(id).unwrap())
|
self.node_slab_mut().get_mut(id).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove(&mut self, id: NodeId) {
|
pub fn remove(&mut self, id: NodeId) {
|
||||||
@@ -131,7 +129,7 @@ impl Tree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_node(&mut self) -> Entry<'_> {
|
pub fn create_node(&mut self) -> EntryBuilder<'_> {
|
||||||
let mut node = self.nodes.insert();
|
let mut node = self.nodes.insert();
|
||||||
node.insert(Node {
|
node.insert(Node {
|
||||||
parent: None,
|
parent: None,
|
||||||
@@ -206,7 +204,7 @@ impl Tree {
|
|||||||
self.set_height(new_id, height);
|
self.set_height(new_id, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert<T: Any>(&mut self, id: NodeId, value: T) {
|
pub fn insert<T: Any + Send + Sync>(&mut self, id: NodeId, value: T) {
|
||||||
self.nodes.add(id, value);
|
self.nodes.add(id, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,42 +212,60 @@ impl Tree {
|
|||||||
self.nodes.len()
|
self.nodes.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn state_view<T: Any>(&self) -> TreeStateView<'_, T> {
|
pub fn state_views(
|
||||||
|
&self,
|
||||||
|
immutable: impl IntoIterator<Item = TypeId>,
|
||||||
|
mutable: impl IntoIterator<Item = TypeId>,
|
||||||
|
) -> TreeStateView<'_> {
|
||||||
TreeStateView {
|
TreeStateView {
|
||||||
nodes_data: self.node_slab(),
|
nodes_data: self.node_slab(),
|
||||||
nodes: self.nodes.get_slab(),
|
nodes: immutable
|
||||||
|
.into_iter()
|
||||||
|
.map(|id| (id, MaybeRead::Read(self.nodes.data.get(&id).unwrap())))
|
||||||
|
.chain(
|
||||||
|
mutable
|
||||||
|
.into_iter()
|
||||||
|
.map(|id| (id, MaybeRead::Write(self.nodes.data.get_mut(&id).unwrap()))),
|
||||||
|
)
|
||||||
|
.collect(),
|
||||||
root: self.root,
|
root: self.root,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn state_view_mut<T: Any>(&mut self) -> TreeStateViewMut<'_, T> {
|
pub fn read<T: Any>(&self, id: NodeId) -> Option<&T> {
|
||||||
TreeStateViewMut {
|
self.nodes.read_slab().get(id)
|
||||||
nodes_data: self.node_slab(),
|
|
||||||
nodes: self.nodes.get_slab_mut(),
|
|
||||||
root: self.root,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl NodeDataView for Tree {
|
pub fn write<T: Any>(&mut self, id: NodeId) -> Option<&mut T> {
|
||||||
fn root(&self) -> NodeId {
|
self.nodes.write_slab().get_mut(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_node(&self, id: NodeId) -> NodeView<'_> {
|
||||||
|
NodeView { tree: self, id }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn contains(&self, id: NodeId) -> bool {
|
||||||
|
self.nodes.contains(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn root(&self) -> NodeId {
|
||||||
self.root
|
self.root
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parent_id(&self, id: NodeId) -> Option<NodeId> {
|
pub fn parent_id(&self, id: NodeId) -> Option<NodeId> {
|
||||||
self.get_node_data(id).parent
|
self.get_node_data(id).parent
|
||||||
}
|
}
|
||||||
|
|
||||||
fn children_ids(&self, id: NodeId) -> Option<Vec<NodeId>> {
|
pub fn children_ids(&self, id: NodeId) -> Option<Vec<NodeId>> {
|
||||||
Some(self.get_node_data(id).children.clone())
|
Some(self.get_node_data(id).children.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn height(&self, id: NodeId) -> Option<u16> {
|
pub fn height(&self, id: NodeId) -> Option<u16> {
|
||||||
Some(self.get_node_data(id).height)
|
Some(self.get_node_data(id).height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait NodeDataView {
|
pub(crate) trait NodeDataView {
|
||||||
fn root(&self) -> NodeId;
|
fn root(&self) -> NodeId;
|
||||||
|
|
||||||
fn parent_id(&self, id: NodeId) -> Option<NodeId>;
|
fn parent_id(&self, id: NodeId) -> Option<NodeId>;
|
||||||
@@ -259,7 +275,7 @@ pub trait NodeDataView {
|
|||||||
fn height(&self, id: NodeId) -> Option<u16>;
|
fn height(&self, id: NodeId) -> Option<u16>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TreeView<T>: Sized + NodeDataView {
|
trait TreeView<T>: Sized + NodeDataView {
|
||||||
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 {
|
||||||
@@ -298,7 +314,7 @@ pub trait TreeView<T>: Sized + NodeDataView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TreeViewMut<T>: Sized + TreeView<T> {
|
trait TreeViewMut<T>: Sized + TreeView<T> {
|
||||||
fn get_mut(&mut self, id: NodeId) -> Option<&mut T>;
|
fn get_mut(&mut self, id: NodeId) -> Option<&mut T>;
|
||||||
|
|
||||||
unsafe fn get_mut_unchecked(&mut self, id: NodeId) -> &mut T {
|
unsafe fn get_mut_unchecked(&mut self, id: NodeId) -> &mut T {
|
||||||
@@ -357,175 +373,91 @@ pub trait TreeViewMut<T>: Sized + TreeView<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TreeLike {
|
enum MaybeRead<'a> {
|
||||||
fn create_node(&mut self) -> Entry;
|
Read(&'a Box<dyn AnySlabStorageImpl>),
|
||||||
|
Write(&'a mut Box<dyn AnySlabStorageImpl>),
|
||||||
fn add_child(&mut self, parent: NodeId, child: NodeId);
|
|
||||||
|
|
||||||
fn remove(&mut self, id: NodeId);
|
|
||||||
|
|
||||||
fn replace(&mut self, old: NodeId, new: NodeId);
|
|
||||||
|
|
||||||
fn insert_before(&mut self, id: NodeId, new: NodeId);
|
|
||||||
|
|
||||||
fn insert_after(&mut self, id: NodeId, new: NodeId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TreeStateView<'a, T> {
|
#[derive(Clone, Copy)]
|
||||||
nodes_data: MappedRwLockReadGuard<'a, SlabStorage<Node>>,
|
struct TreeStateViewEntry<'a> {
|
||||||
nodes: MappedRwLockReadGuard<'a, SlabStorage<T>>,
|
view: &'a TreeStateView<'a>,
|
||||||
|
id: NodeId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> AnyMapLike<'a> for TreeStateViewEntry<'a> {
|
||||||
|
fn get<T: Any>(self) -> Option<&'a T> {
|
||||||
|
self.view.get_slab().and_then(|slab| slab.get(self.id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TreeStateView<'a> {
|
||||||
|
nodes_data: &'a SlabStorage<Node>,
|
||||||
|
nodes: hashbrown::HashMap<TypeId, MaybeRead<'a>, BuildHasherDefault<FxHasher>>,
|
||||||
root: NodeId,
|
root: NodeId,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TreeStateViewMut<'a, T> {
|
impl<'a> TreeStateView<'a> {
|
||||||
nodes_data: MappedRwLockReadGuard<'a, SlabStorage<Node>>,
|
fn get_slab<T: Any>(&self) -> Option<&SlabStorage<T>> {
|
||||||
nodes: MappedRwLockWriteGuard<'a, SlabStorage<T>>,
|
self.nodes
|
||||||
root: NodeId,
|
.get(&TypeId::of::<T>())
|
||||||
}
|
.and_then(|gaurd| match gaurd {
|
||||||
|
MaybeRead::Read(gaurd) => gaurd.as_any().downcast_ref::<SlabStorage<T>>(),
|
||||||
|
MaybeRead::Write(gaurd) => gaurd.as_any().downcast_ref::<SlabStorage<T>>(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_slab_mut<T: Any>(&mut self) -> Option<&mut SlabStorage<T>> {
|
||||||
|
self.nodes
|
||||||
|
.get_mut(&TypeId::of::<T>())
|
||||||
|
.and_then(|gaurd| match gaurd {
|
||||||
|
MaybeRead::Read(gaurd) => None,
|
||||||
|
MaybeRead::Write(gaurd) => gaurd.as_any_mut().downcast_mut::<SlabStorage<T>>(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, T> NodeDataView for TreeStateView<'a, T> {
|
|
||||||
fn root(&self) -> NodeId {
|
fn root(&self) -> NodeId {
|
||||||
self.root
|
self.root
|
||||||
}
|
}
|
||||||
|
|
||||||
fn children_ids(&self, id: NodeId) -> Option<Vec<NodeId>> {
|
pub fn children_ids(&self, id: NodeId) -> Option<Vec<NodeId>> {
|
||||||
self.nodes_data.get(id).map(|node| node.children.clone())
|
self.nodes_data.get(id).map(|node| node.children.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parent_id(&self, id: NodeId) -> Option<NodeId> {
|
pub fn parent_id(&self, id: NodeId) -> Option<NodeId> {
|
||||||
self.nodes_data.get(id).and_then(|node| node.parent)
|
self.nodes_data.get(id).and_then(|node| node.parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn height(&self, id: NodeId) -> Option<u16> {
|
pub fn height(&self, id: NodeId) -> Option<u16> {
|
||||||
self.nodes_data.get(id).map(|n| n.height)
|
self.nodes_data.get(id).map(|n| n.height)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> TreeView<T> for TreeStateView<'a, T> {
|
pub fn get<T: Dependancy>(&self, id: NodeId) -> Option<T::ElementBorrowed<'_>> {
|
||||||
fn get(&self, id: NodeId) -> Option<&T> {
|
T::borrow_elements_from(self.entry(id))
|
||||||
self.nodes.get(id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn children(&self, id: NodeId) -> Option<Vec<&T>> {
|
pub fn get_single<T: Any>(&self, id: NodeId) -> Option<&T> {
|
||||||
|
self.get_slab().and_then(|slab| slab.get(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mut<T: Any>(&mut self, id: NodeId) -> Option<&mut T> {
|
||||||
|
self.get_slab_mut().and_then(|slab| slab.get_mut(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn entry(&self, id: NodeId) -> TreeStateViewEntry<'_> {
|
||||||
|
TreeStateViewEntry { view: self, id }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn children<T: Dependancy>(&self, id: NodeId) -> Option<Vec<T::ElementBorrowed<'_>>> {
|
||||||
let ids = self.children_ids(id);
|
let ids = self.children_ids(id);
|
||||||
ids.map(|ids| ids.iter().map(|id| self.get_unchecked(*id)).collect())
|
ids.and_then(|ids| {
|
||||||
}
|
ids.iter()
|
||||||
|
.map(|id| T::borrow_elements_from(self.entry(*id)))
|
||||||
fn parent(&self, id: NodeId) -> Option<&T> {
|
.collect()
|
||||||
self.nodes_data
|
|
||||||
.get(id)
|
|
||||||
.and_then(|node| node.parent.map(|id| self.nodes.get(id).unwrap()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_unchecked(&self, id: NodeId) -> &T {
|
|
||||||
unsafe { &self.nodes.get_unchecked(id) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> NodeDataView for TreeStateViewMut<'a, T> {
|
|
||||||
fn root(&self) -> NodeId {
|
|
||||||
self.root
|
|
||||||
}
|
|
||||||
|
|
||||||
fn children_ids(&self, id: NodeId) -> Option<Vec<NodeId>> {
|
|
||||||
self.nodes_data.get(id).map(|node| node.children.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_id(&self, id: NodeId) -> Option<NodeId> {
|
|
||||||
self.nodes_data.get(id).and_then(|node| node.parent)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn height(&self, id: NodeId) -> Option<u16> {
|
|
||||||
self.nodes_data.get(id).map(|n| n.height)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> TreeView<T> for TreeStateViewMut<'a, T> {
|
|
||||||
fn get(&self, id: NodeId) -> Option<&T> {
|
|
||||||
self.nodes.get(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn children(&self, id: NodeId) -> Option<Vec<&T>> {
|
|
||||||
let ids = self.children_ids(id);
|
|
||||||
ids.map(|ids| ids.iter().map(|id| self.get_unchecked(*id)).collect())
|
|
||||||
}
|
|
||||||
fn parent(&self, id: NodeId) -> Option<&T> {
|
|
||||||
self.nodes_data
|
|
||||||
.get(id)
|
|
||||||
.and_then(|node| node.parent.map(|id| self.nodes.get(id).unwrap()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_unchecked(&self, id: NodeId) -> &T {
|
|
||||||
unsafe { &self.nodes.get_unchecked(id) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> TreeViewMut<T> for TreeStateViewMut<'a, T> {
|
|
||||||
fn get_mut(&mut self, id: NodeId) -> Option<&mut T> {
|
|
||||||
self.nodes.get_mut(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_mut(&mut self, id: NodeId) -> Option<&mut T> {
|
|
||||||
let parent_id = self.parent_id(id)?;
|
|
||||||
unsafe { Some(self.get_mut_unchecked(parent_id)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn children_mut(&mut self, id: NodeId) -> Option<Vec<&mut T>> {
|
|
||||||
// Safety: No node has itself as a parent.
|
|
||||||
if let Some(children_ids) = self.children_ids(id) {
|
|
||||||
let children_ids = children_ids.to_vec();
|
|
||||||
unsafe {
|
|
||||||
self.nodes
|
|
||||||
.get_many_mut_unchecked(children_ids.into_iter().rev().map(|id| id))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn get_mut_unchecked(&mut self, id: NodeId) -> &mut T {
|
|
||||||
unsafe { self.nodes.get_unchecked_mut(id) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn node_parent_mut(&mut self, id: NodeId) -> Option<(&mut T, Option<&mut T>)> {
|
|
||||||
if let Some(parent_id) = self.parent_id(id) {
|
|
||||||
self.nodes
|
|
||||||
.get2_mut(id, parent_id)
|
|
||||||
.map(|(node, parent)| (node, Some(parent)))
|
|
||||||
} else {
|
|
||||||
self.nodes.get_mut(id).map(|node| (node, None))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn node_parent_children_mut(
|
|
||||||
&mut self,
|
|
||||||
id: NodeId,
|
|
||||||
) -> Option<(&mut T, Option<&mut T>, Option<Vec<&mut T>>)> {
|
|
||||||
// Safety: No node has itself as a parent.
|
|
||||||
let unbounded_self = unsafe { &mut *(self as *mut Self) };
|
|
||||||
self.node_parent_mut(id).map(move |(node, parent)| {
|
|
||||||
let children = unbounded_self.children_mut(id);
|
|
||||||
(node, parent, children)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parent_child_mut(&mut self, id: NodeId) -> Option<(&mut T, Vec<&mut T>)> {
|
pub fn parent<T: Dependancy>(&self, id: NodeId) -> Option<T::ElementBorrowed<'_>> {
|
||||||
// Safety: No node will appear as a child twice
|
T::borrow_elements_from(self.entry(id))
|
||||||
if let Some(children_ids) = self.children_ids(id) {
|
|
||||||
debug_assert!(!children_ids.iter().any(|child_id| *child_id == id));
|
|
||||||
let mut borrowed = unsafe {
|
|
||||||
let as_vec = children_ids.to_vec();
|
|
||||||
self.nodes
|
|
||||||
.get_many_mut_unchecked(
|
|
||||||
as_vec.into_iter().map(|id| id).chain(std::iter::once(id)),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
};
|
|
||||||
let node = borrowed.pop().unwrap();
|
|
||||||
Some((node, borrowed))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -727,7 +659,7 @@ fn get_node_children_mut() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct SlabStorage<T> {
|
pub(crate) struct SlabStorage<T> {
|
||||||
data: Vec<Option<T>>,
|
data: Vec<Option<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -737,7 +669,7 @@ impl<T> Default for SlabStorage<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait AnySlabStorageImpl: Any {
|
trait AnySlabStorageImpl: Any + Send + Sync {
|
||||||
fn remove(&mut self, id: NodeId);
|
fn remove(&mut self, id: NodeId);
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||||
@@ -806,7 +738,7 @@ impl<T> SlabStorage<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> AnySlabStorageImpl for SlabStorage<T> {
|
impl<T: 'static + Send + Sync> AnySlabStorageImpl for SlabStorage<T> {
|
||||||
fn remove(&mut self, id: NodeId) {
|
fn remove(&mut self, id: NodeId) {
|
||||||
self.data[id.0].take();
|
self.data[id.0].take();
|
||||||
}
|
}
|
||||||
@@ -820,12 +752,9 @@ impl<T: 'static> AnySlabStorageImpl for SlabStorage<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AnySlab {
|
pub(crate) struct AnySlab {
|
||||||
data: hashbrown::HashMap<
|
data: hashbrown::HashMap<TypeId, Box<dyn AnySlabStorageImpl>, BuildHasherDefault<FxHasher>>,
|
||||||
TypeId,
|
filled: Vec<bool>,
|
||||||
RwLock<Box<dyn AnySlabStorageImpl>>,
|
|
||||||
BuildHasherDefault<FxHasher>,
|
|
||||||
>,
|
|
||||||
free: VecDeque<NodeId>,
|
free: VecDeque<NodeId>,
|
||||||
len: usize,
|
len: usize,
|
||||||
}
|
}
|
||||||
@@ -850,80 +779,104 @@ impl AnySlab {
|
|||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
data: Default::default(),
|
data: Default::default(),
|
||||||
|
filled: Default::default(),
|
||||||
free: VecDeque::new(),
|
free: VecDeque::new(),
|
||||||
len: 0,
|
len: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_get_slab<T: Any>(&self) -> Option<MappedRwLockReadGuard<'_, SlabStorage<T>>> {
|
fn try_read_slab<T: Any>(&self) -> Option<&SlabStorage<T>> {
|
||||||
self.data
|
self.data
|
||||||
.get(&TypeId::of::<T>())
|
.get(&TypeId::of::<T>())
|
||||||
.map(|x| RwLockReadGuard::map(x.read(), |x| x.as_any().downcast_ref().unwrap()))
|
.map(|x| x.as_any().downcast_ref().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_slab<T: Any>(&self) -> MappedRwLockReadGuard<'_, SlabStorage<T>> {
|
fn read_slab<T: Any>(&self) -> &SlabStorage<T> {
|
||||||
self.try_get_slab().unwrap()
|
self.try_read_slab().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_get_slab_mut<T: Any>(&self) -> Option<MappedRwLockWriteGuard<'_, SlabStorage<T>>> {
|
fn try_write_slab<T: Any>(&self) -> Option<&mut SlabStorage<T>> {
|
||||||
self.data
|
self.data
|
||||||
.get(&TypeId::of::<T>())
|
.get(&TypeId::of::<T>())
|
||||||
.map(|x| RwLockWriteGuard::map(x.write(), |x| x.as_any_mut().downcast_mut().unwrap()))
|
.map(|x| x.as_any_mut().downcast_mut().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_slab_mut<T: Any>(&self) -> MappedRwLockWriteGuard<'_, SlabStorage<T>> {
|
fn write_slab<T: Any>(&self) -> &mut SlabStorage<T> {
|
||||||
self.try_get_slab_mut().unwrap()
|
self.try_write_slab().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_or_insert_slab_mut<T: Any>(&mut self) -> MappedRwLockWriteGuard<'_, SlabStorage<T>> {
|
fn get_slab_mut_borrow<T: Any>(&mut self) -> &mut SlabStorage<T> {
|
||||||
RwLockWriteGuard::map(
|
self.data
|
||||||
self.data
|
.get_mut(&TypeId::of::<T>())
|
||||||
.entry(TypeId::of::<T>())
|
.unwrap()
|
||||||
.or_insert_with(|| RwLock::new(Box::new(SlabStorage::<T>::default())))
|
.as_any_mut()
|
||||||
.write(),
|
.downcast_mut()
|
||||||
|x| x.as_any_mut().downcast_mut().unwrap(),
|
.unwrap()
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert(&mut self) -> Entry<'_> {
|
fn get_or_insert_slab_mut<T: Any + Send + Sync>(&mut self) -> &mut SlabStorage<T> {
|
||||||
|
self.data
|
||||||
|
.entry(TypeId::of::<T>())
|
||||||
|
.or_insert_with(|| Box::new(SlabStorage::<T>::default()))
|
||||||
|
.as_any_mut()
|
||||||
|
.downcast_mut()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert(&mut self) -> EntryBuilder<'_> {
|
||||||
let id = if let Some(id) = self.free.pop_front() {
|
let id = if let Some(id) = self.free.pop_front() {
|
||||||
|
self.filled[id.0] = true;
|
||||||
id
|
id
|
||||||
} else {
|
} else {
|
||||||
let id = self.len;
|
let id = self.len;
|
||||||
|
self.filled.push(true);
|
||||||
self.len += 1;
|
self.len += 1;
|
||||||
NodeId(id)
|
NodeId(id)
|
||||||
};
|
};
|
||||||
Entry { id, inner: self }
|
EntryBuilder { id, inner: self }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add<T: Any>(&mut self, id: NodeId, value: T) {
|
fn add<T: Any + Send + Sync>(&mut self, id: NodeId, value: T) {
|
||||||
self.get_or_insert_slab_mut().insert(id, value);
|
self.get_or_insert_slab_mut().insert(id, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove(&mut self, id: NodeId) {
|
fn remove(&mut self, id: NodeId) {
|
||||||
for slab in self.data.values_mut() {
|
for slab in self.data.values_mut() {
|
||||||
slab.write().remove(id);
|
slab.remove(id);
|
||||||
}
|
}
|
||||||
|
self.filled[id.0] = true;
|
||||||
self.free.push_back(id);
|
self.free.push_back(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
self.len - self.free.len()
|
self.len - self.free.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn contains(&self, id: NodeId) -> bool {
|
||||||
|
self.filled.get(id.0).copied().unwrap_or_default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Entry<'a> {
|
pub struct EntryBuilder<'a> {
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
inner: &'a mut AnySlab,
|
inner: &'a mut AnySlab,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Entry<'_> {
|
impl EntryBuilder<'_> {
|
||||||
pub fn insert<T: Any>(&mut self, value: T) {
|
pub fn insert<T: Any + Send + Sync>(&mut self, value: T) {
|
||||||
self.inner
|
self.inner
|
||||||
.get_or_insert_slab_mut::<T>()
|
.get_or_insert_slab_mut::<T>()
|
||||||
.insert(self.id, value);
|
.insert(self.id, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get<T: Any>(&self) -> Option<&T> {
|
||||||
|
self.inner.read_slab().get(self.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mut<T: Any>(&mut self) -> Option<&mut T> {
|
||||||
|
self.inner.write_slab().get_mut(self.id)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn remove(self) {
|
pub fn remove(self) {
|
||||||
self.inner.remove(self.id);
|
self.inner.remove(self.id);
|
||||||
}
|
}
|
||||||
@@ -946,7 +899,7 @@ fn remove() {
|
|||||||
|
|
||||||
slab.remove(node1_id);
|
slab.remove(node1_id);
|
||||||
|
|
||||||
assert!(slab.get_slab::<i32>().get(node1_id).is_none());
|
assert!(slab.read_slab::<i32>().get(node1_id).is_none());
|
||||||
assert_eq!(slab.len(), 1);
|
assert_eq!(slab.len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -966,7 +919,7 @@ fn get_many_mut_unchecked() {
|
|||||||
println!("ids: {:#?}", [parent, child, grandchild]);
|
println!("ids: {:#?}", [parent, child, grandchild]);
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut i32_slab = slab.get_slab_mut::<i32>();
|
let mut i32_slab = slab.write_slab::<i32>();
|
||||||
let all =
|
let all =
|
||||||
unsafe { i32_slab.get_many_mut_unchecked([parent, child, grandchild].into_iter()) }
|
unsafe { i32_slab.get_many_mut_unchecked([parent, child, grandchild].into_iter()) }
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -974,7 +927,7 @@ fn get_many_mut_unchecked() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut i32_slab = slab.get_slab_mut::<i32>();
|
let mut i32_slab = slab.write_slab::<i32>();
|
||||||
assert!(
|
assert!(
|
||||||
unsafe { i32_slab.get_many_mut_unchecked([NodeId(3), NodeId(100)].into_iter()) }
|
unsafe { i32_slab.get_many_mut_unchecked([NodeId(3), NodeId(100)].into_iter()) }
|
||||||
.is_none()
|
.is_none()
|
||||||
@@ -1001,8 +954,8 @@ fn get_many_many_mut_unchecked() {
|
|||||||
|
|
||||||
println!("slab: {:#?}", slab);
|
println!("slab: {:#?}", slab);
|
||||||
|
|
||||||
let mut num_entries = slab.get_slab_mut::<i32>();
|
let mut num_entries = slab.write_slab::<i32>();
|
||||||
let mut str_entries = slab.get_slab_mut::<&str>();
|
let mut str_entries = slab.write_slab::<&str>();
|
||||||
|
|
||||||
let all_num = unsafe {
|
let all_num = unsafe {
|
||||||
num_entries
|
num_entries
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
mod persistant_iterator;
|
// mod persistant_iterator;
|
||||||
pub use persistant_iterator::*;
|
// pub use persistant_iterator::*;
|
||||||
pub mod cursor;
|
pub mod cursor;
|
||||||
@@ -2,8 +2,6 @@ use crate::{
|
|||||||
node::{ElementNode, FromAnyValue, NodeType},
|
node::{ElementNode, FromAnyValue, NodeType},
|
||||||
passes::{AnyMapLike, TypeErasedPass},
|
passes::{AnyMapLike, TypeErasedPass},
|
||||||
real_dom::RealDom,
|
real_dom::RealDom,
|
||||||
state::State,
|
|
||||||
tree::TreeView,
|
|
||||||
NodeId,
|
NodeId,
|
||||||
};
|
};
|
||||||
use dioxus_core::{Mutation, Mutations};
|
use dioxus_core::{Mutation, Mutations};
|
||||||
|
|||||||
Reference in new issue
Block a user