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"
|
||||
anymap = "1.0.0-beta.2"
|
||||
slab = "0.4"
|
||||
parking_lot = "0.12.1"
|
||||
parking_lot = { version = "0.12.1", features = ["send_guard"] }
|
||||
crossbeam-deque = "0.8.2"
|
||||
dashmap = "5.4.0"
|
||||
hashbrown = { version = "0.13.2", features = ["raw"] }
|
||||
|
||||
@@ -5,7 +5,6 @@ pub use node_ref::NodeMask;
|
||||
pub use passes::AnyMapLike;
|
||||
pub use passes::{Dependancy, Pass, TypeErasedPass};
|
||||
use rustc_hash::FxHasher;
|
||||
pub use state::State;
|
||||
pub use tree::NodeId;
|
||||
|
||||
pub mod layout_attributes;
|
||||
@@ -13,7 +12,6 @@ pub mod node;
|
||||
pub mod node_ref;
|
||||
mod passes;
|
||||
pub mod real_dom;
|
||||
pub mod state;
|
||||
pub mod tree;
|
||||
pub mod utils;
|
||||
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
use crate::{state::State, tree::NodeId};
|
||||
use crate::tree::NodeId;
|
||||
use dioxus_core::{AnyValue, BorrowedAttributeValue, ElementId};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
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)]
|
||||
pub struct NodeData<V: FromAnyValue = ()> {
|
||||
/// The id of the node
|
||||
@@ -38,21 +29,18 @@ pub enum NodeType<V: FromAnyValue = ()> {
|
||||
Placeholder,
|
||||
}
|
||||
|
||||
impl<S: State<V>, V: FromAnyValue> Node<S, V> {
|
||||
impl<V: FromAnyValue> NodeData<V> {
|
||||
pub(crate) fn new(node_type: NodeType<V>) -> Self {
|
||||
Node {
|
||||
state: S::default(),
|
||||
node_data: NodeData {
|
||||
element_id: None,
|
||||
node_type,
|
||||
node_id: NodeId(0),
|
||||
},
|
||||
NodeData {
|
||||
element_id: None,
|
||||
node_type,
|
||||
node_id: NodeId(0),
|
||||
}
|
||||
}
|
||||
|
||||
/// get the mounted id of the node
|
||||
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 crate::{
|
||||
node::{ElementNode, FromAnyValue, NodeData, NodeType, OwnedAttributeView},
|
||||
state::union_ordered_iter,
|
||||
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.
|
||||
#[derive(Debug)]
|
||||
pub struct NodeView<'a, V: FromAnyValue = ()> {
|
||||
|
||||
+173
-193
@@ -1,18 +1,115 @@
|
||||
use anymap::AnyMap;
|
||||
use parking_lot::RwLock;
|
||||
use rustc_hash::FxHashSet;
|
||||
use std::any::{Any, TypeId};
|
||||
use std::any::{self, Any, TypeId};
|
||||
use std::collections::BTreeMap;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::node::{FromAnyValue, Node};
|
||||
use crate::node::{FromAnyValue, NodeData};
|
||||
use crate::node_ref::NodeView;
|
||||
use crate::state::State;
|
||||
use crate::tree::TreeViewMut;
|
||||
use crate::tree::{Tree, TreeView};
|
||||
use crate::real_dom::RealDom;
|
||||
use crate::tree::{Node, TreeStateView};
|
||||
use crate::{FxDashMap, FxDashSet, SendAnyMap};
|
||||
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, ..)
|
||||
type ParentDependencies: Dependancy;
|
||||
/// This is a tuple of (T: Any, ..)
|
||||
@@ -26,23 +123,21 @@ pub trait Pass<V: FromAnyValue = ()>: Any {
|
||||
node_view: NodeView<V>,
|
||||
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>>,
|
||||
>,
|
||||
children: Option<Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>>,
|
||||
context: &SendAnyMap,
|
||||
) -> bool;
|
||||
|
||||
fn validate() {
|
||||
// no type can be a child and parent dependency
|
||||
for type_id in Self::parent_type_ids() {
|
||||
for type_id2 in Self::child_type_ids() {
|
||||
for type_id in Self::parent_type_ids().into_iter().copied() {
|
||||
for type_id2 in Self::child_type_ids().into_iter().copied() {
|
||||
if type_id == type_id2 {
|
||||
panic!("type cannot be both a parent and child dependency");
|
||||
}
|
||||
}
|
||||
}
|
||||
// this type should not be a node dependency
|
||||
for type_id in Self::node_type_ids() {
|
||||
for type_id in Self::node_type_ids().into_iter().copied() {
|
||||
if type_id == TypeId::of::<Self>() {
|
||||
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
|
||||
Self: Sized,
|
||||
{
|
||||
Self::validate();
|
||||
TypeErasedPass {
|
||||
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(),
|
||||
child_dependant: !Self::child_type_ids().is_empty(),
|
||||
dependants: FxHashSet::default(),
|
||||
mask: Self::NODE_MASK,
|
||||
pass_direction: Self::pass_direction(),
|
||||
pass: Box::new(
|
||||
|node_id: NodeId, any_map: &mut Tree<Node<T, V>>, 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, V>;
|
||||
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")
|
||||
};
|
||||
|node_id: NodeId, tree: &mut TreeStateView, context: &SendAnyMap| {
|
||||
debug_assert!(!Self::NodeDependencies::type_ids()
|
||||
.into_iter()
|
||||
.any(|id| *id == TypeId::of::<Self>()));
|
||||
// get all of the states from the tree view
|
||||
// Safety: No node has itself as a parent or child.
|
||||
let node_raw = tree.get_mut::<Self>(node_id).unwrap() as *mut Self;
|
||||
let node_data = tree.get_single::<NodeData<V>>(node_id).unwrap();
|
||||
let node = tree.get::<Self::NodeDependencies>(node_id).unwrap();
|
||||
let children = tree.children::<Self::ChildDependencies>(node_id);
|
||||
let parent = tree.parent::<Self::ParentDependencies>(node_id);
|
||||
let myself = unsafe { &mut *node_raw };
|
||||
|
||||
myself.pass(
|
||||
NodeView::new(¤t_node.node_data, Self::NODE_MASK),
|
||||
NodeView::new(&node_data, Self::NODE_MASK),
|
||||
node,
|
||||
parent,
|
||||
children,
|
||||
context,
|
||||
)
|
||||
},
|
||||
)
|
||||
as Box<dyn Fn(NodeId, &mut Tree<Node<T, V>>, &SendAnyMap) -> bool + Send + Sync>,
|
||||
) as PassCallback,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_type_ids() -> Vec<TypeId> {
|
||||
fn parent_type_ids() -> Box<[TypeId]> {
|
||||
Self::ParentDependencies::type_ids()
|
||||
}
|
||||
|
||||
fn child_type_ids() -> Vec<TypeId> {
|
||||
fn child_type_ids() -> Box<[TypeId]> {
|
||||
Self::ChildDependencies::type_ids()
|
||||
}
|
||||
|
||||
fn node_type_ids() -> Vec<TypeId> {
|
||||
fn node_type_ids() -> Box<[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 all_dependanices() -> Box<[TypeId]> {
|
||||
let mut dependencies = Self::parent_type_ids().to_vec();
|
||||
dependencies.extend(Self::child_type_ids().into_iter());
|
||||
dependencies.extend(Self::node_type_ids().into_iter());
|
||||
dependencies.into_boxed_slice()
|
||||
}
|
||||
|
||||
fn pass_direction() -> PassDirection {
|
||||
if Self::child_type_ids()
|
||||
.into_iter()
|
||||
.any(|type_id| type_id == TypeId::of::<Self>())
|
||||
.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>())
|
||||
.any(|type_id| *type_id == TypeId::of::<Self>())
|
||||
{
|
||||
PassDirection::ParentToChild
|
||||
} 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) parent_dependant: bool,
|
||||
pub(crate) child_dependant: bool,
|
||||
pub(crate) combined_dependancy_type_ids: FxHashSet<TypeId>,
|
||||
pub(crate) dependants: FxHashSet<TypeId>,
|
||||
pub(crate) mask: NodeMask,
|
||||
pass: PassCallback<T, V>,
|
||||
pass: PassCallback,
|
||||
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(
|
||||
&self,
|
||||
tree: &mut Tree<Node<T, V>>,
|
||||
mut dirty: DirtyNodes,
|
||||
dirty_states: &DirtyNodeStates,
|
||||
mut tree: TreeStateView,
|
||||
dirty: &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) {
|
||||
while let Some((height, id)) = dirty.pop_front(self.this_type_id) {
|
||||
if (self.pass)(id, &mut tree, ctx) {
|
||||
nodes_updated.insert(id);
|
||||
for id in tree.children_ids(id).unwrap() {
|
||||
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 => {
|
||||
while let Some(id) = dirty.pop_back() {
|
||||
if (self.pass)(id, tree, ctx) {
|
||||
while let Some((height, id)) = dirty.pop_back(self.this_type_id) {
|
||||
if (self.pass)(id, &mut tree, ctx) {
|
||||
nodes_updated.insert(id);
|
||||
if let Some(id) = tree.parent_id(id) {
|
||||
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 => {
|
||||
while let Some(id) = dirty.pop_back() {
|
||||
if (self.pass)(id, tree, ctx) {
|
||||
while let Some((height, id)) = dirty.pop_back(self.this_type_id) {
|
||||
if (self.pass)(id, &mut tree, ctx) {
|
||||
nodes_updated.insert(id);
|
||||
for dependant in &self.dependants {
|
||||
dirty_states.insert(*dependant, id);
|
||||
dirty.insert(*dependant, id, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,30 +295,20 @@ pub enum PassDirection {
|
||||
AnyOrder,
|
||||
}
|
||||
|
||||
type PassCallback<T, V> =
|
||||
Box<dyn Fn(NodeId, &mut Tree<Node<T, V>>, &SendAnyMap) -> bool + Send + Sync>;
|
||||
type PassCallback = Box<dyn Fn(NodeId, &mut TreeStateView, &SendAnyMap) -> bool + Send + Sync>;
|
||||
|
||||
pub trait AnyMapLike {
|
||||
fn get<T: Any>(&self) -> Option<&T>;
|
||||
fn get_mut<T: Any>(&mut self) -> Option<&mut T>;
|
||||
pub trait AnyMapLike<'a> {
|
||||
fn get<T: Any>(self) -> Option<&'a T>;
|
||||
}
|
||||
|
||||
impl AnyMapLike for AnyMap {
|
||||
fn get<T: Any>(&self) -> Option<&T> {
|
||||
impl<'a> AnyMapLike<'a> for &'a AnyMap {
|
||||
fn get<T: Any>(self) -> Option<&'a 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> {
|
||||
impl<'a> AnyMapLike<'a> for &'a SendAnyMap {
|
||||
fn get<T: Any>(self) -> Option<&'a T> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
@@ -250,8 +318,10 @@ pub trait Dependancy {
|
||||
where
|
||||
Self: 'a;
|
||||
|
||||
fn borrow_elements_from<T: AnyMapLike>(map: &T) -> Option<Self::ElementBorrowed<'_>>;
|
||||
fn type_ids() -> Vec<TypeId>;
|
||||
fn borrow_elements_from<'a, T: AnyMapLike<'a> + Copy>(
|
||||
map: T,
|
||||
) -> Option<Self::ElementBorrowed<'a>>;
|
||||
fn type_ids() -> Box<[TypeId]>;
|
||||
}
|
||||
|
||||
macro_rules! impl_dependancy {
|
||||
@@ -260,12 +330,12 @@ macro_rules! impl_dependancy {
|
||||
type ElementBorrowed<'a> = ($(&'a $t,)*) where Self: 'a;
|
||||
|
||||
#[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>()?,)*))
|
||||
}
|
||||
|
||||
fn type_ids() -> Vec<TypeId> {
|
||||
vec![$(TypeId::of::<$t>()),*]
|
||||
fn type_ids() -> Box<[TypeId]> {
|
||||
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, P);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct DirtyNodes {
|
||||
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>>,
|
||||
pub fn resolve_passes<V: FromAnyValue + Send + Sync>(
|
||||
tree: &mut RealDom<V>,
|
||||
dirty_nodes: DirtyNodeStates,
|
||||
passes: &[TypeErasedPass<T, V>],
|
||||
ctx: SendAnyMap,
|
||||
) -> FxDashSet<NodeId> {
|
||||
let dirty_states = Arc::new(dirty_nodes);
|
||||
let passes = &tree.passes;
|
||||
let mut resolved_passes: FxHashSet<TypeId> = FxHashSet::default();
|
||||
let mut resolving = Vec::new();
|
||||
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);
|
||||
resolving.push(pass_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_unbounded_mut = unsafe { &mut *(tree as *mut _) };
|
||||
let dirty_states = dirty_states.clone();
|
||||
let tree_view = tree.tree.state_views(
|
||||
[pass.this_type_id],
|
||||
pass.combined_dependancy_type_ids.iter().copied(),
|
||||
);
|
||||
let dirty_nodes = dirty_nodes.clone();
|
||||
let nodes_updated = nodes_updated.clone();
|
||||
let ctx = ctx.clone();
|
||||
s.spawn(move || {
|
||||
let mut dirty = DirtyNodes::default();
|
||||
dirty_states.all_dirty(pass_id, &mut dirty, tree_unbounded_mut);
|
||||
pass.resolve(
|
||||
tree_unbounded_mut,
|
||||
dirty,
|
||||
&dirty_states,
|
||||
&nodes_updated,
|
||||
&ctx,
|
||||
);
|
||||
pass.resolve(tree_view, &dirty_nodes, &nodes_updated, &ctx);
|
||||
});
|
||||
} else {
|
||||
i += 1;
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
use dioxus_core::{BorrowedAttributeValue, ElementId, Mutations, TemplateNode};
|
||||
use parking_lot::{MappedRwLockReadGuard, MappedRwLockWriteGuard};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::any::Any;
|
||||
|
||||
use crate::node::{
|
||||
ElementNode, FromAnyValue, Node, NodeData, NodeType, OwnedAttributeDiscription,
|
||||
OwnedAttributeValue,
|
||||
ElementNode, FromAnyValue, NodeData, NodeType, OwnedAttributeDiscription, OwnedAttributeValue,
|
||||
};
|
||||
use crate::node_ref::{AttributeMask, NodeMask};
|
||||
use crate::passes::{resolve_passes, DirtyNodeStates, TypeErasedPass};
|
||||
use crate::state::State;
|
||||
use crate::tree::{NodeId, Tree, TreeLike, TreeView, TreeViewMut};
|
||||
use crate::tree::{EntryBuilder, NodeId, Tree};
|
||||
use crate::{FxDashSet, SendAnyMap};
|
||||
|
||||
/// 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
|
||||
/// 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 = ()> {
|
||||
tree: Tree<Node<S, V>>,
|
||||
pub struct RealDom<V: FromAnyValue + Send = ()> {
|
||||
pub(crate) tree: Tree,
|
||||
/// a map from element id to real node id
|
||||
node_id_mapping: Vec<Option<NodeId>>,
|
||||
nodes_listening: FxHashMap<String, FxHashSet<NodeId>>,
|
||||
stack: 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>,
|
||||
passes_updated: DirtyNodeStates,
|
||||
parent_changed_nodes: FxHashSet<NodeId>,
|
||||
child_changed_nodes: FxHashSet<NodeId>,
|
||||
nodes_created: FxHashSet<NodeId>,
|
||||
phantom: std::marker::PhantomData<V>,
|
||||
}
|
||||
|
||||
impl<S: State<V>, V: FromAnyValue> Default for RealDom<S, V> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: State<V>, V: FromAnyValue> RealDom<S, V> {
|
||||
pub fn new() -> RealDom<S, V> {
|
||||
let mut root = Node::new(NodeType::Element(ElementNode {
|
||||
impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
||||
pub fn new(mut passes: Box<[TypeErasedPass<V>]>) -> RealDom<V> {
|
||||
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 {
|
||||
tag: "Root".to_string(),
|
||||
namespace: Some("Root".to_string()),
|
||||
attributes: FxHashMap::default(),
|
||||
listeners: FxHashSet::default(),
|
||||
}));
|
||||
root.node_data.element_id = Some(ElementId(0));
|
||||
let mut tree = Tree::new(root);
|
||||
let root_id = tree.root();
|
||||
tree.get_mut(root_id).unwrap().node_data.node_id = root_id;
|
||||
|
||||
let mut passes = S::create_passes();
|
||||
root_node.element_id = Some(ElementId(0));
|
||||
root_node.node_id = root_id;
|
||||
root.insert(root_node);
|
||||
|
||||
// resolve dependants for each pass
|
||||
for i in 1..passes.len() {
|
||||
@@ -83,6 +77,7 @@ impl<S: State<V>, V: FromAnyValue> RealDom<S, V> {
|
||||
parent_changed_nodes: FxHashSet::default(),
|
||||
child_changed_nodes: 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) {
|
||||
let node = self.tree.get_mut(node_id).unwrap();
|
||||
let node_id = node.node_data.node_id;
|
||||
node.node_data.element_id = Some(element_id);
|
||||
let mut node = self.tree.write::<NodeData>(node_id).unwrap();
|
||||
let node_id = node.node_id;
|
||||
node.element_id = Some(element_id);
|
||||
if self.node_id_mapping.len() <= element_id.0 {
|
||||
self.node_id_mapping.resize(element_id.0 + 1, None);
|
||||
}
|
||||
@@ -124,14 +119,21 @@ impl<S: State<V>, V: FromAnyValue> RealDom<S, V> {
|
||||
current
|
||||
}
|
||||
|
||||
fn create_node(&mut self, node: Node<S, V>, mark_dirty: bool) -> NodeId {
|
||||
let node_id = self.tree.create_node(node);
|
||||
let node = self.tree.get_mut(node_id).unwrap();
|
||||
node.node_data.node_id = node_id;
|
||||
fn create_node(
|
||||
&mut self,
|
||||
mut node: NodeData<V>,
|
||||
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 {
|
||||
self.nodes_created.insert(node_id);
|
||||
}
|
||||
node_id
|
||||
node_entry
|
||||
}
|
||||
|
||||
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,
|
||||
children,
|
||||
} => {
|
||||
let node = Node::new(NodeType::Element(ElementNode {
|
||||
let node = NodeData::new(NodeType::Element(ElementNode {
|
||||
tag: tag.to_string(),
|
||||
namespace: namespace.map(|s| s.to_string()),
|
||||
attributes: attrs
|
||||
@@ -169,22 +171,22 @@ impl<S: State<V>, V: FromAnyValue> RealDom<S, V> {
|
||||
.collect(),
|
||||
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 {
|
||||
let child_id = self.create_template_node(child);
|
||||
self.add_child(node_id, child_id);
|
||||
}
|
||||
node_id
|
||||
}
|
||||
TemplateNode::Text { text } => {
|
||||
self.create_node(Node::new(NodeType::Text(text.to_string())), true)
|
||||
}
|
||||
TemplateNode::Dynamic { .. } => {
|
||||
self.create_node(Node::new(NodeType::Placeholder), true)
|
||||
}
|
||||
TemplateNode::DynamicText { .. } => {
|
||||
self.create_node(Node::new(NodeType::Text(String::new())), true)
|
||||
}
|
||||
TemplateNode::Text { text } => self
|
||||
.create_node(NodeData::new(NodeType::Text(text.to_string())), None, true)
|
||||
.id(),
|
||||
TemplateNode::Dynamic { .. } => self
|
||||
.create_node(NodeData::new(NodeType::Placeholder), None, true)
|
||||
.id(),
|
||||
TemplateNode::DynamicText { .. } => self
|
||||
.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);
|
||||
}
|
||||
CreatePlaceholder { id } => {
|
||||
let node = Node::new(NodeType::Placeholder);
|
||||
let node_id = self.create_node(node, true);
|
||||
let node = NodeData::new(NodeType::Placeholder);
|
||||
let node_id = self.create_node(node, None, true).id();
|
||||
self.set_element_id(node_id, id);
|
||||
self.stack.push(node_id);
|
||||
}
|
||||
CreateTextNode { value, id } => {
|
||||
let node = Node::new(NodeType::Text(value.to_string()));
|
||||
let node_id = self.create_node(node, true);
|
||||
let node = self.tree.get_mut(node_id).unwrap();
|
||||
node.node_data.element_id = Some(id);
|
||||
let node_data = NodeData::new(NodeType::Text(value.to_string()));
|
||||
let node_id = self.create_node(node_data, None, true).id();
|
||||
self.set_element_id(node_id, id);
|
||||
self.stack.push(node_id);
|
||||
}
|
||||
HydrateText { path, value, id } => {
|
||||
let node_id = self.load_child(path);
|
||||
self.set_element_id(node_id, id);
|
||||
let node = self.tree.get_mut(node_id).unwrap();
|
||||
if let NodeType::Text(text) = &mut node.node_data.node_type {
|
||||
let mut node = self.get_mut(node_id).unwrap();
|
||||
if let NodeTypeMut::Text(text) = node.node_type_mut() {
|
||||
*text = value.to_string();
|
||||
} 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 } => {
|
||||
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.
|
||||
/// 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) {
|
||||
let mut listening: Vec<_> = nodes.iter().map(|id| self.get(*id).unwrap()).collect();
|
||||
listening.sort_by(|n1, n2| {
|
||||
(self.tree.height(n1.node_data.node_id))
|
||||
.cmp(&self.tree.height(n2.node_data.node_id))
|
||||
.reverse()
|
||||
});
|
||||
listening
|
||||
let mut listening: Vec<_> = nodes
|
||||
.iter()
|
||||
.map(|id| (*id, self.tree.height(*id).unwrap()))
|
||||
.collect();
|
||||
listening.sort_by(|(_, h1), (_, h2)| h1.cmp(h2).reverse());
|
||||
listening.into_iter().map(|(id, _)| id).collect()
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
@@ -376,160 +374,94 @@ impl<S: State<V>, V: FromAnyValue> RealDom<S, V> {
|
||||
}
|
||||
|
||||
fn clone_node(&mut self, node_id: NodeId) -> NodeId {
|
||||
let node = self.tree.get(node_id).unwrap();
|
||||
let new_node = Node {
|
||||
state: node.state.clone(),
|
||||
node_data: node.node_data.clone(),
|
||||
};
|
||||
let new_id = self.create_node(new_node, true);
|
||||
let node = self.get(node_id).unwrap();
|
||||
let new_node = node.node_data().clone();
|
||||
let new_id = self.create_node(new_node, None, true).id();
|
||||
|
||||
let self_ptr = self as *mut Self;
|
||||
for child in self.tree.children_ids(node_id).unwrap() {
|
||||
unsafe {
|
||||
// this is safe because no node has itself as a child
|
||||
let self_mut = &mut *self_ptr;
|
||||
let child_id = self_mut.clone_node(*child);
|
||||
self_mut.add_child(new_id, child_id);
|
||||
}
|
||||
let child_id = self.clone_node(child);
|
||||
self.add_child(new_id, child_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>> {
|
||||
self.tree.get_mut(id).map(|node| NodeMut {
|
||||
node: &mut node.node_data,
|
||||
self.tree.contains(id).then(|| NodeMut {
|
||||
id,
|
||||
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.
|
||||
pub fn get_mut_raw(&mut self, id: NodeId) -> Option<&mut Node<S, V>> {
|
||||
self.tree.get_mut(id)
|
||||
pub fn get_mut_raw(&mut self, id: NodeId) -> Option<&mut NodeData<V>> {
|
||||
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.
|
||||
pub fn update_state(
|
||||
&mut self,
|
||||
ctx: SendAnyMap,
|
||||
) -> (FxDashSet<NodeId>, FxHashMap<NodeId, NodeMask>) {
|
||||
let passes = &self.passes;
|
||||
let dirty_nodes = std::mem::take(&mut self.passes_updated);
|
||||
let nodes_updated = std::mem::take(&mut self.nodes_updated);
|
||||
for (&node, mask) in &nodes_updated {
|
||||
// remove any nodes that were created and then removed in the same mutations from the dirty nodes list
|
||||
if self.tree.contains(node) {
|
||||
if let Some(height) = self.tree.height(node) {
|
||||
for pass in &*self.passes {
|
||||
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) {
|
||||
// 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 {
|
||||
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) {
|
||||
// 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 {
|
||||
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) {
|
||||
// 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 {
|
||||
dirty_nodes.insert(pass.this_type_id, node);
|
||||
dirty_nodes.insert(pass.this_type_id, node, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let tree = &mut self.tree;
|
||||
|
||||
(
|
||||
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()
|
||||
(resolve_passes(self, dirty_nodes, ctx), nodes_updated)
|
||||
}
|
||||
|
||||
fn get(&self, id: NodeId) -> Option<&Node<S, V>> {
|
||||
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>> {
|
||||
fn remove(&mut self, id: NodeId) {
|
||||
if let Some(parent_id) = self.tree.parent_id(id) {
|
||||
self.mark_child_changed(parent_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) {
|
||||
if let Some(parent_id) = self.tree.parent_id(old) {
|
||||
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> {
|
||||
type Output = Node<S, V>;
|
||||
// impl<V: FromAnyValue> Index<ElementId> for RealDom<V> {
|
||||
// type Output = Node<V>;
|
||||
|
||||
fn index(&self, id: ElementId) -> &Self::Output {
|
||||
self.tree.get(self.element_to_node_id(id)).unwrap()
|
||||
// fn index(&self, id: ElementId) -> &Self::Output {
|
||||
// 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> {
|
||||
&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> {
|
||||
match &mut self.node.node_type {
|
||||
NodeType::Element(element) => NodeTypeMut::Element(ElementNodeMut {
|
||||
element,
|
||||
dirty: &mut self.dirty,
|
||||
}),
|
||||
let Self { id, dom, dirty } = self;
|
||||
let node_type = &mut dom.tree.write::<NodeData<V>>(*id).unwrap().node_type;
|
||||
match node_type {
|
||||
NodeType::Element(element) => NodeTypeMut::Element(ElementNodeMut { element, dirty }),
|
||||
NodeType::Text(text) => {
|
||||
self.dirty.set_text();
|
||||
dirty.set_text();
|
||||
NodeTypeMut::Text(text)
|
||||
}
|
||||
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) {
|
||||
let node_id = self.node.node_id;
|
||||
let node_id = self.node_data().node_id;
|
||||
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);
|
||||
} 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::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);
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub struct Node {
|
||||
pub(crate) struct Node {
|
||||
parent: Option<NodeId>,
|
||||
children: Vec<NodeId>,
|
||||
height: u16,
|
||||
}
|
||||
|
||||
pub struct NodeView<'a> {
|
||||
pub(crate) struct NodeView<'a> {
|
||||
tree: &'a Tree,
|
||||
id: NodeId,
|
||||
}
|
||||
@@ -27,25 +29,21 @@ impl NodeView<'_> {
|
||||
where
|
||||
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
|
||||
T: Any,
|
||||
{
|
||||
MappedRwLockReadGuard::map(self.tree.nodes.get_slab::<T>(), |slab| {
|
||||
slab.get(self.id).unwrap()
|
||||
})
|
||||
self.tree.nodes.read_slab::<T>().get(self.id).unwrap()
|
||||
}
|
||||
|
||||
pub fn get_mut<T>(&self) -> MappedRwLockWriteGuard<'_, T>
|
||||
pub fn get_mut<T>(&self) -> &mut T
|
||||
where
|
||||
T: Any,
|
||||
{
|
||||
MappedRwLockWriteGuard::map(self.tree.nodes.get_slab_mut::<T>(), |slab| {
|
||||
slab.get_mut(self.id).unwrap()
|
||||
})
|
||||
self.tree.nodes.write_slab::<T>().get_mut(self.id).unwrap()
|
||||
}
|
||||
|
||||
pub fn height(&self) -> u16 {
|
||||
@@ -66,7 +64,7 @@ impl NodeView<'_> {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Tree {
|
||||
pub(crate) struct Tree {
|
||||
nodes: AnySlab,
|
||||
root: NodeId,
|
||||
}
|
||||
@@ -84,20 +82,20 @@ impl Tree {
|
||||
Self { nodes, root }
|
||||
}
|
||||
|
||||
fn node_slab(&self) -> MappedRwLockReadGuard<'_, SlabStorage<Node>> {
|
||||
self.nodes.get_slab()
|
||||
fn node_slab(&self) -> &SlabStorage<Node> {
|
||||
self.nodes.read_slab()
|
||||
}
|
||||
|
||||
pub fn get_node_data(&self, id: NodeId) -> MappedRwLockReadGuard<'_, Node> {
|
||||
MappedRwLockReadGuard::map(self.node_slab(), |slab| slab.get(id).unwrap())
|
||||
pub fn get_node_data(&self, id: NodeId) -> &Node {
|
||||
self.node_slab().get(id).unwrap()
|
||||
}
|
||||
|
||||
fn node_slab_mut(&self) -> MappedRwLockWriteGuard<'_, SlabStorage<Node>> {
|
||||
self.nodes.get_slab_mut()
|
||||
fn node_slab_mut(&self) -> &mut SlabStorage<Node> {
|
||||
self.nodes.write_slab()
|
||||
}
|
||||
|
||||
pub fn get_node_data_mut(&self, id: NodeId) -> MappedRwLockWriteGuard<'_, Node> {
|
||||
MappedRwLockWriteGuard::map(self.node_slab_mut(), |slab| slab.get_mut(id).unwrap())
|
||||
pub fn get_node_data_mut(&self, id: NodeId) -> &mut Node {
|
||||
self.node_slab_mut().get_mut(id).unwrap()
|
||||
}
|
||||
|
||||
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();
|
||||
node.insert(Node {
|
||||
parent: None,
|
||||
@@ -206,7 +204,7 @@ impl Tree {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -214,42 +212,60 @@ impl Tree {
|
||||
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 {
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn state_view_mut<T: Any>(&mut self) -> TreeStateViewMut<'_, T> {
|
||||
TreeStateViewMut {
|
||||
nodes_data: self.node_slab(),
|
||||
nodes: self.nodes.get_slab_mut(),
|
||||
root: self.root,
|
||||
}
|
||||
pub fn read<T: Any>(&self, id: NodeId) -> Option<&T> {
|
||||
self.nodes.read_slab().get(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl NodeDataView for Tree {
|
||||
fn root(&self) -> NodeId {
|
||||
pub fn write<T: Any>(&mut self, id: NodeId) -> Option<&mut T> {
|
||||
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
|
||||
}
|
||||
|
||||
fn parent_id(&self, id: NodeId) -> Option<NodeId> {
|
||||
pub fn parent_id(&self, id: NodeId) -> Option<NodeId> {
|
||||
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())
|
||||
}
|
||||
|
||||
fn height(&self, id: NodeId) -> Option<u16> {
|
||||
pub fn height(&self, id: NodeId) -> Option<u16> {
|
||||
Some(self.get_node_data(id).height)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait NodeDataView {
|
||||
pub(crate) trait NodeDataView {
|
||||
fn root(&self) -> NodeId;
|
||||
|
||||
fn parent_id(&self, id: NodeId) -> Option<NodeId>;
|
||||
@@ -259,7 +275,7 @@ pub trait NodeDataView {
|
||||
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_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>;
|
||||
|
||||
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 {
|
||||
fn create_node(&mut self) -> Entry;
|
||||
|
||||
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);
|
||||
enum MaybeRead<'a> {
|
||||
Read(&'a Box<dyn AnySlabStorageImpl>),
|
||||
Write(&'a mut Box<dyn AnySlabStorageImpl>),
|
||||
}
|
||||
|
||||
pub struct TreeStateView<'a, T> {
|
||||
nodes_data: MappedRwLockReadGuard<'a, SlabStorage<Node>>,
|
||||
nodes: MappedRwLockReadGuard<'a, SlabStorage<T>>,
|
||||
#[derive(Clone, Copy)]
|
||||
struct TreeStateViewEntry<'a> {
|
||||
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,
|
||||
}
|
||||
|
||||
pub struct TreeStateViewMut<'a, T> {
|
||||
nodes_data: MappedRwLockReadGuard<'a, SlabStorage<Node>>,
|
||||
nodes: MappedRwLockWriteGuard<'a, SlabStorage<T>>,
|
||||
root: NodeId,
|
||||
}
|
||||
impl<'a> TreeStateView<'a> {
|
||||
fn get_slab<T: Any>(&self) -> Option<&SlabStorage<T>> {
|
||||
self.nodes
|
||||
.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 {
|
||||
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())
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
fn height(&self, id: NodeId) -> Option<u16> {
|
||||
pub fn height(&self, id: NodeId) -> Option<u16> {
|
||||
self.nodes_data.get(id).map(|n| n.height)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> TreeView<T> for TreeStateView<'a, T> {
|
||||
fn get(&self, id: NodeId) -> Option<&T> {
|
||||
self.nodes.get(id)
|
||||
pub fn get<T: Dependancy>(&self, id: NodeId) -> Option<T::ElementBorrowed<'_>> {
|
||||
T::borrow_elements_from(self.entry(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);
|
||||
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> 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)
|
||||
ids.and_then(|ids| {
|
||||
ids.iter()
|
||||
.map(|id| T::borrow_elements_from(self.entry(*id)))
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
||||
fn parent_child_mut(&mut self, id: NodeId) -> Option<(&mut T, Vec<&mut T>)> {
|
||||
// Safety: No node will appear as a child twice
|
||||
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
|
||||
}
|
||||
pub fn parent<T: Dependancy>(&self, id: NodeId) -> Option<T::ElementBorrowed<'_>> {
|
||||
T::borrow_elements_from(self.entry(id))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -727,7 +659,7 @@ fn get_node_children_mut() {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct SlabStorage<T> {
|
||||
pub(crate) struct SlabStorage<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 as_any(&self) -> &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) {
|
||||
self.data[id.0].take();
|
||||
}
|
||||
@@ -820,12 +752,9 @@ impl<T: 'static> AnySlabStorageImpl for SlabStorage<T> {
|
||||
}
|
||||
}
|
||||
|
||||
struct AnySlab {
|
||||
data: hashbrown::HashMap<
|
||||
TypeId,
|
||||
RwLock<Box<dyn AnySlabStorageImpl>>,
|
||||
BuildHasherDefault<FxHasher>,
|
||||
>,
|
||||
pub(crate) struct AnySlab {
|
||||
data: hashbrown::HashMap<TypeId, Box<dyn AnySlabStorageImpl>, BuildHasherDefault<FxHasher>>,
|
||||
filled: Vec<bool>,
|
||||
free: VecDeque<NodeId>,
|
||||
len: usize,
|
||||
}
|
||||
@@ -850,80 +779,104 @@ impl AnySlab {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
data: Default::default(),
|
||||
filled: Default::default(),
|
||||
free: VecDeque::new(),
|
||||
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
|
||||
.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>> {
|
||||
self.try_get_slab().unwrap()
|
||||
fn read_slab<T: Any>(&self) -> &SlabStorage<T> {
|
||||
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
|
||||
.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>> {
|
||||
self.try_get_slab_mut().unwrap()
|
||||
fn write_slab<T: Any>(&self) -> &mut SlabStorage<T> {
|
||||
self.try_write_slab().unwrap()
|
||||
}
|
||||
|
||||
fn get_or_insert_slab_mut<T: Any>(&mut self) -> MappedRwLockWriteGuard<'_, SlabStorage<T>> {
|
||||
RwLockWriteGuard::map(
|
||||
self.data
|
||||
.entry(TypeId::of::<T>())
|
||||
.or_insert_with(|| RwLock::new(Box::new(SlabStorage::<T>::default())))
|
||||
.write(),
|
||||
|x| x.as_any_mut().downcast_mut().unwrap(),
|
||||
)
|
||||
fn get_slab_mut_borrow<T: Any>(&mut self) -> &mut SlabStorage<T> {
|
||||
self.data
|
||||
.get_mut(&TypeId::of::<T>())
|
||||
.unwrap()
|
||||
.as_any_mut()
|
||||
.downcast_mut()
|
||||
.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() {
|
||||
self.filled[id.0] = true;
|
||||
id
|
||||
} else {
|
||||
let id = self.len;
|
||||
self.filled.push(true);
|
||||
self.len += 1;
|
||||
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);
|
||||
}
|
||||
|
||||
fn remove(&mut self, id: NodeId) {
|
||||
for slab in self.data.values_mut() {
|
||||
slab.write().remove(id);
|
||||
slab.remove(id);
|
||||
}
|
||||
self.filled[id.0] = true;
|
||||
self.free.push_back(id);
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
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,
|
||||
inner: &'a mut AnySlab,
|
||||
}
|
||||
|
||||
impl Entry<'_> {
|
||||
pub fn insert<T: Any>(&mut self, value: T) {
|
||||
impl EntryBuilder<'_> {
|
||||
pub fn insert<T: Any + Send + Sync>(&mut self, value: T) {
|
||||
self.inner
|
||||
.get_or_insert_slab_mut::<T>()
|
||||
.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) {
|
||||
self.inner.remove(self.id);
|
||||
}
|
||||
@@ -946,7 +899,7 @@ fn remove() {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -966,7 +919,7 @@ fn get_many_mut_unchecked() {
|
||||
println!("ids: {:#?}", [parent, child, grandchild]);
|
||||
|
||||
{
|
||||
let mut i32_slab = slab.get_slab_mut::<i32>();
|
||||
let mut i32_slab = slab.write_slab::<i32>();
|
||||
let all =
|
||||
unsafe { i32_slab.get_many_mut_unchecked([parent, child, grandchild].into_iter()) }
|
||||
.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!(
|
||||
unsafe { i32_slab.get_many_mut_unchecked([NodeId(3), NodeId(100)].into_iter()) }
|
||||
.is_none()
|
||||
@@ -1001,8 +954,8 @@ fn get_many_many_mut_unchecked() {
|
||||
|
||||
println!("slab: {:#?}", slab);
|
||||
|
||||
let mut num_entries = slab.get_slab_mut::<i32>();
|
||||
let mut str_entries = slab.get_slab_mut::<&str>();
|
||||
let mut num_entries = slab.write_slab::<i32>();
|
||||
let mut str_entries = slab.write_slab::<&str>();
|
||||
|
||||
let all_num = unsafe {
|
||||
num_entries
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
mod persistant_iterator;
|
||||
pub use persistant_iterator::*;
|
||||
// mod persistant_iterator;
|
||||
// pub use persistant_iterator::*;
|
||||
pub mod cursor;
|
||||
@@ -2,8 +2,6 @@ use crate::{
|
||||
node::{ElementNode, FromAnyValue, NodeType},
|
||||
passes::{AnyMapLike, TypeErasedPass},
|
||||
real_dom::RealDom,
|
||||
state::State,
|
||||
tree::TreeView,
|
||||
NodeId,
|
||||
};
|
||||
use dioxus_core::{Mutation, Mutations};
|
||||
|
||||
Reference in new issue
Block a user