work on integrating new pass system
This commit is contained in:
1 parent
e76cd63ee3
commit
9e971fbe11
9 files changed
+1251
-1158
No files matched your search
@@ -14,8 +14,6 @@ pub mod state;
|
|||||||
pub mod tree;
|
pub mod tree;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
/// A id for a node that lives in the real dom.
|
|
||||||
pub type RealNodeId = NodeId;
|
|
||||||
pub type FxDashMap<K, V> = dashmap::DashMap<K, V, BuildHasherDefault<FxHasher>>;
|
pub type FxDashMap<K, V> = dashmap::DashMap<K, V, BuildHasherDefault<FxHasher>>;
|
||||||
pub type FxDashSet<K> = dashmap::DashSet<K, BuildHasherDefault<FxHasher>>;
|
pub type FxDashSet<K> = dashmap::DashSet<K, BuildHasherDefault<FxHasher>>;
|
||||||
pub type SendAnyMap = anymap::Map<dyn anymap::any::Any + Send + Sync + 'static>;
|
pub type SendAnyMap = anymap::Map<dyn anymap::any::Any + Send + Sync + 'static>;
|
||||||
@@ -25,11 +23,11 @@ pub type SendAnyMap = anymap::Map<dyn anymap::any::Any + Send + Sync + 'static>;
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct HeightOrdering {
|
pub struct HeightOrdering {
|
||||||
pub height: u16,
|
pub height: u16,
|
||||||
pub id: RealNodeId,
|
pub id: NodeId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HeightOrdering {
|
impl HeightOrdering {
|
||||||
pub fn new(height: u16, id: RealNodeId) -> Self {
|
pub fn new(height: u16, id: NodeId) -> Self {
|
||||||
HeightOrdering { height, id }
|
HeightOrdering { height, id }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,23 +21,24 @@ pub struct NodeData {
|
|||||||
pub node_type: NodeType,
|
pub node_type: NodeType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ElementNode {
|
||||||
|
pub tag: String,
|
||||||
|
pub namespace: Option<String>,
|
||||||
|
pub attributes: FxHashMap<OwnedAttributeDiscription, OwnedAttributeValue>,
|
||||||
|
pub listeners: FxHashSet<String>,
|
||||||
|
}
|
||||||
|
|
||||||
/// A type of node with data specific to the node type. The types are a subset of the [VNode] types.
|
/// A type of node with data specific to the node type. The types are a subset of the [VNode] types.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum NodeType {
|
pub enum NodeType {
|
||||||
Text {
|
Text(String),
|
||||||
text: String,
|
Element(ElementNode),
|
||||||
},
|
|
||||||
Element {
|
|
||||||
tag: String,
|
|
||||||
namespace: Option<String>,
|
|
||||||
attributes: FxHashMap<OwnedAttributeDiscription, OwnedAttributeValue>,
|
|
||||||
listeners: FxHashSet<String>,
|
|
||||||
},
|
|
||||||
Placeholder,
|
Placeholder,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: State> Node<S> {
|
impl<S: State> Node<S> {
|
||||||
pub(crate) fn new(node_type: NodeType) -> Self {
|
pub fn new(node_type: NodeType) -> Self {
|
||||||
Node {
|
Node {
|
||||||
state: S::default(),
|
state: S::default(),
|
||||||
node_data: NodeData {
|
node_data: NodeData {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use dioxus_core::ElementId;
|
use dioxus_core::ElementId;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
node::{NodeData, NodeType, OwnedAttributeView},
|
node::{ElementNode, NodeData, NodeType, OwnedAttributeView},
|
||||||
state::union_ordered_iter,
|
state::union_ordered_iter,
|
||||||
RealNodeId,
|
NodeId,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A view into a [VNode] with limited access.
|
/// A view into a [VNode] with limited access.
|
||||||
@@ -28,7 +28,7 @@ impl<'a> NodeView<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the node id of the node
|
/// Get the node id of the node
|
||||||
pub fn node_id(&self) -> RealNodeId {
|
pub fn node_id(&self) -> NodeId {
|
||||||
self.inner.node_id
|
self.inner.node_id
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ impl<'a> NodeView<'a> {
|
|||||||
self.mask
|
self.mask
|
||||||
.tag
|
.tag
|
||||||
.then_some(match &self.inner.node_type {
|
.then_some(match &self.inner.node_type {
|
||||||
NodeType::Element { tag, .. } => Some(&**tag),
|
NodeType::Element(ElementNode { tag, .. }) => Some(&**tag),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.flatten()
|
.flatten()
|
||||||
@@ -48,7 +48,7 @@ impl<'a> NodeView<'a> {
|
|||||||
self.mask
|
self.mask
|
||||||
.namespace
|
.namespace
|
||||||
.then_some(match &self.inner.node_type {
|
.then_some(match &self.inner.node_type {
|
||||||
NodeType::Element { namespace, .. } => namespace.as_deref(),
|
NodeType::Element(ElementNode { namespace, .. }) => namespace.as_deref(),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.flatten()
|
.flatten()
|
||||||
@@ -57,7 +57,7 @@ impl<'a> NodeView<'a> {
|
|||||||
/// Get any attributes that are enabled in the mask
|
/// Get any attributes that are enabled in the mask
|
||||||
pub fn attributes<'b>(&'b self) -> Option<impl Iterator<Item = OwnedAttributeView<'a>> + 'b> {
|
pub fn attributes<'b>(&'b self) -> Option<impl Iterator<Item = OwnedAttributeView<'a>> + 'b> {
|
||||||
match &self.inner.node_type {
|
match &self.inner.node_type {
|
||||||
NodeType::Element { attributes, .. } => Some(
|
NodeType::Element(ElementNode { attributes, .. }) => Some(
|
||||||
attributes
|
attributes
|
||||||
.iter()
|
.iter()
|
||||||
.filter(move |(attr, _)| self.mask.attritutes.contains_attribute(&attr.name))
|
.filter(move |(attr, _)| self.mask.attritutes.contains_attribute(&attr.name))
|
||||||
@@ -75,7 +75,7 @@ impl<'a> NodeView<'a> {
|
|||||||
self.mask
|
self.mask
|
||||||
.text
|
.text
|
||||||
.then_some(match &self.inner.node_type {
|
.then_some(match &self.inner.node_type {
|
||||||
NodeType::Text { text } => Some(&**text),
|
NodeType::Text(text) => Some(&**text),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.flatten()
|
.flatten()
|
||||||
@@ -85,7 +85,9 @@ impl<'a> NodeView<'a> {
|
|||||||
pub fn listeners(&self) -> Option<impl Iterator<Item = &'a str> + '_> {
|
pub fn listeners(&self) -> Option<impl Iterator<Item = &'a str> + '_> {
|
||||||
if self.mask.listeners {
|
if self.mask.listeners {
|
||||||
match &self.inner.node_type {
|
match &self.inner.node_type {
|
||||||
NodeType::Element { listeners, .. } => Some(listeners.iter().map(|l| &**l)),
|
NodeType::Element(ElementNode { listeners, .. }) => {
|
||||||
|
Some(listeners.iter().map(|l| &**l))
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -238,6 +240,28 @@ impl NodeMask {
|
|||||||
.with_element()
|
.with_element()
|
||||||
.with_listeners();
|
.with_listeners();
|
||||||
|
|
||||||
|
pub fn from_node(node: &NodeType) -> Self {
|
||||||
|
match node {
|
||||||
|
NodeType::Text { .. } => Self::new().with_text(),
|
||||||
|
NodeType::Element(ElementNode {
|
||||||
|
tag: _,
|
||||||
|
namespace: _,
|
||||||
|
attributes,
|
||||||
|
listeners,
|
||||||
|
}) => {
|
||||||
|
let mut mask = Self::new_with_attrs(AttributeMask::Dynamic(
|
||||||
|
attributes.keys().map(|key| key.name.clone()).collect(),
|
||||||
|
))
|
||||||
|
.with_element();
|
||||||
|
if !listeners.is_empty() {
|
||||||
|
mask = mask.with_listeners();
|
||||||
|
}
|
||||||
|
mask
|
||||||
|
}
|
||||||
|
NodeType::Placeholder => Self::new().with_element(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if two masks overlap
|
/// Check if two masks overlap
|
||||||
pub fn overlaps(&self, other: &Self) -> bool {
|
pub fn overlaps(&self, other: &Self) -> bool {
|
||||||
(self.tag && other.tag)
|
(self.tag && other.tag)
|
||||||
@@ -280,12 +304,22 @@ impl NodeMask {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the mask to view the tag
|
||||||
|
pub fn set_tag(&mut self) {
|
||||||
|
self.tag = true;
|
||||||
|
}
|
||||||
|
|
||||||
/// Allow the mask to view the namespace
|
/// Allow the mask to view the namespace
|
||||||
pub const fn with_namespace(mut self) -> Self {
|
pub const fn with_namespace(mut self) -> Self {
|
||||||
self.namespace = true;
|
self.namespace = true;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the mask to view the namespace
|
||||||
|
pub fn set_namespace(&mut self) {
|
||||||
|
self.namespace = true;
|
||||||
|
}
|
||||||
|
|
||||||
/// Allow the mask to view the namespace and tag
|
/// Allow the mask to view the namespace and tag
|
||||||
pub const fn with_element(self) -> Self {
|
pub const fn with_element(self) -> Self {
|
||||||
self.with_namespace().with_tag()
|
self.with_namespace().with_tag()
|
||||||
@@ -297,9 +331,24 @@ impl NodeMask {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the mask to view the text
|
||||||
|
pub fn set_text(&mut self) {
|
||||||
|
self.text = true;
|
||||||
|
}
|
||||||
|
|
||||||
/// Allow the mask to view the listeners
|
/// Allow the mask to view the listeners
|
||||||
pub const fn with_listeners(mut self) -> Self {
|
pub const fn with_listeners(mut self) -> Self {
|
||||||
self.listeners = true;
|
self.listeners = true;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the mask to view the listeners
|
||||||
|
pub fn set_listeners(&mut self) {
|
||||||
|
self.listeners = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allow the mask to view the given attributes
|
||||||
|
pub fn add_attributes(&mut self, attributes: AttributeMask) {
|
||||||
|
self.attritutes = self.attritutes.union(&attributes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+661
-547
File diff suppressed because it is too large.
Load diff
@@ -1,26 +1,17 @@
|
|||||||
use dioxus_core::{ElementId, Mutations, TemplateNode};
|
use dioxus_core::{ElementId, Mutations, TemplateNode};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
use std::any::TypeId;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::ops::{Deref, DerefMut, Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
|
|
||||||
use crate::node::{Node, NodeType, OwnedAttributeDiscription, OwnedAttributeValue};
|
use crate::node::{
|
||||||
|
ElementNode, Node, NodeData, NodeType, OwnedAttributeDiscription, OwnedAttributeValue,
|
||||||
|
};
|
||||||
use crate::node_ref::{AttributeMask, NodeMask};
|
use crate::node_ref::{AttributeMask, NodeMask};
|
||||||
use crate::passes::{resolve_passes, DirtyNodeStates, TypeErasedPass};
|
use crate::passes::{resolve_passes, DirtyNodeStates, TypeErasedPass};
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
use crate::tree::{NodeId, Tree, TreeLike, TreeView};
|
use crate::tree::{NodeId, Tree, TreeLike, TreeView, TreeViewMut};
|
||||||
use crate::{FxDashSet, RealNodeId, SendAnyMap};
|
use crate::{FxDashSet, SendAnyMap};
|
||||||
|
|
||||||
fn mark_dirty(
|
|
||||||
node_id: NodeId,
|
|
||||||
mask: NodeMask,
|
|
||||||
nodes_updated: &mut FxHashMap<RealNodeId, NodeMask>,
|
|
||||||
) {
|
|
||||||
if let Some(node) = nodes_updated.get_mut(&node_id) {
|
|
||||||
*node = node.union(&mask);
|
|
||||||
} else {
|
|
||||||
nodes_updated.insert(node_id, mask);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers.
|
/// A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers.
|
||||||
/// The render state passes from parent to children and or accumulates state from children to parents.
|
/// The render state passes from parent to children and or accumulates state from children to parents.
|
||||||
@@ -28,12 +19,15 @@ fn mark_dirty(
|
|||||||
pub struct RealDom<S: State + Send> {
|
pub struct RealDom<S: State + Send> {
|
||||||
pub tree: Tree<Node<S>>,
|
pub tree: Tree<Node<S>>,
|
||||||
/// a map from element id to real node id
|
/// a map from element id to real node id
|
||||||
node_id_mapping: Vec<Option<RealNodeId>>,
|
node_id_mapping: Vec<Option<NodeId>>,
|
||||||
nodes_listening: FxHashMap<String, FxHashSet<RealNodeId>>,
|
nodes_listening: FxHashMap<String, FxHashSet<NodeId>>,
|
||||||
stack: Vec<RealNodeId>,
|
stack: Vec<NodeId>,
|
||||||
templates: FxHashMap<String, Vec<RealNodeId>>,
|
templates: FxHashMap<String, Vec<NodeId>>,
|
||||||
root_initialized: bool,
|
|
||||||
pub(crate) passes: Box<[TypeErasedPass<S>]>,
|
pub(crate) passes: Box<[TypeErasedPass<S>]>,
|
||||||
|
pub(crate) nodes_updated: FxHashMap<NodeId, NodeMask>,
|
||||||
|
passes_updated: FxHashMap<NodeId, FxHashSet<TypeId>>,
|
||||||
|
parent_changed_nodes: FxHashSet<NodeId>,
|
||||||
|
child_changed_nodes: FxHashSet<NodeId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: State + Send + Debug> Debug for RealDom<S> {
|
impl<S: State + Send + Debug> Debug for RealDom<S> {
|
||||||
@@ -44,7 +38,6 @@ impl<S: State + Send + Debug> Debug for RealDom<S> {
|
|||||||
.field("nodes_listening", &self.nodes_listening)
|
.field("nodes_listening", &self.nodes_listening)
|
||||||
.field("stack", &self.stack)
|
.field("stack", &self.stack)
|
||||||
.field("templates", &self.templates)
|
.field("templates", &self.templates)
|
||||||
.field("root_initialized", &self.root_initialized)
|
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,18 +50,34 @@ impl<S: State + Send> Default for RealDom<S> {
|
|||||||
|
|
||||||
impl<S: State + Send> RealDom<S> {
|
impl<S: State + Send> RealDom<S> {
|
||||||
pub fn new() -> RealDom<S> {
|
pub fn new() -> RealDom<S> {
|
||||||
let mut root = Node::new(NodeType::Element {
|
let mut root = Node::new(NodeType::Element(ElementNode {
|
||||||
tag: "Root".to_string(),
|
tag: "Root".to_string(),
|
||||||
namespace: Some("Root".to_string()),
|
namespace: Some("Root".to_string()),
|
||||||
attributes: FxHashMap::default(),
|
attributes: FxHashMap::default(),
|
||||||
listeners: FxHashSet::default(),
|
listeners: FxHashSet::default(),
|
||||||
});
|
}));
|
||||||
root.node_data.element_id = Some(ElementId(0));
|
root.node_data.element_id = Some(ElementId(0));
|
||||||
let mut tree = Tree::new(root);
|
let mut tree = Tree::new(root);
|
||||||
let root_id = tree.root();
|
let root_id = tree.root();
|
||||||
tree.get_mut(root_id).unwrap().node_data.node_id = root_id;
|
tree.get_mut(root_id).unwrap().node_data.node_id = root_id;
|
||||||
|
|
||||||
let passes = S::create_passes();
|
let mut passes = S::create_passes();
|
||||||
|
|
||||||
|
// resolve dependants for each pass
|
||||||
|
for i in 1..passes.len() {
|
||||||
|
let (before, after) = passes.split_at_mut(i);
|
||||||
|
let (current, before) = before.split_last_mut().unwrap();
|
||||||
|
for pass in before.iter_mut().chain(after.iter_mut()) {
|
||||||
|
for dependancy in ¤t.combined_dependancy_type_ids {
|
||||||
|
if pass.this_type_id == *dependancy {
|
||||||
|
pass.dependants.insert(current.this_type_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut nodes_updated = FxHashMap::default();
|
||||||
|
let root_id = NodeId(0);
|
||||||
|
nodes_updated.insert(root_id, NodeMask::ALL);
|
||||||
|
|
||||||
RealDom {
|
RealDom {
|
||||||
tree,
|
tree,
|
||||||
@@ -76,12 +85,31 @@ impl<S: State + Send> RealDom<S> {
|
|||||||
nodes_listening: FxHashMap::default(),
|
nodes_listening: FxHashMap::default(),
|
||||||
stack: vec![root_id],
|
stack: vec![root_id],
|
||||||
templates: FxHashMap::default(),
|
templates: FxHashMap::default(),
|
||||||
root_initialized: false,
|
|
||||||
passes,
|
passes,
|
||||||
|
nodes_updated,
|
||||||
|
passes_updated: FxHashMap::default(),
|
||||||
|
parent_changed_nodes: FxHashSet::default(),
|
||||||
|
child_changed_nodes: FxHashSet::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn element_to_node_id(&self, element_id: ElementId) -> RealNodeId {
|
fn mark_dirty(&mut self, node_id: NodeId, mask: NodeMask) {
|
||||||
|
if let Some(node) = self.nodes_updated.get_mut(&node_id) {
|
||||||
|
*node = node.union(&mask);
|
||||||
|
} else {
|
||||||
|
self.nodes_updated.insert(node_id, mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_parent_added_or_removed(&mut self, node_id: NodeId) {
|
||||||
|
self.parent_changed_nodes.insert(node_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_child_changed(&mut self, node_id: NodeId) {
|
||||||
|
self.child_changed_nodes.insert(node_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn element_to_node_id(&self, element_id: ElementId) -> NodeId {
|
||||||
self.node_id_mapping.get(element_id.0).unwrap().unwrap()
|
self.node_id_mapping.get(element_id.0).unwrap().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +127,7 @@ impl<S: State + Send> RealDom<S> {
|
|||||||
self.node_id_mapping[element_id.0] = Some(node_id);
|
self.node_id_mapping[element_id.0] = Some(node_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_child(&self, path: &[u8]) -> RealNodeId {
|
fn load_child(&self, path: &[u8]) -> NodeId {
|
||||||
let mut current = *self.stack.last().unwrap();
|
let mut current = *self.stack.last().unwrap();
|
||||||
for i in path {
|
for i in path {
|
||||||
current = self.tree.children_ids(current).unwrap()[*i as usize];
|
current = self.tree.children_ids(current).unwrap()[*i as usize];
|
||||||
@@ -107,18 +135,21 @@ impl<S: State + Send> RealDom<S> {
|
|||||||
current
|
current
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_node(&mut self, node: Node<S>) -> RealNodeId {
|
fn create_node(&mut self, node: Node<S>, mark_dirty: bool) -> NodeId {
|
||||||
let node_id = self.tree.create_node(node);
|
let node_id = self.tree.create_node(node);
|
||||||
let node = self.tree.get_mut(node_id).unwrap();
|
let node = self.tree.get_mut(node_id).unwrap();
|
||||||
node.node_data.node_id = node_id;
|
node.node_data.node_id = node_id;
|
||||||
|
if mark_dirty {
|
||||||
|
self.nodes_updated.insert(node_id, NodeMask::ALL);
|
||||||
|
}
|
||||||
node_id
|
node_id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_child(&mut self, node_id: RealNodeId, child_id: RealNodeId) {
|
fn add_child(&mut self, node_id: NodeId, child_id: NodeId) {
|
||||||
self.tree.add_child(node_id, child_id);
|
self.tree.add_child(node_id, child_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_template_node(&mut self, node: &TemplateNode) -> RealNodeId {
|
fn create_template_node(&mut self, node: &TemplateNode) -> NodeId {
|
||||||
match node {
|
match node {
|
||||||
TemplateNode::Element {
|
TemplateNode::Element {
|
||||||
tag,
|
tag,
|
||||||
@@ -126,7 +157,7 @@ impl<S: State + Send> RealDom<S> {
|
|||||||
attrs,
|
attrs,
|
||||||
children,
|
children,
|
||||||
} => {
|
} => {
|
||||||
let node = Node::new(NodeType::Element {
|
let node = Node::new(NodeType::Element(ElementNode {
|
||||||
tag: tag.to_string(),
|
tag: tag.to_string(),
|
||||||
namespace: namespace.map(|s| s.to_string()),
|
namespace: namespace.map(|s| s.to_string()),
|
||||||
attributes: attrs
|
attributes: attrs
|
||||||
@@ -148,30 +179,28 @@ impl<S: State + Send> RealDom<S> {
|
|||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
listeners: FxHashSet::default(),
|
listeners: FxHashSet::default(),
|
||||||
});
|
}));
|
||||||
let node_id = self.create_node(node);
|
let node_id = self.create_node(node, true);
|
||||||
for child in *children {
|
for child in *children {
|
||||||
let child_id = self.create_template_node(child);
|
let child_id = self.create_template_node(child);
|
||||||
self.add_child(node_id, child_id);
|
self.add_child(node_id, child_id);
|
||||||
}
|
}
|
||||||
node_id
|
node_id
|
||||||
}
|
}
|
||||||
TemplateNode::Text { text } => self.create_node(Node::new(NodeType::Text {
|
TemplateNode::Text { text } => {
|
||||||
text: text.to_string(),
|
self.create_node(Node::new(NodeType::Text(text.to_string())), true)
|
||||||
})),
|
}
|
||||||
TemplateNode::Dynamic { .. } => self.create_node(Node::new(NodeType::Placeholder)),
|
TemplateNode::Dynamic { .. } => {
|
||||||
TemplateNode::DynamicText { .. } => self.create_node(Node::new(NodeType::Text {
|
self.create_node(Node::new(NodeType::Placeholder), true)
|
||||||
text: String::new(),
|
}
|
||||||
})),
|
TemplateNode::DynamicText { .. } => {
|
||||||
|
self.create_node(Node::new(NodeType::Text(String::new())), true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the dom with some mutations and return a set of nodes that were updated. Pass the dirty nodes to update_state.
|
/// Updates the dom with some mutations and return a set of nodes that were updated. Pass the dirty nodes to update_state.
|
||||||
pub fn apply_mutations(
|
pub fn apply_mutations(&mut self, mutations: Mutations) {
|
||||||
&mut self,
|
|
||||||
mutations: Mutations,
|
|
||||||
) -> (DirtyNodeStates, FxHashMap<RealNodeId, NodeMask>) {
|
|
||||||
let mut nodes_updated: FxHashMap<RealNodeId, NodeMask> = FxHashMap::default();
|
|
||||||
for template in mutations.templates {
|
for template in mutations.templates {
|
||||||
let mut template_root_ids = Vec::new();
|
let mut template_root_ids = Vec::new();
|
||||||
for root in template.roots {
|
for root in template.roots {
|
||||||
@@ -181,11 +210,7 @@ impl<S: State + Send> RealDom<S> {
|
|||||||
self.templates
|
self.templates
|
||||||
.insert(template.name.to_string(), template_root_ids);
|
.insert(template.name.to_string(), template_root_ids);
|
||||||
}
|
}
|
||||||
if !self.root_initialized {
|
|
||||||
self.root_initialized = true;
|
|
||||||
let root_id = self.tree.root();
|
|
||||||
nodes_updated.insert(root_id, NodeMask::ALL);
|
|
||||||
}
|
|
||||||
for e in mutations.edits {
|
for e in mutations.edits {
|
||||||
use dioxus_core::Mutation::*;
|
use dioxus_core::Mutation::*;
|
||||||
match e {
|
match e {
|
||||||
@@ -194,7 +219,6 @@ impl<S: State + Send> RealDom<S> {
|
|||||||
let parent = self.element_to_node_id(id);
|
let parent = self.element_to_node_id(id);
|
||||||
for child in children {
|
for child in children {
|
||||||
self.add_child(parent, child);
|
self.add_child(parent, child);
|
||||||
mark_dirty(child, NodeMask::ALL, &mut nodes_updated);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AssignId { path, id } => {
|
AssignId { path, id } => {
|
||||||
@@ -202,38 +226,32 @@ impl<S: State + Send> RealDom<S> {
|
|||||||
}
|
}
|
||||||
CreatePlaceholder { id } => {
|
CreatePlaceholder { id } => {
|
||||||
let node = Node::new(NodeType::Placeholder);
|
let node = Node::new(NodeType::Placeholder);
|
||||||
let node_id = self.create_node(node);
|
let node_id = self.create_node(node, true);
|
||||||
self.set_element_id(node_id, id);
|
self.set_element_id(node_id, id);
|
||||||
self.stack.push(node_id);
|
self.stack.push(node_id);
|
||||||
mark_dirty(node_id, NodeMask::ALL, &mut nodes_updated);
|
|
||||||
}
|
}
|
||||||
CreateTextNode { value, id } => {
|
CreateTextNode { value, id } => {
|
||||||
let node = Node::new(NodeType::Text {
|
let node = Node::new(NodeType::Text(value.to_string()));
|
||||||
text: value.to_string(),
|
let node_id = self.create_node(node, true);
|
||||||
});
|
|
||||||
let node_id = self.create_node(node);
|
|
||||||
let node = self.tree.get_mut(node_id).unwrap();
|
let node = self.tree.get_mut(node_id).unwrap();
|
||||||
node.node_data.element_id = Some(id);
|
node.node_data.element_id = Some(id);
|
||||||
self.stack.push(node_id);
|
self.stack.push(node_id);
|
||||||
mark_dirty(node_id, NodeMask::new().with_text(), &mut nodes_updated);
|
|
||||||
}
|
}
|
||||||
HydrateText { path, value, id } => {
|
HydrateText { path, value, id } => {
|
||||||
let node_id = self.load_child(path);
|
let node_id = self.load_child(path);
|
||||||
self.set_element_id(node_id, id);
|
self.set_element_id(node_id, id);
|
||||||
let node = self.tree.get_mut(node_id).unwrap();
|
let node = self.tree.get_mut(node_id).unwrap();
|
||||||
if let NodeType::Text { text } = &mut node.node_data.node_type {
|
if let NodeType::Text(text) = &mut node.node_data.node_type {
|
||||||
*text = value.to_string();
|
*text = value.to_string();
|
||||||
} else {
|
} else {
|
||||||
node.node_data.node_type = NodeType::Text {
|
node.node_data.node_type = NodeType::Text(value.to_string());
|
||||||
text: value.to_string(),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mark_dirty(node_id, NodeMask::new().with_text(), &mut nodes_updated);
|
self.mark_dirty(node_id, NodeMask::new().with_text());
|
||||||
}
|
}
|
||||||
LoadTemplate { name, index, id } => {
|
LoadTemplate { name, index, id } => {
|
||||||
let template_id = self.templates[name][index];
|
let template_id = self.templates[name][index];
|
||||||
let clone_id = self.clone_node(template_id, &mut nodes_updated);
|
let clone_id = self.clone_node(template_id);
|
||||||
self.set_element_id(clone_id, id);
|
self.set_element_id(clone_id, id);
|
||||||
self.stack.push(clone_id);
|
self.stack.push(clone_id);
|
||||||
}
|
}
|
||||||
@@ -242,7 +260,6 @@ impl<S: State + Send> RealDom<S> {
|
|||||||
let old_node_id = self.element_to_node_id(id);
|
let old_node_id = self.element_to_node_id(id);
|
||||||
for new in new_nodes {
|
for new in new_nodes {
|
||||||
self.tree.insert_before(old_node_id, new);
|
self.tree.insert_before(old_node_id, new);
|
||||||
mark_dirty(new, NodeMask::ALL, &mut nodes_updated);
|
|
||||||
}
|
}
|
||||||
self.tree.remove(old_node_id);
|
self.tree.remove(old_node_id);
|
||||||
}
|
}
|
||||||
@@ -251,7 +268,6 @@ impl<S: State + Send> RealDom<S> {
|
|||||||
let old_node_id = self.load_child(path);
|
let old_node_id = self.load_child(path);
|
||||||
for new in new_nodes {
|
for new in new_nodes {
|
||||||
self.tree.insert_before(old_node_id, new);
|
self.tree.insert_before(old_node_id, new);
|
||||||
mark_dirty(new, NodeMask::ALL, &mut nodes_updated);
|
|
||||||
}
|
}
|
||||||
self.tree.remove(old_node_id);
|
self.tree.remove(old_node_id);
|
||||||
}
|
}
|
||||||
@@ -260,7 +276,6 @@ impl<S: State + Send> RealDom<S> {
|
|||||||
let old_node_id = self.element_to_node_id(id);
|
let old_node_id = self.element_to_node_id(id);
|
||||||
for new in new_nodes.into_iter().rev() {
|
for new in new_nodes.into_iter().rev() {
|
||||||
self.tree.insert_after(old_node_id, new);
|
self.tree.insert_after(old_node_id, new);
|
||||||
mark_dirty(new, NodeMask::ALL, &mut nodes_updated);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InsertBefore { id, m } => {
|
InsertBefore { id, m } => {
|
||||||
@@ -268,7 +283,6 @@ impl<S: State + Send> RealDom<S> {
|
|||||||
let old_node_id = self.element_to_node_id(id);
|
let old_node_id = self.element_to_node_id(id);
|
||||||
for new in new_nodes {
|
for new in new_nodes {
|
||||||
self.tree.insert_before(old_node_id, new);
|
self.tree.insert_before(old_node_id, new);
|
||||||
mark_dirty(new, NodeMask::ALL, &mut nodes_updated);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SetAttribute {
|
SetAttribute {
|
||||||
@@ -278,9 +292,9 @@ impl<S: State + Send> RealDom<S> {
|
|||||||
ns,
|
ns,
|
||||||
} => {
|
} => {
|
||||||
let node_id = self.element_to_node_id(id);
|
let node_id = self.element_to_node_id(id);
|
||||||
let node = self.tree.get_mut(node_id).unwrap();
|
let mut node = self.get_mut(node_id).unwrap();
|
||||||
if let NodeType::Element { attributes, .. } = &mut node.node_data.node_type {
|
if let NodeTypeMut::Element(mut element) = node.node_type_mut() {
|
||||||
attributes.insert(
|
element.set_attribute(
|
||||||
OwnedAttributeDiscription {
|
OwnedAttributeDiscription {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
namespace: ns.map(|s| s.to_string()),
|
namespace: ns.map(|s| s.to_string()),
|
||||||
@@ -288,18 +302,13 @@ impl<S: State + Send> RealDom<S> {
|
|||||||
},
|
},
|
||||||
crate::node::OwnedAttributeValue::Text(value.to_string()),
|
crate::node::OwnedAttributeValue::Text(value.to_string()),
|
||||||
);
|
);
|
||||||
mark_dirty(
|
|
||||||
node_id,
|
|
||||||
NodeMask::new_with_attrs(AttributeMask::single(name)),
|
|
||||||
&mut nodes_updated,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SetBoolAttribute { name, value, id } => {
|
SetBoolAttribute { name, value, id } => {
|
||||||
let node_id = self.element_to_node_id(id);
|
let node_id = self.element_to_node_id(id);
|
||||||
let node = self.tree.get_mut(node_id).unwrap();
|
let mut node = self.get_mut(node_id).unwrap();
|
||||||
if let NodeType::Element { attributes, .. } = &mut node.node_data.node_type {
|
if let NodeTypeMut::Element(mut element) = node.node_type_mut() {
|
||||||
attributes.insert(
|
element.set_attribute(
|
||||||
OwnedAttributeDiscription {
|
OwnedAttributeDiscription {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
namespace: None,
|
namespace: None,
|
||||||
@@ -307,25 +316,21 @@ impl<S: State + Send> RealDom<S> {
|
|||||||
},
|
},
|
||||||
crate::node::OwnedAttributeValue::Bool(value),
|
crate::node::OwnedAttributeValue::Bool(value),
|
||||||
);
|
);
|
||||||
mark_dirty(
|
|
||||||
node_id,
|
|
||||||
NodeMask::new_with_attrs(AttributeMask::single(name)),
|
|
||||||
&mut nodes_updated,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SetText { value, id } => {
|
SetText { value, id } => {
|
||||||
let node_id = self.element_to_node_id(id);
|
let node_id = self.element_to_node_id(id);
|
||||||
let node = self.tree.get_mut(node_id).unwrap();
|
let mut node = self.get_mut(node_id).unwrap();
|
||||||
if let NodeType::Text { text } = &mut node.node_data.node_type {
|
if let NodeTypeMut::Text(text) = node.node_type_mut() {
|
||||||
*text = value.to_string();
|
*text = value.to_string();
|
||||||
}
|
}
|
||||||
mark_dirty(node_id, NodeMask::new().with_text(), &mut nodes_updated);
|
|
||||||
}
|
}
|
||||||
NewEventListener { name, id } => {
|
NewEventListener { name, id } => {
|
||||||
let node_id = self.element_to_node_id(id);
|
let node_id = self.element_to_node_id(id);
|
||||||
let node = self.tree.get_mut(node_id).unwrap();
|
let mut node = self.get_mut(node_id).unwrap();
|
||||||
if let NodeType::Element { listeners, .. } = &mut node.node_data.node_type {
|
if let NodeTypeMut::Element(mut element) = node.node_type_mut() {
|
||||||
|
element.listeners_mut().insert(name.to_string());
|
||||||
|
drop(node);
|
||||||
match self.nodes_listening.get_mut(name) {
|
match self.nodes_listening.get_mut(name) {
|
||||||
Some(hs) => {
|
Some(hs) => {
|
||||||
hs.insert(node_id);
|
hs.insert(node_id);
|
||||||
@@ -336,14 +341,15 @@ impl<S: State + Send> RealDom<S> {
|
|||||||
self.nodes_listening.insert(name.to_string(), hs);
|
self.nodes_listening.insert(name.to_string(), hs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
listeners.insert(name.to_string());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RemoveEventListener { id, name } => {
|
RemoveEventListener { id, name } => {
|
||||||
let node_id = self.element_to_node_id(id);
|
let node_id = self.element_to_node_id(id);
|
||||||
let node = self.tree.get_mut(node_id).unwrap();
|
{
|
||||||
if let NodeType::Element { listeners, .. } = &mut node.node_data.node_type {
|
let mut node = self.get_mut(node_id).unwrap();
|
||||||
listeners.remove(name);
|
if let NodeTypeMut::Element(mut element) = node.node_type_mut() {
|
||||||
|
element.listeners_mut().remove(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.nodes_listening.get_mut(name).unwrap().remove(&node_id);
|
self.nodes_listening.get_mut(name).unwrap().remove(&node_id);
|
||||||
}
|
}
|
||||||
@@ -357,8 +363,17 @@ impl<S: State + Send> RealDom<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 tree = &mut self.tree;
|
||||||
|
let passes = &self.passes;
|
||||||
let dirty_nodes = DirtyNodeStates::default();
|
let dirty_nodes = DirtyNodeStates::default();
|
||||||
|
let nodes_updated = std::mem::take(&mut self.nodes_updated);
|
||||||
for (&n, mask) in &nodes_updated {
|
for (&n, mask) in &nodes_updated {
|
||||||
// remove any nodes that were created and then removed in the same mutations from the dirty nodes list
|
// remove any nodes that were created and then removed in the same mutations from the dirty nodes list
|
||||||
if self.tree.contains(n) {
|
if self.tree.contains(n) {
|
||||||
@@ -370,18 +385,11 @@ impl<S: State + Send> RealDom<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(dirty_nodes, nodes_updated)
|
todo!("incorporate other update members");
|
||||||
}
|
(
|
||||||
|
resolve_passes(tree, dirty_nodes, passes, ctx),
|
||||||
/// 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.
|
nodes_updated,
|
||||||
pub fn update_state(
|
)
|
||||||
&mut self,
|
|
||||||
nodes_updated: DirtyNodeStates,
|
|
||||||
ctx: SendAnyMap,
|
|
||||||
) -> FxDashSet<RealNodeId> {
|
|
||||||
let tree = &mut self.tree;
|
|
||||||
let passes = &self.passes;
|
|
||||||
resolve_passes(tree, nodes_updated, passes, ctx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find all nodes that are listening for an event, sorted by there height in the dom progressing starting at the bottom and progressing up.
|
/// Find all nodes that are listening for an event, sorted by there height in the dom progressing starting at the bottom and progressing up.
|
||||||
@@ -411,39 +419,135 @@ impl<S: State + Send> RealDom<S> {
|
|||||||
self.tree.root()
|
self.tree.root()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_node(
|
fn clone_node(&mut self, node_id: NodeId) -> NodeId {
|
||||||
&mut self,
|
|
||||||
node_id: NodeId,
|
|
||||||
nodes_updated: &mut FxHashMap<RealNodeId, NodeMask>,
|
|
||||||
) -> RealNodeId {
|
|
||||||
let node = self.tree.get(node_id).unwrap();
|
let node = self.tree.get(node_id).unwrap();
|
||||||
let new_node = node.clone();
|
let new_node = Node {
|
||||||
let new_id = self.create_node(new_node);
|
state: node.state.clone_or_default(),
|
||||||
mark_dirty(new_id, NodeMask::ALL, nodes_updated);
|
node_data: node.node_data.clone(),
|
||||||
|
};
|
||||||
|
let new_id = self.create_node(new_node, false);
|
||||||
|
if let Some(passes) = S::non_clone_nodes() {
|
||||||
|
for pass_id in &*passes {
|
||||||
|
self.passes_updated
|
||||||
|
.entry(node_id)
|
||||||
|
.or_default()
|
||||||
|
.insert(*pass_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let self_ptr = self as *mut Self;
|
let self_ptr = self as *mut Self;
|
||||||
for child in self.tree.children_ids(node_id).unwrap() {
|
for child in self.tree.children_ids(node_id).unwrap() {
|
||||||
unsafe {
|
unsafe {
|
||||||
// this is safe because no node has itself as a child
|
// this is safe because no node has itself as a child
|
||||||
let self_mut = &mut *self_ptr;
|
let self_mut = &mut *self_ptr;
|
||||||
let child_id = self_mut.clone_node(*child, nodes_updated);
|
let child_id = self_mut.clone_node(*child);
|
||||||
self_mut.add_child(new_id, child_id);
|
self_mut.add_child(new_id, child_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
new_id
|
new_id
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: State + Send> Deref for RealDom<S> {
|
pub fn get_mut(&mut self, id: NodeId) -> Option<NodeMut<'_>> {
|
||||||
type Target = Tree<Node<S>>;
|
self.tree.get_mut(id).map(|node| NodeMut {
|
||||||
|
node: &mut node.node_data,
|
||||||
|
dirty: NodeMask::new(),
|
||||||
|
nodes_updated: &mut self.nodes_updated,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
/// 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.
|
||||||
&self.tree
|
pub fn get_mut_raw(&mut self, id: NodeId) -> Option<&mut Node<S>> {
|
||||||
|
self.tree.get_mut(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: State + Send> DerefMut for RealDom<S> {
|
impl<S: State + Send> TreeView<Node<S>> for RealDom<S> {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
type Iterator<'a> = <Tree<Node<S>> as TreeView<Node<S>>>::Iterator<'a>;
|
||||||
&mut self.tree
|
|
||||||
|
fn root(&self) -> NodeId {
|
||||||
|
self.tree.root()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(&self, id: NodeId) -> Option<&Node<S>> {
|
||||||
|
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>> {
|
||||||
|
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 + Send> TreeLike<Node<S>> for RealDom<S> {
|
||||||
|
fn create_node(&mut self, node: Node<S>) -> NodeId {
|
||||||
|
let mask = NodeMask::ALL;
|
||||||
|
let id = self.tree.create_node(node);
|
||||||
|
self.tree.get_mut(id).unwrap().node_data.node_id = id;
|
||||||
|
self.mark_dirty(id, mask);
|
||||||
|
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>> {
|
||||||
|
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>> {
|
||||||
|
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);
|
||||||
|
self.mark_parent_added_or_removed(new);
|
||||||
|
}
|
||||||
|
self.tree.replace(old, new);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_before(&mut self, id: NodeId, new: NodeId) {
|
||||||
|
if let Some(parent_id) = self.tree.parent_id(id) {
|
||||||
|
self.mark_child_changed(parent_id);
|
||||||
|
self.mark_parent_added_or_removed(new);
|
||||||
|
}
|
||||||
|
self.tree.insert_before(id, new);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_after(&mut self, id: NodeId, new: NodeId) {
|
||||||
|
if let Some(parent_id) = self.tree.parent_id(id) {
|
||||||
|
self.mark_child_changed(parent_id);
|
||||||
|
self.mark_parent_added_or_removed(new);
|
||||||
|
}
|
||||||
|
self.tree.insert_after(id, new);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,10 +559,10 @@ impl<S: State + Send> Index<ElementId> for RealDom<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: State + Send> Index<RealNodeId> for RealDom<S> {
|
impl<S: State + Send> Index<NodeId> for RealDom<S> {
|
||||||
type Output = Node<S>;
|
type Output = Node<S>;
|
||||||
|
|
||||||
fn index(&self, idx: RealNodeId) -> &Self::Output {
|
fn index(&self, idx: NodeId) -> &Self::Output {
|
||||||
self.tree.get(idx).unwrap()
|
self.tree.get(idx).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -469,8 +573,114 @@ impl<S: State + Send> IndexMut<ElementId> for RealDom<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: State + Send> IndexMut<RealNodeId> for RealDom<S> {
|
impl<S: State + Send> IndexMut<NodeId> for RealDom<S> {
|
||||||
fn index_mut(&mut self, idx: RealNodeId) -> &mut Self::Output {
|
fn index_mut(&mut self, idx: NodeId) -> &mut Self::Output {
|
||||||
self.tree.get_mut(idx).unwrap()
|
self.tree.get_mut(idx).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct NodeMut<'a> {
|
||||||
|
node: &'a mut NodeData,
|
||||||
|
dirty: NodeMask,
|
||||||
|
nodes_updated: &'a mut FxHashMap<NodeId, NodeMask>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> NodeMut<'a> {
|
||||||
|
pub fn node_type(&self) -> &NodeType {
|
||||||
|
&self.node.node_type
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn node_type_mut(&mut self) -> NodeTypeMut<'_> {
|
||||||
|
match &mut self.node.node_type {
|
||||||
|
NodeType::Element(element) => NodeTypeMut::Element(ElementNodeMut {
|
||||||
|
element,
|
||||||
|
dirty: &mut self.dirty,
|
||||||
|
}),
|
||||||
|
NodeType::Text(text) => {
|
||||||
|
self.dirty.set_text();
|
||||||
|
NodeTypeMut::Text(text)
|
||||||
|
}
|
||||||
|
NodeType::Placeholder => NodeTypeMut::Placeholder,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for NodeMut<'_> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let node_id = self.node.node_id;
|
||||||
|
let mask = std::mem::take(&mut self.dirty);
|
||||||
|
if let Some(node) = self.nodes_updated.get_mut(&node_id) {
|
||||||
|
*node = node.union(&mask);
|
||||||
|
} else {
|
||||||
|
self.nodes_updated.insert(node_id, mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum NodeTypeMut<'a> {
|
||||||
|
Element(ElementNodeMut<'a>),
|
||||||
|
Text(&'a mut String),
|
||||||
|
Placeholder,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ElementNodeMut<'a> {
|
||||||
|
element: &'a mut ElementNode,
|
||||||
|
dirty: &'a mut NodeMask,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ElementNodeMut<'_> {
|
||||||
|
pub fn tag(&self) -> &str {
|
||||||
|
&self.element.tag
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tag_mut(&mut self) -> &mut String {
|
||||||
|
self.dirty.set_tag();
|
||||||
|
&mut self.element.tag
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn namespace(&self) -> Option<&str> {
|
||||||
|
self.element.namespace.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn namespace_mut(&mut self) -> &mut Option<String> {
|
||||||
|
self.dirty.set_namespace();
|
||||||
|
&mut self.element.namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn attributes(&self) -> &FxHashMap<OwnedAttributeDiscription, OwnedAttributeValue> {
|
||||||
|
&self.element.attributes
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn attributes_mut(
|
||||||
|
&mut self,
|
||||||
|
) -> &mut FxHashMap<OwnedAttributeDiscription, OwnedAttributeValue> {
|
||||||
|
self.dirty.add_attributes(AttributeMask::All);
|
||||||
|
&mut self.element.attributes
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_attribute(
|
||||||
|
&mut self,
|
||||||
|
name: OwnedAttributeDiscription,
|
||||||
|
value: OwnedAttributeValue,
|
||||||
|
) -> Option<OwnedAttributeValue> {
|
||||||
|
self.dirty.add_attributes(AttributeMask::single(&name.name));
|
||||||
|
self.element.attributes.insert(name, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_attribute_mut(
|
||||||
|
&mut self,
|
||||||
|
name: &OwnedAttributeDiscription,
|
||||||
|
) -> Option<&mut OwnedAttributeValue> {
|
||||||
|
self.dirty.add_attributes(AttributeMask::single(&name.name));
|
||||||
|
self.element.attributes.get_mut(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn listeners(&self) -> &FxHashSet<String> {
|
||||||
|
&self.element.listeners
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn listeners_mut(&mut self) -> &mut FxHashSet<String> {
|
||||||
|
self.dirty.set_listeners();
|
||||||
|
&mut self.element.listeners
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
use std::cmp::Ordering;
|
|
||||||
|
|
||||||
use crate::node::Node;
|
|
||||||
use crate::node_ref::{NodeMask, NodeView};
|
use crate::node_ref::{NodeMask, NodeView};
|
||||||
use crate::passes::{resolve_passes, AnyMapLike, DirtyNodeStates, Pass, TypeErasedPass};
|
use crate::passes::{AnyMapLike, TypeErasedPass};
|
||||||
use crate::tree::{Tree, TreeView};
|
use std::any::TypeId;
|
||||||
use crate::{FxDashSet, RealNodeId, SendAnyMap};
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
/// Join two sorted iterators
|
/// Join two sorted iterators
|
||||||
pub(crate) fn union_ordered_iter<'a>(
|
pub(crate) fn union_ordered_iter<'a>(
|
||||||
@@ -213,6 +210,16 @@ pub trait NodeDepState {
|
|||||||
pub trait State: Default + Clone + AnyMapLike + 'static {
|
pub trait State: Default + Clone + AnyMapLike + 'static {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
fn create_passes() -> Box<[TypeErasedPass<Self>]>;
|
fn create_passes() -> Box<[TypeErasedPass<Self>]>;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn clone_or_default(&self) -> Self {
|
||||||
|
self.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn non_clone_nodes() -> Option<Box<[TypeId]>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChildDepState for () {
|
impl ChildDepState for () {
|
||||||
|
|||||||
+131
-414
@@ -25,6 +25,17 @@ pub struct Tree<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Tree<T> {
|
impl<T> Tree<T> {
|
||||||
|
pub fn new(root: T) -> Self {
|
||||||
|
let mut nodes = Slab::default();
|
||||||
|
let root = NodeId(nodes.insert(Node {
|
||||||
|
value: root,
|
||||||
|
parent: None,
|
||||||
|
children: Vec::new(),
|
||||||
|
height: 0,
|
||||||
|
}));
|
||||||
|
Self { nodes, root }
|
||||||
|
}
|
||||||
|
|
||||||
fn try_remove(&mut self, id: NodeId) -> Option<Node<T>> {
|
fn try_remove(&mut self, id: NodeId) -> Option<Node<T>> {
|
||||||
self.nodes.try_remove(id.0).map(|node| {
|
self.nodes.try_remove(id.0).map(|node| {
|
||||||
if let Some(parent) = node.parent {
|
if let Some(parent) = node.parent {
|
||||||
@@ -63,10 +74,6 @@ impl<T> Tree<T> {
|
|||||||
|
|
||||||
pub trait TreeView<T>: Sized {
|
pub trait TreeView<T>: Sized {
|
||||||
type Iterator<'a>: Iterator<Item = &'a T>
|
type Iterator<'a>: Iterator<Item = &'a T>
|
||||||
where
|
|
||||||
T: 'a,
|
|
||||||
Self: 'a;
|
|
||||||
type IteratorMut<'a>: Iterator<Item = &'a mut T>
|
|
||||||
where
|
where
|
||||||
T: 'a,
|
T: 'a,
|
||||||
Self: 'a;
|
Self: 'a;
|
||||||
@@ -83,69 +90,16 @@ pub trait TreeView<T>: Sized {
|
|||||||
unsafe { self.get(id).unwrap_unchecked() }
|
unsafe { self.get(id).unwrap_unchecked() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_mut(&mut self, id: NodeId) -> Option<&mut T>;
|
|
||||||
|
|
||||||
fn get_mut_unchecked(&mut self, id: NodeId) -> &mut T {
|
|
||||||
unsafe { self.get_mut(id).unwrap_unchecked() }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn children(&self, id: NodeId) -> Option<Self::Iterator<'_>>;
|
fn children(&self, id: NodeId) -> Option<Self::Iterator<'_>>;
|
||||||
|
|
||||||
fn children_mut(&mut self, id: NodeId) -> Option<Self::IteratorMut<'_>>;
|
|
||||||
|
|
||||||
fn parent_child_mut(&mut self, id: NodeId) -> Option<(&mut T, Self::IteratorMut<'_>)> {
|
|
||||||
let mut_ptr: *mut Self = self;
|
|
||||||
unsafe {
|
|
||||||
// Safety: No node has itself as a child.
|
|
||||||
(*mut_ptr).get_mut(id).and_then(|parent| {
|
|
||||||
(*mut_ptr)
|
|
||||||
.children_mut(id)
|
|
||||||
.map(|children| (parent, children))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn children_ids(&self, id: NodeId) -> Option<&[NodeId]>;
|
fn children_ids(&self, id: NodeId) -> Option<&[NodeId]>;
|
||||||
|
|
||||||
fn parent(&self, id: NodeId) -> Option<&T>;
|
fn parent(&self, id: NodeId) -> Option<&T>;
|
||||||
|
|
||||||
fn parent_mut(&mut self, id: NodeId) -> Option<&mut T>;
|
|
||||||
|
|
||||||
fn node_parent_mut(&mut self, id: NodeId) -> Option<(&mut T, Option<&mut T>)> {
|
|
||||||
let mut_ptr: *mut Self = self;
|
|
||||||
unsafe {
|
|
||||||
// Safety: No node has itself as a parent.
|
|
||||||
(*mut_ptr)
|
|
||||||
.get_mut(id)
|
|
||||||
.map(|node| (node, (*mut_ptr).parent_mut(id)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn node_parent_children_mut(
|
|
||||||
&mut self,
|
|
||||||
id: NodeId,
|
|
||||||
) -> Option<(&mut T, Option<&mut T>, Option<Self::IteratorMut<'_>>)> {
|
|
||||||
let mut_ptr: *mut Self = self;
|
|
||||||
unsafe {
|
|
||||||
// Safety: No node has itself as a parent or child.
|
|
||||||
(*mut_ptr)
|
|
||||||
.get_mut(id)
|
|
||||||
.map(|node| (node, (*mut_ptr).parent_mut(id), (*mut_ptr).children_mut(id)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_id(&self, id: NodeId) -> Option<NodeId>;
|
fn parent_id(&self, id: NodeId) -> Option<NodeId>;
|
||||||
|
|
||||||
fn height(&self, id: NodeId) -> Option<u16>;
|
fn height(&self, id: NodeId) -> Option<u16>;
|
||||||
|
|
||||||
fn map<T2, F: Fn(&T) -> &T2, FMut: Fn(&mut T) -> &mut T2>(
|
|
||||||
&mut self,
|
|
||||||
map: F,
|
|
||||||
map_mut: FMut,
|
|
||||||
) -> TreeMap<T, T2, Self, F, FMut> {
|
|
||||||
TreeMap::new(self, map, map_mut)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size(&self) -> usize;
|
fn size(&self) -> usize;
|
||||||
|
|
||||||
fn traverse_depth_first(&self, mut f: impl FnMut(&T)) {
|
fn traverse_depth_first(&self, mut f: impl FnMut(&T)) {
|
||||||
@@ -160,18 +114,6 @@ pub trait TreeView<T>: Sized {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn traverse_depth_first_mut(&mut self, mut f: impl FnMut(&mut T)) {
|
|
||||||
let mut stack = vec![self.root()];
|
|
||||||
while let Some(id) = stack.pop() {
|
|
||||||
if let Some(node) = self.get_mut(id) {
|
|
||||||
f(node);
|
|
||||||
if let Some(children) = self.children_ids(id) {
|
|
||||||
stack.extend(children.iter().copied().rev());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn traverse_breadth_first(&self, mut f: impl FnMut(&T)) {
|
fn traverse_breadth_first(&self, mut f: impl FnMut(&T)) {
|
||||||
let mut queue = VecDeque::new();
|
let mut queue = VecDeque::new();
|
||||||
queue.push_back(self.root());
|
queue.push_back(self.root());
|
||||||
@@ -186,6 +128,61 @@ pub trait TreeView<T>: Sized {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait TreeViewMut<T>: Sized + TreeView<T> {
|
||||||
|
type IteratorMut<'a>: Iterator<Item = &'a mut T>
|
||||||
|
where
|
||||||
|
T: 'a,
|
||||||
|
Self: 'a;
|
||||||
|
|
||||||
|
fn get_mut(&mut self, id: NodeId) -> Option<&mut T>;
|
||||||
|
|
||||||
|
fn get_mut_unchecked(&mut self, id: NodeId) -> &mut T {
|
||||||
|
unsafe { self.get_mut(id).unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn children_mut(&mut self, id: NodeId) -> Option<<Self as TreeViewMut<T>>::IteratorMut<'_>>;
|
||||||
|
|
||||||
|
fn parent_child_mut(
|
||||||
|
&mut self,
|
||||||
|
id: NodeId,
|
||||||
|
) -> Option<(&mut T, <Self as TreeViewMut<T>>::IteratorMut<'_>)> {
|
||||||
|
let mut_ptr: *mut Self = self;
|
||||||
|
unsafe {
|
||||||
|
// Safety: No node has itself as a child.
|
||||||
|
(*mut_ptr).get_mut(id).and_then(|parent| {
|
||||||
|
(*mut_ptr)
|
||||||
|
.children_mut(id)
|
||||||
|
.map(|children| (parent, children))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parent_mut(&mut self, id: NodeId) -> Option<&mut T>;
|
||||||
|
|
||||||
|
fn node_parent_mut(&mut self, id: NodeId) -> Option<(&mut T, Option<&mut T>)>;
|
||||||
|
|
||||||
|
fn node_parent_children_mut(
|
||||||
|
&mut self,
|
||||||
|
id: NodeId,
|
||||||
|
) -> Option<(
|
||||||
|
&mut T,
|
||||||
|
Option<&mut T>,
|
||||||
|
Option<<Self as TreeViewMut<T>>::IteratorMut<'_>>,
|
||||||
|
)>;
|
||||||
|
|
||||||
|
fn traverse_depth_first_mut(&mut self, mut f: impl FnMut(&mut T)) {
|
||||||
|
let mut stack = vec![self.root()];
|
||||||
|
while let Some(id) = stack.pop() {
|
||||||
|
if let Some(node) = self.get_mut(id) {
|
||||||
|
f(node);
|
||||||
|
if let Some(children) = self.children_ids(id) {
|
||||||
|
stack.extend(children.iter().copied().rev());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn traverse_breadth_first_mut(&mut self, mut f: impl FnMut(&mut T)) {
|
fn traverse_breadth_first_mut(&mut self, mut f: impl FnMut(&mut T)) {
|
||||||
let mut queue = VecDeque::new();
|
let mut queue = VecDeque::new();
|
||||||
@@ -203,9 +200,7 @@ pub trait TreeView<T>: Sized {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TreeLike<T>: TreeView<T> {
|
pub trait TreeLike<T> {
|
||||||
fn new(root: T) -> Self;
|
|
||||||
|
|
||||||
fn create_node(&mut self, value: T) -> NodeId;
|
fn create_node(&mut self, value: T) -> NodeId;
|
||||||
|
|
||||||
fn add_child(&mut self, parent: NodeId, child: NodeId);
|
fn add_child(&mut self, parent: NodeId, child: NodeId);
|
||||||
@@ -239,22 +234,22 @@ impl<'a, T: 'a, Tr: TreeView<T>> Iterator for ChildNodeIterator<'a, T, Tr> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ChildNodeIteratorMut<'a, T, Tr: TreeView<T> + 'a> {
|
pub struct ChildNodeIteratorMut<'a, T, Tr: TreeViewMut<T> + 'a> {
|
||||||
tree: *mut Tr,
|
tree: *mut Tr,
|
||||||
children_ids: &'a [NodeId],
|
children_ids: &'a [NodeId],
|
||||||
index: usize,
|
index: usize,
|
||||||
node_type: PhantomData<T>,
|
node_type: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<'a, T, Tr: TreeView<T> + 'a> Sync for ChildNodeIteratorMut<'a, T, Tr> {}
|
unsafe impl<'a, T, Tr: TreeViewMut<T> + 'a> Sync for ChildNodeIteratorMut<'a, T, Tr> {}
|
||||||
|
|
||||||
impl<'a, T, Tr: TreeView<T>> ChildNodeIteratorMut<'a, T, Tr> {
|
impl<'a, T, Tr: TreeViewMut<T>> ChildNodeIteratorMut<'a, T, Tr> {
|
||||||
fn tree_mut(&mut self) -> &'a mut Tr {
|
fn tree_mut(&mut self) -> &'a mut Tr {
|
||||||
unsafe { &mut *self.tree }
|
unsafe { &mut *self.tree }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: 'a, Tr: TreeView<T>> Iterator for ChildNodeIteratorMut<'a, T, Tr> {
|
impl<'a, T: 'a, Tr: TreeViewMut<T>> Iterator for ChildNodeIteratorMut<'a, T, Tr> {
|
||||||
type Item = &'a mut T;
|
type Item = &'a mut T;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
@@ -272,7 +267,6 @@ impl<'a, T: 'a, Tr: TreeView<T>> Iterator for ChildNodeIteratorMut<'a, T, Tr> {
|
|||||||
|
|
||||||
impl<T> TreeView<T> for Tree<T> {
|
impl<T> TreeView<T> for Tree<T> {
|
||||||
type Iterator<'a> = ChildNodeIterator<'a, T, Tree<T>> where T: 'a;
|
type Iterator<'a> = ChildNodeIterator<'a, T, Tree<T>> where T: 'a;
|
||||||
type IteratorMut<'a> = ChildNodeIteratorMut<'a, T, Tree<T>> where T: 'a;
|
|
||||||
|
|
||||||
fn root(&self) -> NodeId {
|
fn root(&self) -> NodeId {
|
||||||
self.root
|
self.root
|
||||||
@@ -282,10 +276,6 @@ impl<T> TreeView<T> for Tree<T> {
|
|||||||
self.nodes.get(id.0).map(|node| &node.value)
|
self.nodes.get(id.0).map(|node| &node.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_mut(&mut self, id: NodeId) -> Option<&mut T> {
|
|
||||||
self.nodes.get_mut(id.0).map(|node| &mut node.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn children(&self, id: NodeId) -> Option<Self::Iterator<'_>> {
|
fn children(&self, id: NodeId) -> Option<Self::Iterator<'_>> {
|
||||||
self.children_ids(id).map(|children_ids| ChildNodeIterator {
|
self.children_ids(id).map(|children_ids| ChildNodeIterator {
|
||||||
tree: self,
|
tree: self,
|
||||||
@@ -295,20 +285,6 @@ impl<T> TreeView<T> for Tree<T> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn children_mut(&mut self, id: NodeId) -> Option<Self::IteratorMut<'_>> {
|
|
||||||
let raw_ptr = self as *mut Self;
|
|
||||||
unsafe {
|
|
||||||
// Safety: No node will appear as a child twice
|
|
||||||
self.children_ids(id)
|
|
||||||
.map(|children_ids| ChildNodeIteratorMut {
|
|
||||||
tree: &mut *raw_ptr,
|
|
||||||
children_ids,
|
|
||||||
index: 0,
|
|
||||||
node_type: PhantomData,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn children_ids(&self, id: NodeId) -> Option<&[NodeId]> {
|
fn children_ids(&self, id: NodeId) -> Option<&[NodeId]> {
|
||||||
self.nodes.get(id.0).map(|node| node.children.as_slice())
|
self.nodes.get(id.0).map(|node| node.children.as_slice())
|
||||||
}
|
}
|
||||||
@@ -320,6 +296,30 @@ impl<T> TreeView<T> for Tree<T> {
|
|||||||
.map(|node| &node.value)
|
.map(|node| &node.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parent_id(&self, id: NodeId) -> Option<NodeId> {
|
||||||
|
self.nodes.get(id.0).and_then(|node| node.parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn height(&self, id: NodeId) -> Option<u16> {
|
||||||
|
self.nodes.get(id.0).map(|n| n.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_unchecked(&self, id: NodeId) -> &T {
|
||||||
|
unsafe { &self.nodes.get_unchecked(id.0).value }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> usize {
|
||||||
|
self.nodes.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> TreeViewMut<T> for Tree<T> {
|
||||||
|
type IteratorMut<'a> = ChildNodeIteratorMut<'a, T, Tree<T>> where T: 'a;
|
||||||
|
|
||||||
|
fn get_mut(&mut self, id: NodeId) -> Option<&mut T> {
|
||||||
|
self.nodes.get_mut(id.0).map(|node| &mut node.value)
|
||||||
|
}
|
||||||
|
|
||||||
fn parent_mut(&mut self, id: NodeId) -> Option<&mut T> {
|
fn parent_mut(&mut self, id: NodeId) -> Option<&mut T> {
|
||||||
let self_ptr = self as *mut Self;
|
let self_ptr = self as *mut Self;
|
||||||
unsafe {
|
unsafe {
|
||||||
@@ -334,39 +334,52 @@ impl<T> TreeView<T> for Tree<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parent_id(&self, id: NodeId) -> Option<NodeId> {
|
fn children_mut(&mut self, id: NodeId) -> Option<Self::IteratorMut<'_>> {
|
||||||
self.nodes.get(id.0).and_then(|node| node.parent)
|
let raw_ptr = self as *mut Self;
|
||||||
}
|
unsafe {
|
||||||
|
// Safety: No node will appear as a child twice
|
||||||
fn height(&self, id: NodeId) -> Option<u16> {
|
self.children_ids(id)
|
||||||
self.nodes.get(id.0).map(|n| n.height)
|
.map(|children_ids| ChildNodeIteratorMut {
|
||||||
}
|
tree: &mut *raw_ptr,
|
||||||
|
children_ids,
|
||||||
fn get_unchecked(&self, id: NodeId) -> &T {
|
index: 0,
|
||||||
unsafe { &self.nodes.get_unchecked(id.0).value }
|
node_type: PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_mut_unchecked(&mut self, id: NodeId) -> &mut T {
|
fn get_mut_unchecked(&mut self, id: NodeId) -> &mut T {
|
||||||
unsafe { &mut self.nodes.get_unchecked_mut(id.0).value }
|
unsafe { &mut self.nodes.get_unchecked_mut(id.0).value }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size(&self) -> usize {
|
fn node_parent_mut(&mut self, id: NodeId) -> Option<(&mut T, Option<&mut T>)> {
|
||||||
self.nodes.len()
|
if let Some(parent_id) = self.parent_id(id) {
|
||||||
|
self.nodes
|
||||||
|
.get2_mut(id.0, parent_id.0)
|
||||||
|
.map(|(node, parent)| (&mut node.value, Some(&mut parent.value)))
|
||||||
|
} else {
|
||||||
|
self.nodes.get_mut(id.0).map(|node| (&mut node.value, None))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn node_parent_children_mut(
|
||||||
|
&mut self,
|
||||||
|
id: NodeId,
|
||||||
|
) -> Option<(
|
||||||
|
&mut T,
|
||||||
|
Option<&mut T>,
|
||||||
|
Option<<Self as TreeViewMut<T>>::IteratorMut<'_>>,
|
||||||
|
)> {
|
||||||
|
// 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)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> TreeLike<T> for Tree<T> {
|
impl<T> TreeLike<T> for Tree<T> {
|
||||||
fn new(root: T) -> Self {
|
|
||||||
let mut nodes = Slab::default();
|
|
||||||
let root = NodeId(nodes.insert(Node {
|
|
||||||
value: root,
|
|
||||||
parent: None,
|
|
||||||
children: Vec::new(),
|
|
||||||
height: 0,
|
|
||||||
}));
|
|
||||||
Self { nodes, root }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_node(&mut self, value: T) -> NodeId {
|
fn create_node(&mut self, value: T) -> NodeId {
|
||||||
NodeId(self.nodes.insert(Node {
|
NodeId(self.nodes.insert(Node {
|
||||||
value,
|
value,
|
||||||
@@ -448,248 +461,6 @@ impl<T> TreeLike<T> for Tree<T> {
|
|||||||
self.set_height(new, height);
|
self.set_height(new, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TreeMap<'a, T1, T2, Tr, F, FMut>
|
|
||||||
where
|
|
||||||
Tr: TreeView<T1>,
|
|
||||||
F: Fn(&T1) -> &T2,
|
|
||||||
FMut: Fn(&mut T1) -> &mut T2,
|
|
||||||
{
|
|
||||||
tree: &'a mut Tr,
|
|
||||||
map: F,
|
|
||||||
map_mut: FMut,
|
|
||||||
in_node_type: PhantomData<T1>,
|
|
||||||
out_node_type: PhantomData<T2>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T1, T2, Tr, F, FMut> TreeMap<'a, T1, T2, Tr, F, FMut>
|
|
||||||
where
|
|
||||||
Tr: TreeView<T1>,
|
|
||||||
F: Fn(&T1) -> &T2,
|
|
||||||
FMut: Fn(&mut T1) -> &mut T2,
|
|
||||||
{
|
|
||||||
pub fn new(tree: &'a mut Tr, map: F, map_mut: FMut) -> Self {
|
|
||||||
TreeMap {
|
|
||||||
tree,
|
|
||||||
map,
|
|
||||||
map_mut,
|
|
||||||
in_node_type: PhantomData,
|
|
||||||
out_node_type: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T1, T2, Tr, F, FMut> TreeView<T2> for TreeMap<'a, T1, T2, Tr, F, FMut>
|
|
||||||
where
|
|
||||||
Tr: TreeView<T1>,
|
|
||||||
F: Fn(&T1) -> &T2,
|
|
||||||
FMut: Fn(&mut T1) -> &mut T2,
|
|
||||||
{
|
|
||||||
type Iterator<'b> = ChildNodeIterator<'b, T2, TreeMap<'a, T1, T2, Tr, F, FMut>>
|
|
||||||
where
|
|
||||||
T2: 'b,
|
|
||||||
Self:'b;
|
|
||||||
type IteratorMut<'b> = ChildNodeIteratorMut<'b, T2, TreeMap<'a, T1, T2, Tr, F, FMut>>
|
|
||||||
where
|
|
||||||
T2: 'b,
|
|
||||||
Self:'b;
|
|
||||||
|
|
||||||
fn root(&self) -> NodeId {
|
|
||||||
self.tree.root()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self, id: NodeId) -> Option<&T2> {
|
|
||||||
self.tree.get(id).map(|node| (self.map)(node))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_mut(&mut self, id: NodeId) -> Option<&mut T2> {
|
|
||||||
self.tree.get_mut(id).map(|node| (self.map_mut)(node))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn children(&self, id: NodeId) -> Option<Self::Iterator<'_>> {
|
|
||||||
self.children_ids(id).map(|children_ids| ChildNodeIterator {
|
|
||||||
tree: self,
|
|
||||||
children_ids,
|
|
||||||
index: 0,
|
|
||||||
node_type: PhantomData,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn children_mut(&mut self, id: NodeId) -> Option<Self::IteratorMut<'_>> {
|
|
||||||
let raw_ptr = self as *mut Self;
|
|
||||||
unsafe {
|
|
||||||
// Safety: No node can be a child twice.
|
|
||||||
self.children_ids(id)
|
|
||||||
.map(|children_ids| ChildNodeIteratorMut {
|
|
||||||
tree: &mut *raw_ptr,
|
|
||||||
children_ids,
|
|
||||||
index: 0,
|
|
||||||
node_type: PhantomData,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn children_ids(&self, id: NodeId) -> Option<&[NodeId]> {
|
|
||||||
self.tree.children_ids(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent(&self, id: NodeId) -> Option<&T2> {
|
|
||||||
self.tree.parent(id).map(|node| (self.map)(node))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_mut(&mut self, id: NodeId) -> Option<&mut T2> {
|
|
||||||
self.tree.parent_mut(id).map(|node| (self.map_mut)(node))
|
|
||||||
}
|
|
||||||
|
|
||||||
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 get_unchecked(&self, id: NodeId) -> &T2 {
|
|
||||||
(self.map)(self.tree.get_unchecked(id))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_mut_unchecked(&mut self, id: NodeId) -> &mut T2 {
|
|
||||||
(self.map_mut)(self.tree.get_mut_unchecked(id))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size(&self) -> usize {
|
|
||||||
self.tree.size()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A view into a tree that can be shared between multiple threads. Nodes are locked invividually.
|
|
||||||
pub struct SharedView<'a, T, Tr: TreeView<T>> {
|
|
||||||
tree: Arc<UnsafeCell<&'a mut Tr>>,
|
|
||||||
node_locks: Arc<RwLock<Vec<RawMutex>>>,
|
|
||||||
node_type: PhantomData<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T, Tr: TreeView<T>> SharedView<'a, T, Tr> {
|
|
||||||
/// Checks if a node is currently locked. Returns None if the node does not exist.
|
|
||||||
pub fn check_lock(&self, id: NodeId) -> Option<bool> {
|
|
||||||
let locks = self.node_locks.read();
|
|
||||||
locks.get(id.0).map(|lock| lock.is_locked())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<'a, T, Tr: TreeView<T>> Send for SharedView<'a, T, Tr> {}
|
|
||||||
unsafe impl<'a, T, Tr: TreeView<T>> Sync for SharedView<'a, T, Tr> {}
|
|
||||||
impl<'a, T, Tr: TreeView<T>> Clone for SharedView<'a, T, Tr> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
tree: self.tree.clone(),
|
|
||||||
node_locks: self.node_locks.clone(),
|
|
||||||
node_type: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T, Tr: TreeView<T>> SharedView<'a, T, Tr> {
|
|
||||||
pub fn new(tree: &'a mut Tr) -> Self {
|
|
||||||
let tree = Arc::new(UnsafeCell::new(tree));
|
|
||||||
let mut node_locks = Vec::new();
|
|
||||||
for _ in 0..unsafe { (*tree.get()).size() } {
|
|
||||||
node_locks.push(RawMutex::INIT);
|
|
||||||
}
|
|
||||||
Self {
|
|
||||||
tree,
|
|
||||||
node_locks: Arc::new(RwLock::new(node_locks)),
|
|
||||||
node_type: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lock_node(&self, node: NodeId) {
|
|
||||||
let read = self.node_locks.read();
|
|
||||||
let lock = read.get(node.0);
|
|
||||||
match lock {
|
|
||||||
Some(lock) => lock.lock(),
|
|
||||||
None => {
|
|
||||||
drop(read);
|
|
||||||
let mut write = self.node_locks.write();
|
|
||||||
write.resize_with(node.0 + 1, || RawMutex::INIT);
|
|
||||||
unsafe { write.get_unchecked(node.0).lock() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unlock_node(&self, node: NodeId) {
|
|
||||||
let read = self.node_locks.read();
|
|
||||||
let lock = read.get(node.0);
|
|
||||||
match lock {
|
|
||||||
Some(lock) => unsafe { lock.unlock() },
|
|
||||||
None => {
|
|
||||||
panic!("unlocking node that was not locked")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn with_node<R>(&self, node_id: NodeId, f: impl FnOnce(&'a mut Tr) -> R) -> R {
|
|
||||||
self.lock_node(node_id);
|
|
||||||
let tree = unsafe { &mut *self.tree.get() };
|
|
||||||
let r = f(tree);
|
|
||||||
self.unlock_node(node_id);
|
|
||||||
r
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T, Tr: TreeView<T>> TreeView<T> for SharedView<'a, T, Tr> {
|
|
||||||
type Iterator<'b> = Tr::Iterator<'b> where T: 'b, Self: 'b;
|
|
||||||
|
|
||||||
type IteratorMut<'b>=Tr::IteratorMut<'b>
|
|
||||||
where
|
|
||||||
T: 'b,
|
|
||||||
Self: 'b;
|
|
||||||
|
|
||||||
fn root(&self) -> NodeId {
|
|
||||||
unsafe { (*self.tree.get()).root() }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self, id: NodeId) -> Option<&T> {
|
|
||||||
self.with_node(id, |t| t.get(id))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_mut(&mut self, id: NodeId) -> Option<&mut T> {
|
|
||||||
self.with_node(id, |t| t.get_mut(id))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn children(&self, id: NodeId) -> Option<Self::Iterator<'_>> {
|
|
||||||
self.with_node(id, |t| t.children(id))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn children_mut(&mut self, id: NodeId) -> Option<Self::IteratorMut<'_>> {
|
|
||||||
self.with_node(id, |t| t.children_mut(id))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn children_ids(&self, id: NodeId) -> Option<&[NodeId]> {
|
|
||||||
self.with_node(id, |t| t.children_ids(id))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent(&self, id: NodeId) -> Option<&T> {
|
|
||||||
self.with_node(id, |t| t.get(id))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_mut(&mut self, id: NodeId) -> Option<&mut T> {
|
|
||||||
self.with_node(id, |t| t.parent_mut(id))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_id(&self, id: NodeId) -> Option<NodeId> {
|
|
||||||
self.with_node(id, |t| t.parent_id(id))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn height(&self, id: NodeId) -> Option<u16> {
|
|
||||||
unsafe { (*self.tree.get()).height(id) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size(&self) -> usize {
|
|
||||||
unsafe { (*self.tree.get()).size() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn creation() {
|
fn creation() {
|
||||||
let mut tree = Tree::new(1);
|
let mut tree = Tree::new(1);
|
||||||
@@ -798,60 +569,6 @@ fn deletion() {
|
|||||||
assert_eq!(tree.children_ids(parent).unwrap(), &[]);
|
assert_eq!(tree.children_ids(parent).unwrap(), &[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn shared_view() {
|
|
||||||
use std::thread;
|
|
||||||
let mut tree = Tree::new(1);
|
|
||||||
let parent = tree.root();
|
|
||||||
let child = tree.create_node(0);
|
|
||||||
tree.add_child(parent, child);
|
|
||||||
|
|
||||||
let shared = SharedView::new(&mut tree);
|
|
||||||
|
|
||||||
thread::scope(|s| {
|
|
||||||
let (mut shared1, mut shared2, mut shared3) =
|
|
||||||
(shared.clone(), shared.clone(), shared.clone());
|
|
||||||
s.spawn(move || {
|
|
||||||
assert_eq!(*shared1.get_mut(parent).unwrap(), 1);
|
|
||||||
assert_eq!(*shared1.get_mut(child).unwrap(), 0);
|
|
||||||
});
|
|
||||||
s.spawn(move || {
|
|
||||||
assert_eq!(*shared2.get_mut(child).unwrap(), 0);
|
|
||||||
assert_eq!(*shared2.get_mut(parent).unwrap(), 1);
|
|
||||||
});
|
|
||||||
s.spawn(move || {
|
|
||||||
assert_eq!(*shared3.get_mut(parent).unwrap(), 1);
|
|
||||||
assert_eq!(*shared3.get_mut(child).unwrap(), 0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn map() {
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
struct Value {
|
|
||||||
value: i32,
|
|
||||||
}
|
|
||||||
impl Value {
|
|
||||||
fn new(value: i32) -> Self {
|
|
||||||
Self { value }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut tree = Tree::new(Value::new(1));
|
|
||||||
let parent = tree.root();
|
|
||||||
let child = tree.create_node(Value::new(0));
|
|
||||||
tree.add_child(parent, child);
|
|
||||||
|
|
||||||
let mut mapped = tree.map(|x| &x.value, |x| &mut x.value);
|
|
||||||
|
|
||||||
*mapped.get_mut(child).unwrap() = 1;
|
|
||||||
*mapped.get_mut(parent).unwrap() = 2;
|
|
||||||
|
|
||||||
assert_eq!(*tree.get(parent).unwrap(), Value::new(2));
|
|
||||||
assert_eq!(*tree.get(child).unwrap(), Value::new(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn traverse_depth_first() {
|
fn traverse_depth_first() {
|
||||||
let mut tree = Tree::new(0);
|
let mut tree = Tree::new(0);
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
node::NodeType,
|
node::{ElementNode, NodeType},
|
||||||
passes::{AnyMapLike, TypeErasedPass},
|
passes::{AnyMapLike, TypeErasedPass},
|
||||||
real_dom::RealDom,
|
real_dom::RealDom,
|
||||||
state::State,
|
state::State,
|
||||||
tree::TreeView,
|
tree::TreeView,
|
||||||
NodeId, RealNodeId,
|
NodeId,
|
||||||
};
|
};
|
||||||
use dioxus_core::{Mutation, Mutations};
|
use dioxus_core::{Mutation, Mutations};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
@@ -12,12 +12,12 @@ use std::fmt::Debug;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ElementProduced {
|
pub enum ElementProduced {
|
||||||
/// The iterator produced an element by progressing to the next node in a depth first order.
|
/// The iterator produced an element by progressing to the next node in a depth first order.
|
||||||
Progressed(RealNodeId),
|
Progressed(NodeId),
|
||||||
/// The iterator reached the end of the tree and looped back to the root
|
/// The iterator reached the end of the tree and looped back to the root
|
||||||
Looped(RealNodeId),
|
Looped(NodeId),
|
||||||
}
|
}
|
||||||
impl ElementProduced {
|
impl ElementProduced {
|
||||||
pub fn id(&self) -> RealNodeId {
|
pub fn id(&self) -> NodeId {
|
||||||
match self {
|
match self {
|
||||||
ElementProduced::Progressed(id) => *id,
|
ElementProduced::Progressed(id) => *id,
|
||||||
ElementProduced::Looped(id) => *id,
|
ElementProduced::Looped(id) => *id,
|
||||||
@@ -56,7 +56,7 @@ impl NodePosition {
|
|||||||
/// The iterator loops around when it reaches the end or the beginning.
|
/// The iterator loops around when it reaches the end or the beginning.
|
||||||
pub struct PersistantElementIter {
|
pub struct PersistantElementIter {
|
||||||
// stack of elements and fragments
|
// stack of elements and fragments
|
||||||
stack: smallvec::SmallVec<[(RealNodeId, NodePosition); 5]>,
|
stack: smallvec::SmallVec<[(NodeId, NodePosition); 5]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PersistantElementIter {
|
impl Default for PersistantElementIter {
|
||||||
@@ -141,7 +141,7 @@ impl PersistantElementIter {
|
|||||||
let (last, old_child_idx) = self.stack.last_mut().unwrap();
|
let (last, old_child_idx) = self.stack.last_mut().unwrap();
|
||||||
let node = &rdom[*last];
|
let node = &rdom[*last];
|
||||||
match &node.node_data.node_type {
|
match &node.node_data.node_type {
|
||||||
NodeType::Element { .. } => {
|
NodeType::Element(ElementNode { .. }) => {
|
||||||
let children = rdom.tree.children_ids(*last).unwrap();
|
let children = rdom.tree.children_ids(*last).unwrap();
|
||||||
*old_child_idx = old_child_idx.map(|i| i + 1);
|
*old_child_idx = old_child_idx.map(|i| i + 1);
|
||||||
// if we have children, go to the next child
|
// if we have children, go to the next child
|
||||||
@@ -151,7 +151,8 @@ impl PersistantElementIter {
|
|||||||
self.next(rdom)
|
self.next(rdom)
|
||||||
} else {
|
} else {
|
||||||
let id = children[child_idx];
|
let id = children[child_idx];
|
||||||
if let NodeType::Element { .. } = &rdom[id].node_data.node_type {
|
if let NodeType::Element(ElementNode { .. }) = &rdom[id].node_data.node_type
|
||||||
|
{
|
||||||
self.stack.push((id, NodePosition::AtNode));
|
self.stack.push((id, NodePosition::AtNode));
|
||||||
}
|
}
|
||||||
ElementProduced::Progressed(id)
|
ElementProduced::Progressed(id)
|
||||||
@@ -170,12 +171,12 @@ impl PersistantElementIter {
|
|||||||
pub fn prev<S: State + Send>(&mut self, rdom: &RealDom<S>) -> ElementProduced {
|
pub fn prev<S: State + Send>(&mut self, rdom: &RealDom<S>) -> ElementProduced {
|
||||||
// recursively add the last child element to the stack
|
// recursively add the last child element to the stack
|
||||||
fn push_back<S: State + Send>(
|
fn push_back<S: State + Send>(
|
||||||
stack: &mut smallvec::SmallVec<[(RealNodeId, NodePosition); 5]>,
|
stack: &mut smallvec::SmallVec<[(NodeId, NodePosition); 5]>,
|
||||||
new_node: RealNodeId,
|
new_node: NodeId,
|
||||||
rdom: &RealDom<S>,
|
rdom: &RealDom<S>,
|
||||||
) -> RealNodeId {
|
) -> NodeId {
|
||||||
match &rdom[new_node].node_data.node_type {
|
match &rdom[new_node].node_data.node_type {
|
||||||
NodeType::Element { .. } => {
|
NodeType::Element(ElementNode { .. }) => {
|
||||||
let children = rdom.tree.children_ids(new_node).unwrap();
|
let children = rdom.tree.children_ids(new_node).unwrap();
|
||||||
if children.is_empty() {
|
if children.is_empty() {
|
||||||
new_node
|
new_node
|
||||||
@@ -194,7 +195,7 @@ impl PersistantElementIter {
|
|||||||
let (last, old_child_idx) = self.stack.last_mut().unwrap();
|
let (last, old_child_idx) = self.stack.last_mut().unwrap();
|
||||||
let node = &rdom[*last];
|
let node = &rdom[*last];
|
||||||
match &node.node_data.node_type {
|
match &node.node_data.node_type {
|
||||||
NodeType::Element { .. } => {
|
NodeType::Element(ElementNode { .. }) => {
|
||||||
let children = rdom.tree.children_ids(*last).unwrap();
|
let children = rdom.tree.children_ids(*last).unwrap();
|
||||||
// if we have children, go to the next child
|
// if we have children, go to the next child
|
||||||
if let NodePosition::InChild(0) = old_child_idx {
|
if let NodePosition::InChild(0) = old_child_idx {
|
||||||
@@ -228,7 +229,7 @@ impl PersistantElementIter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop(&mut self) -> RealNodeId {
|
fn pop(&mut self) -> NodeId {
|
||||||
self.stack.pop().unwrap().0
|
self.stack.pop().unwrap().0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -280,68 +281,68 @@ fn traverse() {
|
|||||||
let div_tag = "div".to_string();
|
let div_tag = "div".to_string();
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&rdom[iter.next(&rdom).id()].node_data.node_type,
|
&rdom[iter.next(&rdom).id()].node_data.node_type,
|
||||||
NodeType::Element { tag: div_tag, .. }
|
NodeType::Element(ElementNode { tag: div_tag, .. })
|
||||||
));
|
));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&rdom[iter.next(&rdom).id()].node_data.node_type,
|
&rdom[iter.next(&rdom).id()].node_data.node_type,
|
||||||
NodeType::Element { tag: div_tag, .. }
|
NodeType::Element(ElementNode { tag: div_tag, .. })
|
||||||
));
|
));
|
||||||
let text1 = "hello".to_string();
|
let text1 = "hello".to_string();
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&rdom[iter.next(&rdom).id()].node_data.node_type,
|
&rdom[iter.next(&rdom).id()].node_data.node_type,
|
||||||
NodeType::Text { text: text1, .. }
|
NodeType::Text(text1)
|
||||||
));
|
));
|
||||||
let p_tag = "p".to_string();
|
let p_tag = "p".to_string();
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&rdom[iter.next(&rdom).id()].node_data.node_type,
|
&rdom[iter.next(&rdom).id()].node_data.node_type,
|
||||||
NodeType::Element { tag: p_tag, .. }
|
NodeType::Element(ElementNode { tag: p_tag, .. })
|
||||||
));
|
));
|
||||||
let text2 = "world".to_string();
|
let text2 = "world".to_string();
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&rdom[iter.next(&rdom).id()].node_data.node_type,
|
&rdom[iter.next(&rdom).id()].node_data.node_type,
|
||||||
NodeType::Text { text: text2, .. }
|
NodeType::Text(text2)
|
||||||
));
|
));
|
||||||
let text3 = "hello world".to_string();
|
let text3 = "hello world".to_string();
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&rdom[iter.next(&rdom).id()].node_data.node_type,
|
&rdom[iter.next(&rdom).id()].node_data.node_type,
|
||||||
NodeType::Text { text: text3, .. }
|
NodeType::Text(text3)
|
||||||
));
|
));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&rdom[iter.next(&rdom).id()].node_data.node_type,
|
&rdom[iter.next(&rdom).id()].node_data.node_type,
|
||||||
NodeType::Element { tag: div_tag, .. }
|
NodeType::Element(ElementNode { tag: div_tag, .. })
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&rdom[iter.prev(&rdom).id()].node_data.node_type,
|
&rdom[iter.prev(&rdom).id()].node_data.node_type,
|
||||||
NodeType::Text { text: text3, .. }
|
NodeType::Text(text3)
|
||||||
));
|
));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&rdom[iter.prev(&rdom).id()].node_data.node_type,
|
&rdom[iter.prev(&rdom).id()].node_data.node_type,
|
||||||
NodeType::Text { text: text2, .. }
|
NodeType::Text(text2)
|
||||||
));
|
));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&rdom[iter.prev(&rdom).id()].node_data.node_type,
|
&rdom[iter.prev(&rdom).id()].node_data.node_type,
|
||||||
NodeType::Element { tag: p_tag, .. }
|
NodeType::Element(ElementNode { tag: p_tag, .. })
|
||||||
));
|
));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&rdom[iter.prev(&rdom).id()].node_data.node_type,
|
&rdom[iter.prev(&rdom).id()].node_data.node_type,
|
||||||
NodeType::Text { text: text1, .. }
|
NodeType::Text(text1)
|
||||||
));
|
));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&rdom[iter.prev(&rdom).id()].node_data.node_type,
|
&rdom[iter.prev(&rdom).id()].node_data.node_type,
|
||||||
NodeType::Element { tag: div_tag, .. }
|
NodeType::Element(ElementNode { tag: div_tag, .. })
|
||||||
));
|
));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&rdom[iter.prev(&rdom).id()].node_data.node_type,
|
&rdom[iter.prev(&rdom).id()].node_data.node_type,
|
||||||
NodeType::Element { tag: div_tag, .. }
|
NodeType::Element(ElementNode { tag: div_tag, .. })
|
||||||
));
|
));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&rdom[iter.prev(&rdom).id()].node_data.node_type,
|
&rdom[iter.prev(&rdom).id()].node_data.node_type,
|
||||||
NodeType::Element { tag: div_tag, .. }
|
NodeType::Element(ElementNode { tag: div_tag, .. })
|
||||||
));
|
));
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&rdom[iter.prev(&rdom).id()].node_data.node_type,
|
&rdom[iter.prev(&rdom).id()].node_data.node_type,
|
||||||
NodeType::Text { text: text3, .. }
|
NodeType::Text(text3)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,14 +417,14 @@ fn persist_removes() {
|
|||||||
dbg!(&rdom[idx].node_data.node_type);
|
dbg!(&rdom[idx].node_data.node_type);
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&rdom[idx].node_data.node_type,
|
&rdom[idx].node_data.node_type,
|
||||||
NodeType::Element { tag: root_tag, .. }
|
NodeType::Element(ElementNode { tag: root_tag, .. })
|
||||||
));
|
));
|
||||||
|
|
||||||
let idx = iter2.next(&rdom).id();
|
let idx = iter2.next(&rdom).id();
|
||||||
dbg!(&rdom[idx].node_data.node_type);
|
dbg!(&rdom[idx].node_data.node_type);
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&rdom[idx].node_data.node_type,
|
&rdom[idx].node_data.node_type,
|
||||||
NodeType::Element { tag: root_tag, .. }
|
NodeType::Element(ElementNode { tag: root_tag, .. })
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -479,7 +480,7 @@ fn persist_instertions_before() {
|
|||||||
let idx = iter.next(&rdom).id();
|
let idx = iter.next(&rdom).id();
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&rdom[idx].node_data.node_type,
|
&rdom[idx].node_data.node_type,
|
||||||
NodeType::Element { tag: p_tag, .. }
|
NodeType::Element(ElementNode { tag: p_tag, .. })
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -534,12 +535,12 @@ fn persist_instertions_after() {
|
|||||||
let idx = iter.next(&rdom).id();
|
let idx = iter.next(&rdom).id();
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&rdom[idx].node_data.node_type,
|
&rdom[idx].node_data.node_type,
|
||||||
NodeType::Element { tag: p_tag, .. }
|
NodeType::Element(ElementNode { tag: p_tag, .. })
|
||||||
));
|
));
|
||||||
let text = "hello world".to_string();
|
let text = "hello world".to_string();
|
||||||
let idx = iter.next(&rdom).id();
|
let idx = iter.next(&rdom).id();
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
&rdom[idx].node_data.node_type,
|
&rdom[idx].node_data.node_type,
|
||||||
NodeType::Text { text, .. }
|
NodeType::Text(text)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@ use crate::{node::PreventDefault, TuiDom};
|
|||||||
use dioxus_native_core::{
|
use dioxus_native_core::{
|
||||||
tree::TreeView,
|
tree::TreeView,
|
||||||
utils::{ElementProduced, PersistantElementIter},
|
utils::{ElementProduced, PersistantElementIter},
|
||||||
RealNodeId,
|
NodeId,
|
||||||
};
|
};
|
||||||
use dioxus_native_core_macro::sorted_str_slice;
|
use dioxus_native_core_macro::sorted_str_slice;
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ const FOCUS_ATTRIBUTES: &[&str] = &sorted_str_slice!(["tabindex"]);
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub(crate) struct FocusState {
|
pub(crate) struct FocusState {
|
||||||
pub(crate) focus_iter: PersistantElementIter,
|
pub(crate) focus_iter: PersistantElementIter,
|
||||||
pub(crate) last_focused_id: Option<RealNodeId>,
|
pub(crate) last_focused_id: Option<NodeId>,
|
||||||
pub(crate) focus_level: FocusLevel,
|
pub(crate) focus_level: FocusLevel,
|
||||||
pub(crate) dirty: bool,
|
pub(crate) dirty: bool,
|
||||||
}
|
}
|
||||||
@@ -236,11 +236,7 @@ impl FocusState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn prune(&mut self, mutations: &dioxus_core::Mutations, rdom: &TuiDom) {
|
pub(crate) fn prune(&mut self, mutations: &dioxus_core::Mutations, rdom: &TuiDom) {
|
||||||
fn remove_children(
|
fn remove_children(to_prune: &mut [&mut Option<NodeId>], rdom: &TuiDom, removed: NodeId) {
|
||||||
to_prune: &mut [&mut Option<RealNodeId>],
|
|
||||||
rdom: &TuiDom,
|
|
||||||
removed: RealNodeId,
|
|
||||||
) {
|
|
||||||
for opt in to_prune.iter_mut() {
|
for opt in to_prune.iter_mut() {
|
||||||
if let Some(id) = opt {
|
if let Some(id) = opt {
|
||||||
if *id == removed {
|
if *id == removed {
|
||||||
@@ -274,7 +270,7 @@ impl FocusState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_focus(&mut self, rdom: &mut TuiDom, id: RealNodeId) {
|
pub(crate) fn set_focus(&mut self, rdom: &mut TuiDom, id: NodeId) {
|
||||||
if let Some(old) = self.last_focused_id.replace(id) {
|
if let Some(old) = self.last_focused_id.replace(id) {
|
||||||
rdom[old].state.focused = false;
|
rdom[old].state.focused = false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user