WIP make ECS work with reactive system

This commit is contained in:
Evan Almloff committed 2023-01-19 14:40:56 -06:00
1 parent e36874d86e
commit 1587b41829
10 files changed
+564 -685

No files matched your search

+1 -1
View File
@@ -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"] }
-2
View File
@@ -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;
+7 -19
View File
@@ -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
}
}
+37 -1
View File
@@ -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
View File
@@ -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(&current_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(&current_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;
+170 -198
View File
@@ -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);
}
}
}
-46
View File
@@ -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
View File
@@ -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
+2 -2
View File
@@ -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};