From 6fe00c4f78145dfccae7ab186894d7efca55d17d Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sat, 4 Feb 2023 17:56:30 -0600 Subject: [PATCH] make dioxus dependancy optional --- packages/native-core/Cargo.toml | 10 +- packages/native-core/src/dioxus.rs | 254 +++++++ packages/native-core/src/lib.rs | 38 +- packages/native-core/src/node.rs | 52 +- packages/native-core/src/node_ref.rs | 26 +- packages/native-core/src/passes.rs | 717 +----------------- packages/native-core/src/real_dom.rs | 491 ++++-------- packages/native-core/src/tree.rs | 14 +- packages/native-core/src/utils/cursor.rs | 112 +-- packages/native-core/src/utils/mod.rs | 4 +- .../src/utils/persistant_iterator.rs | 9 +- packages/native-core/tests/passes.rs | 620 +++++++++++++++ 12 files changed, 1152 insertions(+), 1195 deletions(-) create mode 100644 packages/native-core/src/dioxus.rs create mode 100644 packages/native-core/tests/passes.rs diff --git a/packages/native-core/Cargo.toml b/packages/native-core/Cargo.toml index 370e85d36..ee2a3b912 100644 --- a/packages/native-core/Cargo.toml +++ b/packages/native-core/Cargo.toml @@ -11,10 +11,9 @@ keywords = ["dom", "ui", "gui", "react"] [dependencies] -dioxus-core = { path = "../core", version = "^0.3.0" } -dioxus-html = { path = "../html", version = "^0.3.0" } -dioxus-core-macro = { path = "../core-macro", version = "^0.3.0" } +dioxus-core = { path = "../core", version = "^0.3.0", optional = true } +keyboard-types = "0.6.2" taffy = "0.2.1" smallvec = "1.6" rustc-hash = "1.1.0" @@ -34,3 +33,8 @@ rayon = "1.6.1" rand = "0.8.5" dioxus = { path = "../dioxus", version = "^0.3.0" } tokio = { version = "*", features = ["full"] } +dioxus-native-core = { path = ".", features = ["dioxus"] } + +[features] +default = ["dioxus"] +dioxus = ["dioxus-core"] \ No newline at end of file diff --git a/packages/native-core/src/dioxus.rs b/packages/native-core/src/dioxus.rs new file mode 100644 index 000000000..6170be0d2 --- /dev/null +++ b/packages/native-core/src/dioxus.rs @@ -0,0 +1,254 @@ +use dioxus_core::{BorrowedAttributeValue, ElementId, Mutations, TemplateNode}; +use rustc_hash::{FxHashMap, FxHashSet}; + +use crate::{ + node::{ElementNode, FromAnyValue, NodeType, OwnedAttributeDiscription, OwnedAttributeValue}, + prelude::{NodeImmutable, NodeMutable}, + real_dom::NodeTypeMut, + NodeId, NodeMut, RealDom, +}; + +pub struct DioxusState { + templates: FxHashMap>, + stack: Vec, + node_id_mapping: Vec>, +} + +impl DioxusState { + pub fn new(rdom: &mut RealDom) -> Self { + rdom.insert_slab::(); + let root_id = rdom.root_id(); + let mut root = rdom.get_mut(root_id).unwrap(); + root.insert(ElementId(0)); + Self { + templates: FxHashMap::default(), + stack: vec![root_id], + node_id_mapping: vec![Some(root_id)], + } + } + + pub fn element_to_node_id(&self, element_id: ElementId) -> NodeId { + self.node_id_mapping.get(element_id.0).unwrap().unwrap() + } + + fn set_element_id(&mut self, mut node: NodeMut, element_id: ElementId) { + let node_id = node.id(); + node.insert(element_id); + if self.node_id_mapping.len() <= element_id.0 { + self.node_id_mapping.resize(element_id.0 + 1, None); + } + self.node_id_mapping[element_id.0] = Some(node_id); + } + + pub fn load_child(&self, rdom: &RealDom, path: &[u8]) -> NodeId { + let mut current = rdom.get(*self.stack.last().unwrap()).unwrap(); + for i in path { + let new_id = current.child_ids().unwrap()[*i as usize]; + current = rdom.get(new_id).unwrap(); + } + current.id() + } + + /// 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(&mut self, rdom: &mut RealDom, mutations: Mutations) { + for template in mutations.templates { + let mut template_root_ids = Vec::new(); + for root in template.roots { + let id = create_template_node(rdom, root); + template_root_ids.push(id); + } + self.templates + .insert(template.name.to_string(), template_root_ids); + } + + for e in mutations.edits { + use dioxus_core::Mutation::*; + match e { + AppendChildren { id, m } => { + let children = self.stack.split_off(self.stack.len() - m); + let parent = self.element_to_node_id(id); + for child in children { + rdom.add_child(parent, child); + } + } + AssignId { path, id } => { + let node_id = self.load_child(rdom, path); + self.set_element_id(rdom.get_mut(node_id).unwrap(), id); + } + CreatePlaceholder { id } => { + let node = NodeType::Placeholder; + let node = rdom.create_node(node, true); + let node_id = node.id(); + self.set_element_id(node, id); + self.stack.push(node_id); + } + CreateTextNode { value, id } => { + let node_data = NodeType::Text(value.to_string()); + let node = rdom.create_node(node_data, true); + let node_id = node.id(); + self.set_element_id(node, id); + self.stack.push(node_id); + } + HydrateText { path, value, id } => { + let node_id = self.load_child(rdom, path); + let node = rdom.get_mut(node_id).unwrap(); + self.set_element_id(node, id); + let mut node = rdom.get_mut(node_id).unwrap(); + if let NodeTypeMut::Text(text) = node.node_type_mut() { + *text = value.to_string(); + } else { + node.set_type(NodeType::Text(value.to_string())); + } + } + LoadTemplate { name, index, id } => { + let template_id = self.templates[name][index]; + let clone_id = rdom.clone_node(template_id); + let clone = rdom.get_mut(clone_id).unwrap(); + self.set_element_id(clone, id); + self.stack.push(clone_id); + } + ReplaceWith { id, m } => { + let new_nodes = self.stack.split_off(self.stack.len() - m); + let old_node_id = self.element_to_node_id(id); + for new in new_nodes { + let mut node = rdom.get_mut(new).unwrap(); + node.insert_before(old_node_id); + } + rdom.remove(old_node_id); + } + ReplacePlaceholder { path, m } => { + let new_nodes = self.stack.split_off(self.stack.len() - m); + let old_node_id = self.load_child(rdom, path); + for new in new_nodes { + let mut node = rdom.get_mut(new).unwrap(); + node.insert_before(old_node_id); + } + rdom.remove(old_node_id); + } + InsertAfter { id, m } => { + let new_nodes = self.stack.split_off(self.stack.len() - m); + let old_node_id = self.element_to_node_id(id); + for new in new_nodes.into_iter().rev() { + let mut node = rdom.get_mut(new).unwrap(); + node.insert_after(old_node_id); + } + } + InsertBefore { id, m } => { + let new_nodes = self.stack.split_off(self.stack.len() - m); + let old_node_id = self.element_to_node_id(id); + for new in new_nodes { + rdom.tree.insert_before(old_node_id, new); + } + } + SetAttribute { + name, + value, + id, + ns, + } => { + let node_id = self.element_to_node_id(id); + let mut node = rdom.get_mut(node_id).unwrap(); + if let NodeTypeMut::Element(element) = &mut node.node_type_mut() { + if let BorrowedAttributeValue::None = &value { + element.remove_attributes(&OwnedAttributeDiscription { + name: name.to_string(), + namespace: ns.map(|s| s.to_string()), + volatile: false, + }); + } else { + element.set_attribute( + OwnedAttributeDiscription { + name: name.to_string(), + namespace: ns.map(|s| s.to_string()), + volatile: false, + }, + OwnedAttributeValue::from(value), + ); + } + } + } + SetText { value, id } => { + let node_id = self.element_to_node_id(id); + let mut node = rdom.get_mut(node_id).unwrap(); + if let NodeTypeMut::Text(text) = node.node_type_mut() { + *text = value.to_string(); + } + } + NewEventListener { name, id } => { + let node_id = self.element_to_node_id(id); + let mut node = rdom.get_mut(node_id).unwrap(); + node.add_event_listener(name); + } + RemoveEventListener { id, name } => { + let node_id = self.element_to_node_id(id); + let mut node = rdom.get_mut(node_id).unwrap(); + node.remove_event_listener(name); + } + Remove { id } => { + let node_id = self.element_to_node_id(id); + rdom.remove(node_id); + } + PushRoot { id } => { + let node_id = self.element_to_node_id(id); + self.stack.push(node_id); + } + } + } + } +} + +fn create_template_node(rdom: &mut RealDom, node: &TemplateNode) -> NodeId { + match node { + TemplateNode::Element { + tag, + namespace, + attrs, + children, + } => { + let node = NodeType::Element(ElementNode { + tag: tag.to_string(), + namespace: namespace.map(|s| s.to_string()), + attributes: attrs + .iter() + .filter_map(|attr| match attr { + dioxus_core::TemplateAttribute::Static { + name, + value, + namespace, + } => Some(( + OwnedAttributeDiscription { + namespace: namespace.map(|s| s.to_string()), + name: name.to_string(), + volatile: false, + }, + OwnedAttributeValue::Text(value.to_string()), + )), + dioxus_core::TemplateAttribute::Dynamic { .. } => None, + }) + .collect(), + listeners: FxHashSet::default(), + }); + let node_id = rdom.create_node(node, true).id(); + for child in *children { + let child_id = create_template_node(rdom, child); + rdom.add_child(node_id, child_id); + } + node_id + } + TemplateNode::Text { text } => rdom + .create_node(NodeType::Text(text.to_string()), true) + .id(), + TemplateNode::Dynamic { .. } => rdom.create_node(NodeType::Placeholder, true).id(), + TemplateNode::DynamicText { .. } => { + rdom.create_node(NodeType::Text(String::new()), true).id() + } + } +} + +trait NodeImmutableDioxusExt: NodeImmutable { + fn mounted_id(&self) -> Option { + self.get().copied() + } +} + +impl, V: FromAnyValue + Send + Sync> NodeImmutableDioxusExt for T {} diff --git a/packages/native-core/src/lib.rs b/packages/native-core/src/lib.rs index c54daab10..5e07f68aa 100644 --- a/packages/native-core/src/lib.rs +++ b/packages/native-core/src/lib.rs @@ -8,6 +8,8 @@ pub use real_dom::{NodeMut, NodeRef, RealDom}; use rustc_hash::FxHasher; pub use tree::NodeId; +#[cfg(feature = "dioxus")] +pub mod dioxus; pub mod layout_attributes; pub mod node; pub mod node_ref; @@ -16,33 +18,15 @@ pub mod real_dom; pub mod tree; pub mod utils; +pub mod prelude { + pub use crate::node::{ElementNode, FromAnyValue, NodeType, OwnedAttributeView}; + pub use crate::node_ref::{AttributeMaskBuilder, NodeMaskBuilder, NodeView}; + pub use crate::passes::{Dependancy, Pass}; + pub use crate::real_dom::{NodeImmutable, NodeMut, NodeMutRaw, NodeMutable, NodeRef, RealDom}; + pub use crate::tree::NodeId; + pub use crate::SendAnyMap; +} + pub type FxDashMap = dashmap::DashMap>; pub type FxDashSet = dashmap::DashSet>; pub type SendAnyMap = anymap::Map; - -/// Used in derived state macros -#[derive(Eq, PartialEq)] -#[doc(hidden)] -pub struct HeightOrdering { - pub height: u16, - pub id: NodeId, -} - -impl HeightOrdering { - pub fn new(height: u16, id: NodeId) -> Self { - HeightOrdering { height, id } - } -} - -// not the ordering after height is just for deduplication it can be any ordering as long as it is consistent -impl Ord for HeightOrdering { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.height.cmp(&other.height).then(self.id.cmp(&other.id)) - } -} - -impl PartialOrd for HeightOrdering { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} diff --git a/packages/native-core/src/node.rs b/packages/native-core/src/node.rs index 7eb0fb31e..f0fe7073a 100644 --- a/packages/native-core/src/node.rs +++ b/packages/native-core/src/node.rs @@ -1,20 +1,8 @@ -use crate::tree::NodeId; -use dioxus_core::{AnyValue, BorrowedAttributeValue, ElementId}; use rustc_hash::{FxHashMap, FxHashSet}; -use std::fmt::Debug; +use std::{any::Any, fmt::Debug}; #[derive(Debug, Clone)] -pub struct NodeData { - /// The id of the node - pub node_id: NodeId, - /// The id of the node in the vdom. - pub element_id: Option, - /// Additional inforation specific to the node type - pub node_type: NodeType, -} - -#[derive(Debug, Clone)] -pub struct ElementNode { +pub struct ElementNode { pub tag: String, pub namespace: Option, pub attributes: FxHashMap>, @@ -29,21 +17,6 @@ pub enum NodeType { Placeholder, } -impl NodeData { - pub(crate) fn new(node_type: NodeType) -> Self { - NodeData { - element_id: None, - node_type, - node_id: NodeId(0), - } - } - - /// get the mounted id of the node - pub fn mounted_id(&self) -> Option { - self.element_id - } -} - #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct OwnedAttributeDiscription { pub name: String, @@ -72,11 +45,11 @@ pub enum OwnedAttributeValue { } pub trait FromAnyValue: Clone + 'static { - fn from_any_value(value: &dyn AnyValue) -> Self; + fn from_any_value(value: &dyn Any) -> Self; } impl FromAnyValue for () { - fn from_any_value(_: &dyn AnyValue) -> Self {} + fn from_any_value(_: &dyn Any) -> Self {} } impl Debug for OwnedAttributeValue { @@ -91,15 +64,16 @@ impl Debug for OwnedAttributeValue { } } -impl From> for OwnedAttributeValue { - fn from(value: BorrowedAttributeValue<'_>) -> Self { +#[cfg(feature = "dioxus")] +impl From> for OwnedAttributeValue { + fn from(value: dioxus_core::BorrowedAttributeValue<'_>) -> Self { match value { - BorrowedAttributeValue::Text(text) => Self::Text(text.to_string()), - BorrowedAttributeValue::Float(float) => Self::Float(float), - BorrowedAttributeValue::Int(int) => Self::Int(int), - BorrowedAttributeValue::Bool(bool) => Self::Bool(bool), - BorrowedAttributeValue::Any(any) => Self::Custom(V::from_any_value(&*any)), - BorrowedAttributeValue::None => panic!("None attribute values result in removing the attribute, not converting it to a None value.") + dioxus_core::BorrowedAttributeValue::Text(text) => Self::Text(text.to_string()), + dioxus_core::BorrowedAttributeValue::Float(float) => Self::Float(float), + dioxus_core::BorrowedAttributeValue::Int(int) => Self::Int(int), + dioxus_core::BorrowedAttributeValue::Bool(bool) => Self::Bool(bool), + dioxus_core::BorrowedAttributeValue::Any(any) => Self::Custom(V::from_any_value(any.as_any())), + dioxus_core::BorrowedAttributeValue::None => panic!("None attribute values result in removing the attribute, not converting it to a None value.") } } } diff --git a/packages/native-core/src/node_ref.rs b/packages/native-core/src/node_ref.rs index f0e094cdd..d8fc309be 100644 --- a/packages/native-core/src/node_ref.rs +++ b/packages/native-core/src/node_ref.rs @@ -1,42 +1,38 @@ -use dioxus_core::ElementId; use rustc_hash::FxHashSet; use crate::{ - node::{ElementNode, FromAnyValue, NodeData, NodeType, OwnedAttributeView}, + node::{ElementNode, FromAnyValue, NodeType, OwnedAttributeView}, NodeId, }; /// A view into a [VNode] with limited access. #[derive(Debug)] pub struct NodeView<'a, V: FromAnyValue = ()> { - inner: &'a NodeData, + id: NodeId, + inner: &'a NodeType, mask: &'a NodeMask, } impl<'a, V: FromAnyValue> NodeView<'a, V> { /// Create a new NodeView from a VNode, and mask. - pub fn new(node: &'a NodeData, view: &'a NodeMask) -> Self { + pub fn new(id: NodeId, node: &'a NodeType, view: &'a NodeMask) -> Self { Self { inner: node, mask: view, + id, } } - /// Get the id of the node - pub fn id(&self) -> Option { - self.inner.element_id - } - /// Get the node id of the node pub fn node_id(&self) -> NodeId { - self.inner.node_id + self.id } /// Get the tag of the node if the tag is enabled in the mask pub fn tag(&self) -> Option<&'a str> { self.mask .tag - .then_some(match &self.inner.node_type { + .then_some(match &self.inner { NodeType::Element(ElementNode { tag, .. }) => Some(&**tag), _ => None, }) @@ -47,7 +43,7 @@ impl<'a, V: FromAnyValue> NodeView<'a, V> { pub fn namespace(&self) -> Option<&'a str> { self.mask .namespace - .then_some(match &self.inner.node_type { + .then_some(match &self.inner { NodeType::Element(ElementNode { namespace, .. }) => namespace.as_deref(), _ => None, }) @@ -58,7 +54,7 @@ impl<'a, V: FromAnyValue> NodeView<'a, V> { pub fn attributes<'b>( &'b self, ) -> Option> + 'b> { - match &self.inner.node_type { + match &self.inner { NodeType::Element(ElementNode { attributes, .. }) => Some( attributes .iter() @@ -76,7 +72,7 @@ impl<'a, V: FromAnyValue> NodeView<'a, V> { pub fn text(&self) -> Option<&str> { self.mask .text - .then_some(match &self.inner.node_type { + .then_some(match &self.inner { NodeType::Text(text) => Some(&**text), _ => None, }) @@ -86,7 +82,7 @@ impl<'a, V: FromAnyValue> NodeView<'a, V> { /// Get the listeners if it is enabled in the mask pub fn listeners(&self) -> Option + '_> { if self.mask.listeners { - match &self.inner.node_type { + match &self.inner { NodeType::Element(ElementNode { listeners, .. }) => { Some(listeners.iter().map(|l| &**l)) } diff --git a/packages/native-core/src/passes.rs b/packages/native-core/src/passes.rs index b7c3de826..f5a66aaad 100644 --- a/packages/native-core/src/passes.rs +++ b/packages/native-core/src/passes.rs @@ -7,7 +7,7 @@ use std::collections::BTreeMap; use std::marker::PhantomData; use std::sync::Arc; -use crate::node::{FromAnyValue, NodeData}; +use crate::node::{FromAnyValue, NodeType}; use crate::node_ref::{NodeMaskBuilder, NodeView}; use crate::real_dom::RealDom; use crate::tree::{SlabEntry, Tree, TreeStateView}; @@ -129,26 +129,35 @@ pub trait Pass: Any + Send + Sync { ) -> Self; fn validate() { - // no type can be a child and parent dependency - for type_id in Self::parent_type_ids().iter().copied() { - for type_id2 in Self::child_type_ids().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().iter().copied() { if type_id == TypeId::of::() { panic!("The current type cannot be a node dependency"); } } + // this type cannot be both a parent and child dependency + assert!( + Self::parent_type_ids() + .iter() + .any(|type_id| *type_id != TypeId::of::()) + && Self::child_type_ids() + .iter() + .any(|type_id| *type_id != TypeId::of::()), + "The current type cannot be a parent and child dependency" + ); // no states have the same type id - if Self::all_dependanices() + if Self::child_type_ids() .iter() - .collect::>() + .collect::>() .len() - != Self::all_dependanices().len() + != Self::child_type_ids().len() + || Self::parent_type_ids() + .iter() + .collect::>() + .len() + != Self::parent_type_ids().len() + || Self::node_type_ids().iter().collect::>().len() + != Self::node_type_ids().len() { panic!("all states must have unique type ids"); } @@ -178,28 +187,21 @@ pub trait Pass: Any + Send + Sync { let myself: SlabEntry<'static, Self> = unsafe { std::mem::transmute(tree.get_slab_mut::().unwrap().entry(node_id)) }; - let node_data = tree.get_single::>(node_id).unwrap(); + let node_data = tree.get_single::>(node_id).unwrap(); let node = tree.get::(node_id).unwrap(); let children = tree.children::(node_id); let parent = tree.parent::(node_id); + let view = NodeView::new(node_id, node_data, &node_mask); if myself.value.is_none() { - *myself.value = Some(Self::create( - NodeView::new(node_data, &node_mask), - node, - parent, - children, - context, - )); + *myself.value = Some(Self::create(view, node, parent, children, context)); true } else { - myself.value.as_mut().unwrap().pass( - NodeView::new(node_data, &node_mask), - node, - parent, - children, - context, - ) + myself + .value + .as_mut() + .unwrap() + .pass(view, node, parent, children, context) } }, ) as PassCallback, @@ -409,7 +411,7 @@ pub fn resolve_passes( .iter() .filter(|id| **id != pass.this_type_id) .copied() - .chain(std::iter::once(TypeId::of::>())), + .chain(std::iter::once(TypeId::of::>())), [pass.this_type_id], ); let dirty_nodes = dirty_nodes.clone(); @@ -432,662 +434,3 @@ pub fn resolve_passes( } std::sync::Arc::try_unwrap(nodes_updated).unwrap() } - -// #[test] -// fn node_pass() { -// use crate::real_dom::RealDom; -// use crate::tree::{Tree, TreeLike}; - -// #[derive(Debug, Default, Clone, PartialEq)] -// struct Number(i32); - -// impl State for Number { -// fn create_passes() -> Box<[TypeErasedPass]> { -// Box::new([Number::to_type_erased()]) -// } -// } - -// impl AnyMapLike for Number { -// fn get(&self) -> Option<&T> { -// if TypeId::of::() == TypeId::of::() { -// Some(unsafe { &*(self as *const Self as *const T) }) -// } else { -// None -// } -// } - -// fn get_mut(&mut self) -> Option<&mut T> { -// if TypeId::of::() == TypeId::of::() { -// Some(unsafe { &mut *(self as *mut Self as *mut T) }) -// } else { -// None -// } -// } -// } - -// impl Pass for Number { -// type ChildDependencies = (); -// type NodeDependencies = (); -// type ParentDependencies = (); -// type Ctx = (); -// const MASK: NodeMask = NodeMask::new(); - -// fn pass<'a>( -// &mut self, -// node_view: NodeView, -// node: ::ElementBorrowed<'a>, -// parent: Option<::ElementBorrowed<'a>>, -// children: Option< -// impl Iterator::ElementBorrowed<'a>>, -// >, -// context: ::ElementBorrowed<'a>, -// ) -> bool { -// self.0 += 1; -// true -// } -// } - -// let mut tree: RealDom = RealDom::new(); -// tree.dirty_nodes.insert(TypeId::of::(), NodeId(0)); -// tree.update_state(SendAnyMap::new()); - -// assert_eq!(tree.get(tree.root()).unwrap().state.0, 1); -// } - -// #[test] -// fn dependant_node_pass() { -// use crate::real_dom::RealDom; - -// #[derive(Debug, Default, Clone, PartialEq)] -// struct AddNumber(i32); - -// impl Pass for AddNumber { -// type ChildDependencies = (); -// type NodeDependencies = (SubtractNumber,); -// type ParentDependencies = (); -// type Ctx = (); -// const MASK: NodeMask = NodeMask::new(); - -// fn pass<'a>( -// &mut self, -// node_view: NodeView, -// node: ::ElementBorrowed<'a>, -// parent: Option<::ElementBorrowed<'a>>, -// children: Option< -// impl Iterator::ElementBorrowed<'a>>, -// >, -// context: ::ElementBorrowed<'a>, -// ) -> bool { -// self.0 += 1; -// true -// } -// } - -// #[derive(Debug, Default, Clone, PartialEq)] -// struct SubtractNumber(i32); - -// impl Pass for SubtractNumber { -// type ChildDependencies = (); -// type NodeDependencies = (); -// type ParentDependencies = (); -// type Ctx = (); -// const MASK: NodeMask = NodeMask::new(); - -// fn pass<'a>( -// &mut self, -// node_view: NodeView, -// node: ::ElementBorrowed<'a>, -// parent: Option<::ElementBorrowed<'a>>, -// children: Option< -// impl Iterator::ElementBorrowed<'a>>, -// >, -// context: ::ElementBorrowed<'a>, -// ) -> bool { -// self.0 -= 1; -// true -// } -// } - -// #[derive(Debug, Default, Clone, PartialEq)] -// struct NumberState { -// add_number: AddNumber, -// subtract_number: SubtractNumber, -// } - -// impl AnyMapLike for NumberState { -// fn get(&self) -> Option<&T> { -// if TypeId::of::() == TypeId::of::() { -// Some(unsafe { &*(&self.add_number as *const AddNumber as *const T) }) -// } else if TypeId::of::() == TypeId::of::() { -// Some(unsafe { &*(&self.subtract_number as *const SubtractNumber as *const T) }) -// } else { -// None -// } -// } - -// fn get_mut(&mut self) -> Option<&mut T> { -// if TypeId::of::() == TypeId::of::() { -// Some(unsafe { &mut *(&mut self.add_number as *mut AddNumber as *mut T) }) -// } else if TypeId::of::() == TypeId::of::() { -// Some(unsafe { &mut *(&mut self.subtract_number as *mut SubtractNumber as *mut T) }) -// } else { -// None -// } -// } -// } - -// impl State for NumberState { -// fn create_passes() -> Box<[TypeErasedPass]> { -// Box::new([ -// AddNumber::to_type_erased(), -// SubtractNumber::to_type_erased(), -// ]) -// } -// } - -// let mut tree: RealDom = RealDom::new(); -// tree.dirty_nodes -// .insert(TypeId::of::(), NodeId(0)); -// tree.update_state(dirty_nodes, SendAnyMap::new()); - -// assert_eq!( -// tree.get(tree.root()).unwrap().state, -// NumberState { -// add_number: AddNumber(1), -// subtract_number: SubtractNumber(-1) -// } -// ); -// } - -// #[test] -// fn independant_node_pass() { -// use crate::real_dom::RealDom; -// use crate::tree::{Tree, TreeLike}; - -// #[derive(Debug, Default, Clone, PartialEq)] -// struct AddNumber(i32); - -// impl Pass for AddNumber { -// type ChildDependencies = (); -// type NodeDependencies = (); -// type ParentDependencies = (); -// type Ctx = (); -// const MASK: NodeMask = NodeMask::new(); - -// fn pass<'a>( -// &mut self, -// node_view: NodeView, -// node: ::ElementBorrowed<'a>, -// parent: Option<::ElementBorrowed<'a>>, -// children: Option< -// impl Iterator::ElementBorrowed<'a>>, -// >, -// context: ::ElementBorrowed<'a>, -// ) -> bool { -// self.0 += 1; -// true -// } -// } - -// #[derive(Debug, Default, Clone, PartialEq)] -// struct SubtractNumber(i32); - -// impl Pass for SubtractNumber { -// type ChildDependencies = (); -// type NodeDependencies = (); -// type ParentDependencies = (); -// type Ctx = (); -// const MASK: NodeMask = NodeMask::new(); - -// fn pass<'a>( -// &mut self, -// node_view: NodeView, -// node: ::ElementBorrowed<'a>, -// parent: Option<::ElementBorrowed<'a>>, -// children: Option< -// impl Iterator::ElementBorrowed<'a>>, -// >, -// context: ::ElementBorrowed<'a>, -// ) -> bool { -// self.0 -= 1; -// true -// } -// } - -// #[derive(Debug, Default, Clone, PartialEq)] -// struct NumberState { -// add_number: AddNumber, -// subtract_number: SubtractNumber, -// } - -// impl AnyMapLike for NumberState { -// fn get(&self) -> Option<&T> { -// if TypeId::of::() == TypeId::of::() { -// Some(unsafe { &*(&self.add_number as *const AddNumber as *const T) }) -// } else if TypeId::of::() == TypeId::of::() { -// Some(unsafe { &*(&self.subtract_number as *const SubtractNumber as *const T) }) -// } else { -// None -// } -// } - -// fn get_mut(&mut self) -> Option<&mut T> { -// if TypeId::of::() == TypeId::of::() { -// Some(unsafe { &mut *(&mut self.add_number as *mut AddNumber as *mut T) }) -// } else if TypeId::of::() == TypeId::of::() { -// Some(unsafe { &mut *(&mut self.subtract_number as *mut SubtractNumber as *mut T) }) -// } else { -// None -// } -// } -// } - -// impl State for NumberState { -// fn create_passes() -> Box<[TypeErasedPass]> { -// Box::new([ -// AddNumber::to_type_erased(), -// SubtractNumber::to_type_erased(), -// ]) -// } -// } - -// let mut tree: RealDom = RealDom::new(); -// tree.dirty_nodes -// .insert(TypeId::of::(), NodeId(0)); -// tree.update_state(SendAnyMap::new()); - -// assert_eq!( -// tree.get(tree.root()).unwrap().state, -// NumberState { -// add_number: AddNumber(0), -// subtract_number: SubtractNumber(-1) -// } -// ); -// } - -// #[test] -// fn down_pass() { -// use crate::real_dom::RealDom; -// use crate::tree::{Tree, TreeLike}; - -// #[derive(Debug, Default, Clone, PartialEq)] -// struct AddNumber(i32); - -// impl Pass for AddNumber { -// type ChildDependencies = (); -// type NodeDependencies = (); -// type ParentDependencies = (AddNumber,); -// type Ctx = (); -// const MASK: NodeMask = NodeMask::new(); - -// fn pass<'a>( -// &mut self, -// node_view: NodeView, -// node: ::ElementBorrowed<'a>, -// parent: Option<::ElementBorrowed<'a>>, -// children: Option< -// impl Iterator::ElementBorrowed<'a>>, -// >, -// context: ::ElementBorrowed<'a>, -// ) -> bool { -// if let Some((parent,)) = parent { -// *self.0 += *parent.0; -// } -// true -// } -// } - -// #[derive(Debug, Default, Clone, PartialEq)] -// struct NumberState { -// add_number: AddNumber, -// } - -// impl AnyMapLike for NumberState { -// fn get(&self) -> Option<&T> { -// if TypeId::of::() == TypeId::of::() { -// Some(unsafe { &*(&self.add_number as *const AddNumber as *const T) }) -// } else { -// None -// } -// } - -// fn get_mut(&mut self) -> Option<&mut T> { -// if TypeId::of::() == TypeId::of::() { -// Some(unsafe { &mut *(&mut self.add_number as *mut AddNumber as *mut T) }) -// } else { -// None -// } -// } -// } - -// impl State for NumberState { -// fn create_passes() -> Box<[TypeErasedPass]> { -// Box::new([AddNumber::to_type_erased()]) -// } -// } - -// let mut tree: RealDom = RealDom::new(); -// let parent = tree.root(); -// let child1 = tree.create_node(1); -// tree.add_child(parent, child1); -// let grandchild1 = tree.create_node(1); -// tree.add_child(child1, grandchild1); -// let child2 = tree.create_node(1); -// tree.add_child(parent, child2); -// let grandchild2 = tree.create_node(1); -// tree.add_child(child2, grandchild2); - -// tree.dirty_nodes -// .insert(TypeId::of::(), NodeId(0)); -// tree.update_state(SendAnyMap::new()); - -// assert_eq!(tree.get(tree.root()).unwrap().state.add_number.0, 1); -// assert_eq!(tree.get(child1).unwrap().state.add_number.0, 2); -// assert_eq!(tree.get(grandchild1).unwrap().state.add_number.0, 3); -// assert_eq!(tree.get(child2).unwrap().state.add_number.0, 2); -// assert_eq!(tree.get(grandchild2).unwrap().state.add_number.0, 3); -// } - -// #[test] -// fn dependant_down_pass() { -// use crate::tree::{Tree, TreeLike}; -// // 0 -// let mut tree = Tree::new(1); -// let parent = tree.root(); -// // 1 -// let child1 = tree.create_node(1); -// tree.add_child(parent, child1); -// // 2 -// let grandchild1 = tree.create_node(1); -// tree.add_child(child1, grandchild1); -// // 3 -// let child2 = tree.create_node(1); -// tree.add_child(parent, child2); -// // 4 -// let grandchild2 = tree.create_node(1); -// tree.add_child(child2, grandchild2); - -// struct AddPass; -// impl Pass for AddPass { -// fn pass_id(&self) -> PassId { -// PassId(0) -// } - -// fn dependancies(&self) -> &'static [PassId] { -// &[PassId(1)] -// } - -// fn dependants(&self) -> &'static [PassId] { -// &[] -// } - -// fn mask(&self) -> MemberMask { -// MemberMask(0) -// } -// } -// impl DownwardPass for AddPass { -// fn pass(&self, node: &mut i32, parent: Option<&mut i32>, _: &SendAnyMap) -> PassReturn { -// if let Some(parent) = parent { -// *node += *parent; -// } else { -// } -// PassReturn { -// progress: true, -// mark_dirty: true, -// } -// } -// } - -// struct SubtractPass; -// impl Pass for SubtractPass { -// fn pass_id(&self) -> PassId { -// PassId(1) -// } - -// fn dependancies(&self) -> &'static [PassId] { -// &[] -// } - -// fn dependants(&self) -> &'static [PassId] { -// &[PassId(0)] -// } - -// fn mask(&self) -> MemberMask { -// MemberMask(0) -// } -// } -// impl DownwardPass for SubtractPass { -// fn pass(&self, node: &mut i32, parent: Option<&mut i32>, _: &SendAnyMap) -> PassReturn { -// if let Some(parent) = parent { -// *node -= *parent; -// } else { -// } -// PassReturn { -// progress: true, -// mark_dirty: true, -// } -// } -// } - -// let add_pass = AnyPass::Downward(&AddPass); -// let subtract_pass = AnyPass::Downward(&SubtractPass); -// let passes = vec![&add_pass, &subtract_pass]; -// let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default(); -// dirty_nodes.insert(PassId(1), tree.root()); -// resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new()); - -// // Tree before: -// // 1=\ -// // 1=\ -// // 1 -// // 1=\ -// // 1 -// // Tree after subtract: -// // 1=\ -// // 0=\ -// // 1 -// // 0=\ -// // 1 -// // Tree after add: -// // 1=\ -// // 1=\ -// // 2 -// // 1=\ -// // 2 -// assert_eq!(tree.get(tree.root()).unwrap(), &1); -// assert_eq!(tree.get(child1).unwrap(), &1); -// assert_eq!(tree.get(grandchild1).unwrap(), &2); -// assert_eq!(tree.get(child2).unwrap(), &1); -// assert_eq!(tree.get(grandchild2).unwrap(), &2); -// } - -// #[test] -// fn up_pass() { -// use crate::tree::{Tree, TreeLike}; -// // Tree before: -// // 0=\ -// // 0=\ -// // 1 -// // 0=\ -// // 1 -// // Tree after: -// // 2=\ -// // 1=\ -// // 1 -// // 1=\ -// // 1 -// let mut tree = Tree::new(0); -// let parent = tree.root(); -// let child1 = tree.create_node(0); -// tree.add_child(parent, child1); -// let grandchild1 = tree.create_node(1); -// tree.add_child(child1, grandchild1); -// let child2 = tree.create_node(0); -// tree.add_child(parent, child2); -// let grandchild2 = tree.create_node(1); -// tree.add_child(child2, grandchild2); - -// struct AddPass; -// impl Pass for AddPass { -// fn pass_id(&self) -> PassId { -// PassId(0) -// } - -// fn dependancies(&self) -> &'static [PassId] { -// &[] -// } - -// fn dependants(&self) -> &'static [PassId] { -// &[] -// } - -// fn mask(&self) -> MemberMask { -// MemberMask(0) -// } -// } -// impl UpwardPass for AddPass { -// fn pass<'a>( -// &self, -// node: &mut i32, -// children: &mut dyn Iterator, -// _: &SendAnyMap, -// ) -> PassReturn { -// *node += children.map(|i| *i).sum::(); -// PassReturn { -// progress: true, -// mark_dirty: true, -// } -// } -// } - -// let add_pass = AnyPass::Upward(&AddPass); -// let passes = vec![&add_pass]; -// let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default(); -// dirty_nodes.insert(PassId(0), grandchild1); -// dirty_nodes.insert(PassId(0), grandchild2); -// resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new()); - -// assert_eq!(tree.get(tree.root()).unwrap(), &2); -// assert_eq!(tree.get(child1).unwrap(), &1); -// assert_eq!(tree.get(grandchild1).unwrap(), &1); -// assert_eq!(tree.get(child2).unwrap(), &1); -// assert_eq!(tree.get(grandchild2).unwrap(), &1); -// } - -// #[test] -// fn dependant_up_pass() { -// use crate::tree::{Tree, TreeLike}; -// // 0 -// let mut tree = Tree::new(0); -// let parent = tree.root(); -// // 1 -// let child1 = tree.create_node(0); -// tree.add_child(parent, child1); -// // 2 -// let grandchild1 = tree.create_node(1); -// tree.add_child(child1, grandchild1); -// // 3 -// let child2 = tree.create_node(0); -// tree.add_child(parent, child2); -// // 4 -// let grandchild2 = tree.create_node(1); -// tree.add_child(child2, grandchild2); - -// struct AddPass; -// impl Pass for AddPass { -// fn pass_id(&self) -> PassId { -// PassId(0) -// } - -// fn dependancies(&self) -> &'static [PassId] { -// &[PassId(1)] -// } - -// fn dependants(&self) -> &'static [PassId] { -// &[] -// } - -// fn mask(&self) -> MemberMask { -// MemberMask(0) -// } -// } -// impl UpwardPass for AddPass { -// fn pass<'a>( -// &self, -// node: &mut i32, -// children: &mut dyn Iterator, -// _: &SendAnyMap, -// ) -> PassReturn { -// *node += children.map(|i| *i).sum::(); -// PassReturn { -// progress: true, -// mark_dirty: true, -// } -// } -// } - -// struct SubtractPass; -// impl Pass for SubtractPass { -// fn pass_id(&self) -> PassId { -// PassId(1) -// } - -// fn dependancies(&self) -> &'static [PassId] { -// &[] -// } - -// fn dependants(&self) -> &'static [PassId] { -// &[PassId(0)] -// } - -// fn mask(&self) -> MemberMask { -// MemberMask(0) -// } -// } -// impl UpwardPass for SubtractPass { -// fn pass<'a>( -// &self, -// node: &mut i32, -// children: &mut dyn Iterator, -// _: &SendAnyMap, -// ) -> PassReturn { -// *node -= children.map(|i| *i).sum::(); -// PassReturn { -// progress: true, -// mark_dirty: true, -// } -// } -// } - -// let add_pass = AnyPass::Upward(&AddPass); -// let subtract_pass = AnyPass::Upward(&SubtractPass); -// let passes = vec![&add_pass, &subtract_pass]; -// let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default(); -// dirty_nodes.insert(PassId(1), grandchild1); -// dirty_nodes.insert(PassId(1), grandchild2); -// resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new()); - -// // Tree before: -// // 0=\ -// // 0=\ -// // 1 -// // 0=\ -// // 1 -// // Tree after subtract: -// // 2=\ -// // -1=\ -// // 1 -// // -1=\ -// // 1 -// // Tree after add: -// // 2=\ -// // 0=\ -// // 1 -// // 0=\ -// // 1 -// assert_eq!(tree.get(tree.root()).unwrap(), &2); -// assert_eq!(tree.get(child1).unwrap(), &0); -// assert_eq!(tree.get(grandchild1).unwrap(), &1); -// assert_eq!(tree.get(child2).unwrap(), &0); -// assert_eq!(tree.get(grandchild2).unwrap(), &1); -// } diff --git a/packages/native-core/src/real_dom.rs b/packages/native-core/src/real_dom.rs index 5db372e06..bb7d1ec99 100644 --- a/packages/native-core/src/real_dom.rs +++ b/packages/native-core/src/real_dom.rs @@ -1,15 +1,13 @@ -use dioxus_core::{BorrowedAttributeValue, ElementId, Mutations, TemplateNode}; - use rustc_hash::{FxHashMap, FxHashSet}; use std::any::{Any, TypeId}; use std::collections::VecDeque; use crate::node::{ - ElementNode, FromAnyValue, NodeData, NodeType, OwnedAttributeDiscription, OwnedAttributeValue, + ElementNode, FromAnyValue, NodeType, OwnedAttributeDiscription, OwnedAttributeValue, }; use crate::node_ref::{AttributeMask, NodeMask, NodeMaskBuilder}; use crate::passes::{resolve_passes, DirtyNodeStates, TypeErasedPass}; -use crate::tree::{EntryBuilder, NodeId, Tree}; +use crate::tree::{NodeId, Tree}; use crate::{FxDashSet, SendAnyMap}; /// A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers. @@ -20,11 +18,7 @@ use crate::{FxDashSet, SendAnyMap}; /// 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 { pub(crate) tree: Tree, - /// a map from element id to real node id - node_id_mapping: Vec>, nodes_listening: FxHashMap>, - stack: Vec, - templates: FxHashMap>, pub(crate) passes: Box<[TypeErasedPass]>, passes_updated: FxHashMap>, nodes_updated: FxHashMap, @@ -34,19 +28,17 @@ pub struct RealDom { impl RealDom { pub fn new(mut passes: Box<[TypeErasedPass]>) -> RealDom { let mut tree = Tree::new(); - tree.insert_slab::>(); + tree.insert_slab::>(); for pass in passes.iter() { (pass.create)(&mut tree); } let root_id = tree.root(); - let mut root_node: NodeData = NodeData::new(NodeType::Element(ElementNode { + let root_node: NodeType = NodeType::Element(ElementNode { tag: "Root".to_string(), namespace: Some("Root".to_string()), attributes: FxHashMap::default(), listeners: FxHashSet::default(), - })); - root_node.element_id = Some(ElementId(0)); - root_node.node_id = root_id; + }); tree.insert(root_id, root_node); // resolve dependants for each pass @@ -71,10 +63,7 @@ impl RealDom { RealDom { tree, - node_id_mapping: vec![Some(root_id)], nodes_listening: FxHashMap::default(), - stack: vec![root_id], - templates: FxHashMap::default(), passes, passes_updated, nodes_updated, @@ -114,239 +103,23 @@ impl RealDom { } } - pub fn element_to_node_id(&self, element_id: ElementId) -> NodeId { - self.node_id_mapping.get(element_id.0).unwrap().unwrap() - } - - fn set_element_id(&mut self, node_id: NodeId, element_id: ElementId) { - let mut node = self.tree.get_mut::(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); - } - self.node_id_mapping[element_id.0] = Some(node_id); - } - - fn load_child(&self, path: &[u8]) -> NodeId { - let mut current = *self.stack.last().unwrap(); - for i in path { - current = self.tree.children_ids(current).unwrap()[*i as usize]; - } - current - } - - fn create_node( - &mut self, - mut node: NodeData, - id: Option, - mark_dirty: bool, - ) -> EntryBuilder<'_> { + pub fn create_node(&mut self, node: NodeType, mark_dirty: bool) -> NodeMut<'_, V> { let mut node_entry = self.tree.create_node(); - let node_id = node_entry.id(); + let id = node_entry.id(); if mark_dirty { self.passes_updated - .entry(node_id) + .entry(id) .or_default() .extend(self.passes.iter().map(|x| x.this_type_id)); } - node.node_id = node_id; - node.element_id = id; node_entry.insert(node); - node_entry + NodeMut::new(id, self) } - fn add_child(&mut self, node_id: NodeId, child_id: NodeId) { + pub fn add_child(&mut self, node_id: NodeId, child_id: NodeId) { self.tree.add_child(node_id, child_id); } - fn create_template_node(&mut self, node: &TemplateNode) -> NodeId { - match node { - TemplateNode::Element { - tag, - namespace, - attrs, - children, - } => { - let node = NodeData::new(NodeType::Element(ElementNode { - tag: tag.to_string(), - namespace: namespace.map(|s| s.to_string()), - attributes: attrs - .iter() - .filter_map(|attr| match attr { - dioxus_core::TemplateAttribute::Static { - name, - value, - namespace, - } => Some(( - OwnedAttributeDiscription { - namespace: namespace.map(|s| s.to_string()), - name: name.to_string(), - volatile: false, - }, - OwnedAttributeValue::Text(value.to_string()), - )), - dioxus_core::TemplateAttribute::Dynamic { .. } => None, - }) - .collect(), - listeners: FxHashSet::default(), - })); - 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(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(), - } - } - - /// 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(&mut self, mutations: Mutations) { - for template in mutations.templates { - let mut template_root_ids = Vec::new(); - for root in template.roots { - let id = self.create_template_node(root); - template_root_ids.push(id); - } - self.templates - .insert(template.name.to_string(), template_root_ids); - } - - for e in mutations.edits { - use dioxus_core::Mutation::*; - match e { - AppendChildren { id, m } => { - let children = self.stack.split_off(self.stack.len() - m); - let parent = self.element_to_node_id(id); - for child in children { - self.add_child(parent, child); - } - } - AssignId { path, id } => { - self.set_element_id(self.load_child(path), id); - } - CreatePlaceholder { id } => { - 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_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 mut node = self.get_mut(node_id).unwrap(); - if let NodeTypeMut::Text(text) = node.node_type_mut() { - *text = value.to_string(); - } else { - node.set_type(NodeType::Text(value.to_string())); - } - } - LoadTemplate { name, index, id } => { - let template_id = self.templates[name][index]; - let clone_id = self.clone_node(template_id); - self.set_element_id(clone_id, id); - self.stack.push(clone_id); - } - ReplaceWith { id, m } => { - let new_nodes = self.stack.split_off(self.stack.len() - m); - let old_node_id = self.element_to_node_id(id); - for new in new_nodes { - self.insert_before(old_node_id, new); - } - self.remove(old_node_id); - } - ReplacePlaceholder { path, m } => { - let new_nodes = self.stack.split_off(self.stack.len() - m); - let old_node_id = self.load_child(path); - for new in new_nodes { - self.insert_before(old_node_id, new); - } - self.remove(old_node_id); - } - InsertAfter { id, m } => { - let new_nodes = self.stack.split_off(self.stack.len() - m); - let old_node_id = self.element_to_node_id(id); - for new in new_nodes.into_iter().rev() { - self.insert_after(old_node_id, new); - } - } - InsertBefore { id, m } => { - let new_nodes = self.stack.split_off(self.stack.len() - m); - let old_node_id = self.element_to_node_id(id); - for new in new_nodes { - self.tree.insert_before(old_node_id, new); - } - } - SetAttribute { - name, - value, - id, - ns, - } => { - let node_id = self.element_to_node_id(id); - let mut node = self.get_mut(node_id).unwrap(); - if let NodeTypeMut::Element(element) = &mut node.node_type_mut() { - if let BorrowedAttributeValue::None = &value { - element.remove_attributes(&OwnedAttributeDiscription { - name: name.to_string(), - namespace: ns.map(|s| s.to_string()), - volatile: false, - }); - } else { - element.set_attribute( - OwnedAttributeDiscription { - name: name.to_string(), - namespace: ns.map(|s| s.to_string()), - volatile: false, - }, - OwnedAttributeValue::from(value), - ); - } - } - } - SetText { value, id } => { - let node_id = self.element_to_node_id(id); - let mut node = self.get_mut(node_id).unwrap(); - if let NodeTypeMut::Text(text) = node.node_type_mut() { - *text = value.to_string(); - } - } - NewEventListener { name, id } => { - let node_id = self.element_to_node_id(id); - self.add_event_listener(node_id, name); - } - RemoveEventListener { id, name } => { - let node_id = self.element_to_node_id(id); - self.remove_event_listener(node_id, name); - } - Remove { id } => { - let node_id = self.element_to_node_id(id); - self.remove(node_id); - } - PushRoot { id } => { - let node_id = self.element_to_node_id(id); - self.stack.push(node_id); - } - } - } - } - /// 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: &str) -> Vec> { @@ -376,10 +149,10 @@ impl RealDom { self.tree.root() } - fn clone_node(&mut self, node_id: NodeId) -> NodeId { + pub fn clone_node(&mut self, node_id: NodeId) -> NodeId { 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 new_node = node.node_type().clone(); + let new_id = self.create_node(new_node, true).id(); let children = self.tree.children_ids(node_id).unwrap().to_vec(); for child in children { @@ -389,26 +162,18 @@ impl RealDom { new_id } - pub fn root(&self) -> NodeId { - self.tree.root() - } - - pub fn get(&self, id: impl IntoNodeId) -> Option> { + pub fn get(&self, id: NodeId) -> Option> { let id = id.into_node_id(self); self.tree.contains(id).then_some(NodeRef { id, dom: self }) } - pub fn get_mut(&mut self, id: impl IntoNodeId) -> Option> { + pub fn get_mut(&mut self, id: NodeId) -> Option> { let id = id.into_node_id(self); - self.tree.contains(id).then(|| NodeMut { - id, - dirty: NodeMask::default(), - dom: self, - }) + self.tree.contains(id).then(|| NodeMut::new(id, 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: impl IntoNodeId) -> Option> { + pub fn get_mut_raw(&mut self, id: NodeId) -> Option> { let id = id.into_node_id(self); self.tree .contains(id) @@ -439,7 +204,7 @@ impl RealDom { ) } - fn remove(&mut self, id: NodeId) { + pub fn remove(&mut self, id: NodeId) { if let Some(parent_id) = self.tree.parent_id(id) { self.mark_child_changed(parent_id); } @@ -454,52 +219,8 @@ impl RealDom { self.tree.replace(old, new); } - pub 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); - } - - pub 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); - } - - pub fn add_event_listener(&mut self, id: NodeId, event: &str) { - let mut node = self.get_mut(id).unwrap(); - if let NodeTypeMut::Element(mut element) = node.node_type_mut() { - element.listeners_mut().insert(event.to_string()); - drop(node); - match self.nodes_listening.get_mut(event) { - Some(hs) => { - hs.insert(id); - } - None => { - let mut hs = FxHashSet::default(); - hs.insert(id); - self.nodes_listening.insert(event.to_string(), hs); - } - } - } - } - - pub fn remove_event_listener(&mut self, id: NodeId, event: &str) { - { - let mut node = self.get_mut(id).unwrap(); - if let NodeTypeMut::Element(mut element) = node.node_type_mut() { - element.listeners_mut().remove(event); - } - } - self.nodes_listening.get_mut(event).unwrap().remove(&id); - } - pub fn traverse_depth_first(&self, mut f: impl FnMut(NodeRef)) { - let mut stack = vec![self.root()]; + let mut stack = vec![self.root_id()]; while let Some(id) = stack.pop() { if let Some(node) = self.get(id) { f(node); @@ -512,7 +233,7 @@ impl RealDom { pub fn traverse_breadth_first(&self, mut f: impl FnMut(NodeRef)) { let mut queue = VecDeque::new(); - queue.push_back(self.root()); + queue.push_back(self.root_id()); while let Some(id) = queue.pop_front() { if let Some(node) = self.get(id) { f(node); @@ -526,7 +247,7 @@ impl RealDom { } pub fn traverse_depth_first_mut(&mut self, mut f: impl FnMut(NodeMut)) { - let mut stack = vec![self.root()]; + let mut stack = vec![self.root_id()]; while let Some(id) = stack.pop() { if let Some(children) = self.tree.children_ids(id) { let children = children.iter().copied().rev().collect::>(); @@ -541,7 +262,7 @@ impl RealDom { pub fn traverse_breadth_first_mut(&mut self, mut f: impl FnMut(NodeMut)) { let mut queue = VecDeque::new(); - queue.push_back(self.root()); + queue.push_back(self.root_id()); while let Some(id) = queue.pop_front() { if let Some(children) = self.tree.children_ids(id) { let children = children.to_vec(); @@ -554,6 +275,10 @@ impl RealDom { } } } + + pub fn insert_slab(&mut self) { + self.tree.insert_slab::(); + } } pub trait IntoNodeId { @@ -566,27 +291,13 @@ impl IntoNodeId for NodeId { } } -impl IntoNodeId for ElementId { - fn into_node_id(self, rdom: &RealDom) -> NodeId { - rdom.element_to_node_id(self) - } -} - pub trait NodeImmutable: Sized { fn real_dom(&self) -> &RealDom; fn id(&self) -> NodeId; - fn mounted_id(&self) -> Option { - self.node_data().mounted_id() - } - - fn node_data(&self) -> &NodeData { - self.get().unwrap() - } - fn node_type(&self) -> &NodeType { - &self.node_data().node_type + self.get().unwrap() } fn get(&self) -> Option<&T> { @@ -621,8 +332,29 @@ pub trait NodeImmutable: Sized { } pub trait NodeMutable: Sized + NodeImmutable { - fn get_mut(&mut self) -> Option<&mut T>; - fn insert(&mut self, value: T); + fn real_dom_mut(&mut self) -> &mut RealDom; + fn get_mut(&mut self) -> Option<&mut T> { + let id = self.id(); + self.real_dom_mut().tree.get_mut(id) + } + fn insert(&mut self, value: T) { + let id = self.id(); + self.real_dom_mut().tree.insert(id, value); + } + fn add_child(&mut self, child: NodeId) { + let id = self.id(); + self.real_dom_mut().tree.add_child(id, child); + } + fn insert_after(&mut self, old: NodeId) { + let id = self.id(); + self.real_dom_mut().tree.insert_after(old, id); + } + fn insert_before(&mut self, old: NodeId) { + let id = self.id(); + self.real_dom_mut().tree.insert_before(old, id); + } + fn add_event_listener(&mut self, event: &str); + fn remove_event_listener(&mut self, event: &str); } #[derive(Clone, Copy)] @@ -647,6 +379,16 @@ pub struct NodeMut<'a, V: FromAnyValue + Send + Sync = ()> { dirty: NodeMask, } +impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { + pub fn new(id: NodeId, dom: &'a mut RealDom) -> Self { + Self { + id, + dom, + dirty: NodeMask::default(), + } + } +} + impl<'a, V: FromAnyValue + Send + Sync> NodeImmutable for NodeMut<'a, V> { fn real_dom(&self) -> &RealDom { self.dom @@ -658,19 +400,78 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeImmutable for NodeMut<'a, V> { } impl<'a, V: FromAnyValue + Send + Sync> NodeMutable for NodeMut<'a, V> { - fn get_mut(&mut self) -> Option<&mut T> { - todo!("get_mut with mark as dirty") + fn real_dom_mut(&mut self) -> &mut RealDom { + self.dom } - fn insert(&mut self, _: T) { - todo!("insert with mark as dirty") + fn get_mut(&mut self) -> Option<&mut T> { + // mark the node state as dirty + self.dom + .passes_updated + .entry(self.id) + .or_default() + .insert(TypeId::of::()); + self.dom.tree.get_mut(self.id) + } + + fn insert(&mut self, value: T) { + // mark the node state as dirty + self.dom + .passes_updated + .entry(self.id) + .or_default() + .insert(TypeId::of::()); + self.dom.tree.insert(self.id, value); + } + + fn insert_after(&mut self, old: NodeId) { + let id = self.id(); + if let Some(parent_id) = self.dom.tree.parent_id(old) { + self.dom.mark_child_changed(parent_id); + self.dom.mark_parent_added_or_removed(id); + } + self.dom.tree.insert_after(old, id); + } + + fn insert_before(&mut self, old: NodeId) { + let id = self.id(); + if let Some(parent_id) = self.dom.tree.parent_id(old) { + self.dom.mark_child_changed(parent_id); + self.dom.mark_parent_added_or_removed(id); + } + self.dom.tree.insert_before(old, id); + } + + fn add_event_listener(&mut self, event: &str) { + let id = self.id(); + if let NodeTypeMut::Element(mut element) = self.node_type_mut() { + element.listeners_mut().insert(event.to_string()); + match self.dom.nodes_listening.get_mut(event) { + Some(hs) => { + hs.insert(id); + } + None => { + let mut hs = FxHashSet::default(); + hs.insert(id); + self.dom.nodes_listening.insert(event.to_string(), hs); + } + } + } + } + + fn remove_event_listener(&mut self, event: &str) { + let id = self.id(); + if let NodeTypeMut::Element(mut element) = self.node_type_mut() { + element.listeners_mut().remove(event); + } + self.dom.nodes_listening.get_mut(event).unwrap().remove(&id); } } impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { pub fn node_type_mut(&mut self) -> NodeTypeMut<'_, V> { let Self { id, dom, dirty } = self; - let node_type = &mut dom.tree.get_mut::>(*id).unwrap().node_type; + let node_type = dom.tree.get_mut::>(*id).unwrap(); match node_type { NodeType::Element(element) => NodeTypeMut::Element(ElementNodeMut { element, dirty }), NodeType::Text(text) => { @@ -682,20 +483,15 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { } pub fn set_type(&mut self, new: NodeType) { - self.dom - .tree - .get_mut::>(self.id) - .unwrap() - .node_type = new; + *self.dom.tree.get_mut::>(self.id).unwrap() = new; self.dirty = NodeMaskBuilder::ALL.build(); } } impl Drop for NodeMut<'_, V> { fn drop(&mut self) { - let node_id = self.node_data().node_id; let mask = std::mem::take(&mut self.dirty); - self.dom.mark_dirty(node_id, mask); + self.dom.mark_dirty(self.id, mask); } } @@ -780,6 +576,12 @@ pub struct NodeMutRaw<'a, V: FromAnyValue + Send + Sync = ()> { dom: &'a mut RealDom, } +impl<'a, V: FromAnyValue + Send + Sync> NodeMutRaw<'a, V> { + fn node_type_mut(&mut self) -> &mut NodeType { + self.dom.tree.get_mut::>(self.id).unwrap() + } +} + impl<'a, V: FromAnyValue + Send + Sync> NodeImmutable for NodeMutRaw<'a, V> { fn real_dom(&self) -> &RealDom { self.dom @@ -791,11 +593,32 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeImmutable for NodeMutRaw<'a, V> { } impl<'a, V: FromAnyValue + Send + Sync> NodeMutable for NodeMutRaw<'a, V> { - fn get_mut(&mut self) -> Option<&mut T> { - self.dom.tree.get_mut::(self.id) + fn real_dom_mut(&mut self) -> &mut RealDom { + self.dom } - fn insert(&mut self, value: T) { - self.dom.tree.insert(self.id, value); + fn add_event_listener(&mut self, event: &str) { + let id = self.id(); + if let NodeType::Element(element) = self.node_type_mut() { + element.listeners.insert(event.to_string()); + match self.dom.nodes_listening.get_mut(event) { + Some(hs) => { + hs.insert(id); + } + None => { + let mut hs = FxHashSet::default(); + hs.insert(id); + self.dom.nodes_listening.insert(event.to_string(), hs); + } + } + } + } + + fn remove_event_listener(&mut self, event: &str) { + let id = self.id(); + if let NodeType::Element(element) = self.node_type_mut() { + element.listeners.remove(event); + } + self.dom.nodes_listening.get_mut(event).unwrap().remove(&id); } } diff --git a/packages/native-core/src/tree.rs b/packages/native-core/src/tree.rs index f2d1a07e6..cbb59dab8 100644 --- a/packages/native-core/src/tree.rs +++ b/packages/native-core/src/tree.rs @@ -659,7 +659,7 @@ impl AnySlab { } } -pub struct EntryBuilder<'a> { +pub(crate) struct EntryBuilder<'a> { id: NodeId, inner: &'a mut AnySlab, } @@ -671,18 +671,6 @@ impl EntryBuilder<'_> { .insert(self.id, value); } - pub fn get(&self) -> Option<&T> { - self.inner.read_slab().get(self.id) - } - - pub fn get_mut(&mut self) -> Option<&mut T> { - self.inner.write_slab().get_mut(self.id) - } - - pub fn remove(self) { - self.inner.remove(self.id); - } - pub fn id(&self) -> NodeId { self.id } diff --git a/packages/native-core/src/utils/cursor.rs b/packages/native-core/src/utils/cursor.rs index eaded383e..18fbbb991 100644 --- a/packages/native-core/src/utils/cursor.rs +++ b/packages/native-core/src/utils/cursor.rs @@ -1,6 +1,6 @@ use std::{cmp::Ordering, ops::Range}; -use dioxus_html::input_data::keyboard_types::{Code, Key, Modifiers}; +use keyboard_types::{Code, Key, Modifiers}; /// This contains the information about the text that is used by the cursor to handle navigation. pub trait Text { @@ -221,26 +221,28 @@ impl Cursor { /// Handle moving the cursor with the given key. pub fn handle_input( &mut self, - data: &dioxus_html::KeyboardData, + code: &Code, + key: &Key, + modifiers: &Modifiers, text: &mut impl TextEditable, max_text_length: usize, ) { use Code::*; - match data.code() { + match code { ArrowUp => { self.move_cursor( |c| c.up(text.as_ref()), - data.modifiers().contains(Modifiers::SHIFT), + modifiers.contains(Modifiers::SHIFT), ); } ArrowDown => { self.move_cursor( |c| c.down(text.as_ref()), - data.modifiers().contains(Modifiers::SHIFT), + modifiers.contains(Modifiers::SHIFT), ); } ArrowRight => { - if data.modifiers().contains(Modifiers::CONTROL) { + if modifiers.contains(Modifiers::CONTROL) { self.move_cursor( |c| { let mut change = 1; @@ -255,17 +257,17 @@ impl Cursor { } c.move_col(change as i32, text.as_ref()); }, - data.modifiers().contains(Modifiers::SHIFT), + modifiers.contains(Modifiers::SHIFT), ); } else { self.move_cursor( |c| c.right(text.as_ref()), - data.modifiers().contains(Modifiers::SHIFT), + modifiers.contains(Modifiers::SHIFT), ); } } ArrowLeft => { - if data.modifiers().contains(Modifiers::CONTROL) { + if modifiers.contains(Modifiers::CONTROL) { self.move_cursor( |c| { let mut change = -1; @@ -279,23 +281,23 @@ impl Cursor { } c.move_col(change, text.as_ref()); }, - data.modifiers().contains(Modifiers::SHIFT), + modifiers.contains(Modifiers::SHIFT), ); } else { self.move_cursor( |c| c.left(text.as_ref()), - data.modifiers().contains(Modifiers::SHIFT), + modifiers.contains(Modifiers::SHIFT), ); } } End => { self.move_cursor( |c| c.col = c.len_line(text.as_ref()), - data.modifiers().contains(Modifiers::SHIFT), + modifiers.contains(Modifiers::SHIFT), ); } Home => { - self.move_cursor(|c| c.col = 0, data.modifiers().contains(Modifiers::SHIFT)); + self.move_cursor(|c| c.col = 0, modifiers.contains(Modifiers::SHIFT)); } Backspace => { self.start.realize_col(text.as_ref()); @@ -305,7 +307,7 @@ impl Cursor { } else if start_idx > 0 { self.start.left(text.as_ref()); text.delete_range(start_idx - 1..start_idx); - if data.modifiers().contains(Modifiers::CONTROL) { + if modifiers.contains(Modifiers::CONTROL) { start_idx = self.start.idx(text.as_ref()); while start_idx > 0 && text @@ -340,7 +342,7 @@ impl Cursor { } _ => { self.start.realize_col(text.as_ref()); - if let Key::Character(character) = data.key() { + if let Key::Character(character) = key { if text.as_ref().length() + 1 - self.selection_len(text.as_ref()) <= max_text_length { @@ -460,13 +462,9 @@ fn cursor_input() { for _ in 0..5 { cursor.handle_input( - &dioxus_html::KeyboardData::new( - dioxus_html::input_data::keyboard_types::Key::ArrowRight, - dioxus_html::input_data::keyboard_types::Code::ArrowRight, - dioxus_html::input_data::keyboard_types::Location::Standard, - false, - Modifiers::empty(), - ), + &keyboard_types::Code::ArrowRight, + &keyboard_types::Key::ArrowRight, + &Modifiers::empty(), &mut text, 10, ); @@ -474,13 +472,9 @@ fn cursor_input() { for _ in 0..5 { cursor.handle_input( - &dioxus_html::KeyboardData::new( - dioxus_html::input_data::keyboard_types::Key::Backspace, - dioxus_html::input_data::keyboard_types::Code::Backspace, - dioxus_html::input_data::keyboard_types::Location::Standard, - false, - Modifiers::empty(), - ), + &keyboard_types::Code::Backspace, + &keyboard_types::Key::Backspace, + &Modifiers::empty(), &mut text, 10, ); @@ -491,61 +485,41 @@ fn cursor_input() { let goal_text = "hello world\nhi"; let max_width = goal_text.len(); cursor.handle_input( - &dioxus_html::KeyboardData::new( - dioxus_html::input_data::keyboard_types::Key::Character("h".to_string()), - dioxus_html::input_data::keyboard_types::Code::KeyH, - dioxus_html::input_data::keyboard_types::Location::Standard, - false, - Modifiers::empty(), - ), + &keyboard_types::Code::KeyH, + &keyboard_types::Key::Character("h".to_string()), + &Modifiers::empty(), &mut text, max_width, ); cursor.handle_input( - &dioxus_html::KeyboardData::new( - dioxus_html::input_data::keyboard_types::Key::Character("e".to_string()), - dioxus_html::input_data::keyboard_types::Code::KeyE, - dioxus_html::input_data::keyboard_types::Location::Standard, - false, - Modifiers::empty(), - ), + &keyboard_types::Code::KeyE, + &keyboard_types::Key::Character("e".to_string()), + &Modifiers::empty(), &mut text, max_width, ); cursor.handle_input( - &dioxus_html::KeyboardData::new( - dioxus_html::input_data::keyboard_types::Key::Character("l".to_string()), - dioxus_html::input_data::keyboard_types::Code::KeyL, - dioxus_html::input_data::keyboard_types::Location::Standard, - false, - Modifiers::empty(), - ), + &keyboard_types::Code::KeyL, + &keyboard_types::Key::Character("l".to_string()), + &Modifiers::empty(), &mut text, max_width, ); cursor.handle_input( - &dioxus_html::KeyboardData::new( - dioxus_html::input_data::keyboard_types::Key::Character("l".to_string()), - dioxus_html::input_data::keyboard_types::Code::KeyL, - dioxus_html::input_data::keyboard_types::Location::Standard, - false, - Modifiers::empty(), - ), + &keyboard_types::Code::KeyL, + &keyboard_types::Key::Character("l".to_string()), + &Modifiers::empty(), &mut text, max_width, ); cursor.handle_input( - &dioxus_html::KeyboardData::new( - dioxus_html::input_data::keyboard_types::Key::Character("o".to_string()), - dioxus_html::input_data::keyboard_types::Code::KeyO, - dioxus_html::input_data::keyboard_types::Location::Standard, - false, - Modifiers::empty(), - ), + &keyboard_types::Code::KeyO, + &keyboard_types::Key::Character("o".to_string()), + &Modifiers::empty(), &mut text, max_width, ); @@ -553,13 +527,9 @@ fn cursor_input() { // these should be ignored for _ in 0..10 { cursor.handle_input( - &dioxus_html::KeyboardData::new( - dioxus_html::input_data::keyboard_types::Key::Character("o".to_string()), - dioxus_html::input_data::keyboard_types::Code::KeyO, - dioxus_html::input_data::keyboard_types::Location::Standard, - false, - Modifiers::empty(), - ), + &keyboard_types::Code::KeyO, + &keyboard_types::Key::Character("o".to_string()), + &Modifiers::empty(), &mut text, max_width, ); diff --git a/packages/native-core/src/utils/mod.rs b/packages/native-core/src/utils/mod.rs index 58e98b0fa..9ddb1a1c7 100644 --- a/packages/native-core/src/utils/mod.rs +++ b/packages/native-core/src/utils/mod.rs @@ -1,3 +1,3 @@ -mod persistant_iterator; -pub use persistant_iterator::*; +// mod persistant_iterator; +// pub use persistant_iterator::*; pub mod cursor; diff --git a/packages/native-core/src/utils/persistant_iterator.rs b/packages/native-core/src/utils/persistant_iterator.rs index 2fffe14d1..eb2cd1269 100644 --- a/packages/native-core/src/utils/persistant_iterator.rs +++ b/packages/native-core/src/utils/persistant_iterator.rs @@ -13,6 +13,7 @@ pub enum ElementProduced { /// The iterator reached the end of the tree and looped back to the root Looped(NodeId), } + impl ElementProduced { pub fn id(&self) -> NodeId { match self { @@ -141,7 +142,7 @@ impl PersistantElementIter { } else { let (last, old_child_idx) = self.stack.last_mut().unwrap(); let node = rdom.get(*last).unwrap(); - match &node.node_data().node_type { + match node.node_type() { NodeType::Element(ElementNode { .. }) => { let children = node.child_ids().unwrap(); *old_child_idx = old_child_idx.map(|i| i + 1); @@ -153,7 +154,7 @@ impl PersistantElementIter { } else { let id = children[child_idx]; if let NodeType::Element(ElementNode { .. }) = - rdom.get(id).unwrap().node_data().node_type + rdom.get(id).unwrap().node_type() { self.stack.push((id, NodePosition::AtNode)); } @@ -178,7 +179,7 @@ impl PersistantElementIter { rdom: &RealDom, ) -> NodeId { let node = rdom.get(new_node).unwrap(); - match &node.node_data().node_type { + match node.node_type() { NodeType::Element(ElementNode { .. }) => { let children = node.child_ids().unwrap(); if children.is_empty() { @@ -197,7 +198,7 @@ impl PersistantElementIter { } else { let (last, old_child_idx) = self.stack.last_mut().unwrap(); let node = rdom.get(*last).unwrap(); - match &node.node_data().node_type { + match node.node_type() { NodeType::Element(ElementNode { .. }) => { let children = node.child_ids().unwrap(); // if we have children, go to the next child diff --git a/packages/native-core/tests/passes.rs b/packages/native-core/tests/passes.rs new file mode 100644 index 000000000..c9d6b089f --- /dev/null +++ b/packages/native-core/tests/passes.rs @@ -0,0 +1,620 @@ +use dioxus::prelude::*; +use dioxus_native_core::node::NodeType; +use dioxus_native_core::prelude::*; +use std::any::TypeId; +use std::sync::{Arc, Mutex}; + +fn create_blank_element() -> NodeType { + NodeType::Element(ElementNode { + tag: "div".to_owned(), + namespace: None, + attributes: HashMap::new(), + listeners: HashMap::new(), + }) +} + +#[test] +fn node_pass() { + #[derive(Debug, Default, Clone, PartialEq)] + struct Number(i32); + + impl Pass for Number { + type ChildDependencies = (); + type NodeDependencies = (); + type ParentDependencies = (); + const NODE_MASK: NodeMaskBuilder = NodeMaskBuilder::new(); + + fn pass<'a>( + &mut self, + node_view: NodeView, + node: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + children: Option::ElementBorrowed<'a>>>, + context: &SendAnyMap, + ) -> bool { + self.0 += 1; + true + } + + fn create<'a>( + node_view: NodeView<()>, + node: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + children: Option::ElementBorrowed<'a>>>, + context: &SendAnyMap, + ) -> Self { + let mut myself = Self::default(); + myself.pass(node_view, node, parent, children, context); + myself + } + } + + let mut tree: RealDom = RealDom::new(Box::new([Number::to_type_erased()])); + tree.update_state(SendAnyMap::new(), false); + + assert_eq!(tree.get(tree.root_id()).unwrap().get(), Some(&Number(1))); + + // mark the node as dirty + tree.get_mut(tree.root_id()).unwrap().get_mut::(); + + tree.update_state(SendAnyMap::new(), false); + assert_eq!(tree.get(tree.root_id()).unwrap().get(), Some(&Number(2))); +} + +#[test] +fn dependant_node_pass() { + #[derive(Debug, Default, Clone, PartialEq)] + struct AddNumber(i32); + + impl Pass for AddNumber { + type ChildDependencies = (); + type NodeDependencies = (SubtractNumber,); + type ParentDependencies = (); + const NODE_MASK: NodeMaskBuilder = NodeMaskBuilder::new(); + + fn pass<'a>( + &mut self, + node_view: NodeView, + node: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + children: Option::ElementBorrowed<'a>>>, + context: &SendAnyMap, + ) -> bool { + self.0 += 1; + true + } + + fn create<'a>( + node_view: NodeView<()>, + node: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + children: Option::ElementBorrowed<'a>>>, + context: &SendAnyMap, + ) -> Self { + let mut myself = Self::default(); + myself.pass(node_view, node, parent, children, context); + myself + } + } + + #[derive(Debug, Default, Clone, PartialEq)] + struct SubtractNumber(i32); + + impl Pass for SubtractNumber { + type ChildDependencies = (); + type NodeDependencies = (); + type ParentDependencies = (); + const NODE_MASK: NodeMaskBuilder = NodeMaskBuilder::new(); + + fn pass<'a>( + &mut self, + node_view: NodeView, + node: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + children: Option::ElementBorrowed<'a>>>, + context: &SendAnyMap, + ) -> bool { + self.0 -= 1; + true + } + + fn create<'a>( + node_view: NodeView<()>, + node: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + children: Option::ElementBorrowed<'a>>>, + context: &SendAnyMap, + ) -> Self { + let mut myself = Self::default(); + myself.pass(node_view, node, parent, children, context); + myself + } + } + + let mut tree: RealDom = RealDom::new(Box::new([ + AddNumber::to_type_erased(), + SubtractNumber::to_type_erased(), + ])); + tree.update_state(SendAnyMap::new(), false); + + let root = tree.get(tree.root_id()).unwrap(); + assert_eq!(root.get(), Some(&AddNumber(1))); + assert_eq!(root.get(), Some(&SubtractNumber(-1))); + + // mark the subtract state as dirty, it should update the add state + tree.get_mut(tree.root_id()) + .unwrap() + .get_mut::(); + + tree.update_state(SendAnyMap::new(), false); + let root = tree.get(tree.root_id()).unwrap(); + assert_eq!(root.get(), Some(&AddNumber(2))); + assert_eq!(root.get(), Some(&SubtractNumber(-2))); + + // mark the add state as dirty, it should ~not~ update the subtract state + tree.get_mut(tree.root_id()).unwrap().get_mut::(); + + tree.update_state(SendAnyMap::new(), false); + let root = tree.get(tree.root_id()).unwrap(); + assert_eq!(root.get(), Some(&AddNumber(3))); + assert_eq!(root.get(), Some(&SubtractNumber(-2))); +} + +#[test] +fn independant_node_pass() { + #[derive(Debug, Default, Clone, PartialEq)] + struct AddNumber(i32); + + impl Pass for AddNumber { + type ChildDependencies = (); + type NodeDependencies = (); + type ParentDependencies = (); + + const NODE_MASK: NodeMaskBuilder = NodeMaskBuilder::new(); + + fn pass<'a>( + &mut self, + node_view: NodeView, + node: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + children: Option::ElementBorrowed<'a>>>, + context: &SendAnyMap, + ) -> bool { + self.0 += 1; + true + } + + fn create<'a>( + node_view: NodeView<()>, + node: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + children: Option::ElementBorrowed<'a>>>, + context: &SendAnyMap, + ) -> Self { + let mut myself = Self::default(); + myself.pass(node_view, node, parent, children, context); + myself + } + } + + #[derive(Debug, Default, Clone, PartialEq)] + struct SubtractNumber(i32); + + impl Pass for SubtractNumber { + type ChildDependencies = (); + type NodeDependencies = (); + type ParentDependencies = (); + + const NODE_MASK: NodeMaskBuilder = NodeMaskBuilder::new(); + + fn pass<'a>( + &mut self, + node_view: NodeView, + node: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + children: Option::ElementBorrowed<'a>>>, + context: &SendAnyMap, + ) -> bool { + self.0 -= 1; + true + } + + fn create<'a>( + node_view: NodeView<()>, + node: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + children: Option::ElementBorrowed<'a>>>, + context: &SendAnyMap, + ) -> Self { + let mut myself = Self::default(); + myself.pass(node_view, node, parent, children, context); + myself + } + } + + let mut tree: RealDom = RealDom::new(Box::new([ + AddNumber::to_type_erased(), + SubtractNumber::to_type_erased(), + ])); + tree.update_state(SendAnyMap::new(), false); + + let root = tree.get(tree.root_id()).unwrap(); + assert_eq!(root.get(), Some(&AddNumber(1))); + assert_eq!(root.get(), Some(&SubtractNumber(-1))); + + // mark the subtract state as dirty, it should ~not~ update the add state + tree.get_mut(tree.root_id()) + .unwrap() + .get_mut::(); + + tree.update_state(SendAnyMap::new(), false); + + let root = tree.get(tree.root_id()).unwrap(); + assert_eq!(root.get(), Some(&AddNumber(1))); + assert_eq!(root.get(), Some(&SubtractNumber(-2))); + + // mark the add state as dirty, it should ~not~ update the subtract state + tree.get_mut(tree.root_id()).unwrap().get_mut::(); + + tree.update_state(SendAnyMap::new(), false); + + let root = tree.get(tree.root_id()).unwrap(); + assert_eq!(root.get(), Some(&AddNumber(2))); + assert_eq!(root.get(), Some(&SubtractNumber(-2))); +} + +#[test] +fn down_pass() { + #[derive(Debug, Clone, PartialEq)] + struct AddNumber(i32); + + impl Default for AddNumber { + fn default() -> Self { + Self(1) + } + } + + impl Pass for AddNumber { + type ChildDependencies = (); + type NodeDependencies = (); + type ParentDependencies = (AddNumber,); + + const NODE_MASK: NodeMaskBuilder = NodeMaskBuilder::new(); + + fn pass<'a>( + &mut self, + node_view: NodeView, + node: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + children: Option::ElementBorrowed<'a>>>, + context: &SendAnyMap, + ) -> bool { + if let Some((parent,)) = parent { + *self.0 += *parent.0; + } + true + } + } + + let mut tree: RealDom = RealDom::new(Box::new([AddNumber::to_type_erased()])); + let parent = tree.root_id(); + let child1 = tree.create_node(create_blank_element(), true); + tree.add_child(parent, child1); + let grandchild1 = tree.create_node(create_blank_element(), true); + tree.add_child(child1, grandchild1); + let child2 = tree.create_node(create_blank_element(), true); + tree.add_child(parent, child2); + let grandchild2 = tree.create_node(create_blank_element(), true); + tree.add_child(child2, grandchild2); + + tree.dirty_nodes + .insert(TypeId::of::(), NodeId(0)); + tree.update_state(SendAnyMap::new(), false); + + assert_eq!(tree.get(tree.root_id()).unwrap().state.add_number.0, 1); + assert_eq!(tree.get(child1).unwrap().state.add_number.0, 2); + assert_eq!(tree.get(grandchild1).unwrap().state.add_number.0, 3); + assert_eq!(tree.get(child2).unwrap().state.add_number.0, 2); + assert_eq!(tree.get(grandchild2).unwrap().state.add_number.0, 3); +} + +// #[test] +// fn dependant_down_pass() { +// // 0 +// let mut tree = Tree::new(1); +// let parent = tree.root_id(); +// // 1 +// let child1 = tree.create_node(1); +// tree.add_child(parent, child1); +// // 2 +// let grandchild1 = tree.create_node(1); +// tree.add_child(child1, grandchild1); +// // 3 +// let child2 = tree.create_node(1); +// tree.add_child(parent, child2); +// // 4 +// let grandchild2 = tree.create_node(1); +// tree.add_child(child2, grandchild2); + +// struct AddPass; +// impl Pass for AddPass { +// fn pass_id(&self) -> PassId { +// PassId(0) +// } + +// fn dependancies(&self) -> &'static [PassId] { +// &[PassId(1)] +// } + +// fn dependants(&self) -> &'static [PassId] { +// &[] +// } + +// fn mask(&self) -> MemberMask { +// MemberMask(0) +// } +// } +// impl DownwardPass for AddPass { +// fn pass(&self, node: &mut i32, parent: Option<&mut i32>, _: &SendAnyMap) -> PassReturn { +// if let Some(parent) = parent { +// *node += *parent; +// } else { +// } +// PassReturn { +// progress: true, +// mark_dirty: true, +// } +// } +// } + +// struct SubtractPass; +// impl Pass for SubtractPass { +// fn pass_id(&self) -> PassId { +// PassId(1) +// } + +// fn dependancies(&self) -> &'static [PassId] { +// &[] +// } + +// fn dependants(&self) -> &'static [PassId] { +// &[PassId(0)] +// } + +// fn mask(&self) -> MemberMask { +// MemberMask(0) +// } +// } +// impl DownwardPass for SubtractPass { +// fn pass(&self, node: &mut i32, parent: Option<&mut i32>, _: &SendAnyMap) -> PassReturn { +// if let Some(parent) = parent { +// *node -= *parent; +// } else { +// } +// PassReturn { +// progress: true, +// mark_dirty: true, +// } +// } +// } + +// let add_pass = AnyPass::Downward(&AddPass); +// let subtract_pass = AnyPass::Downward(&SubtractPass); +// let passes = vec![&add_pass, &subtract_pass]; +// let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default(); +// dirty_nodes.insert(PassId(1), tree.root_id()); +// resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new()); + +// // Tree before: +// // 1=\ +// // 1=\ +// // 1 +// // 1=\ +// // 1 +// // Tree after subtract: +// // 1=\ +// // 0=\ +// // 1 +// // 0=\ +// // 1 +// // Tree after add: +// // 1=\ +// // 1=\ +// // 2 +// // 1=\ +// // 2 +// assert_eq!(tree.get(tree.root_id()).unwrap(), &1); +// assert_eq!(tree.get(child1).unwrap(), &1); +// assert_eq!(tree.get(grandchild1).unwrap(), &2); +// assert_eq!(tree.get(child2).unwrap(), &1); +// assert_eq!(tree.get(grandchild2).unwrap(), &2); +// } + +// #[test] +// fn up_pass() { +// // Tree before: +// // 0=\ +// // 0=\ +// // 1 +// // 0=\ +// // 1 +// // Tree after: +// // 2=\ +// // 1=\ +// // 1 +// // 1=\ +// // 1 +// let mut tree = Tree::new(0); +// let parent = tree.root_id(); +// let child1 = tree.create_node(0); +// tree.add_child(parent, child1); +// let grandchild1 = tree.create_node(1); +// tree.add_child(child1, grandchild1); +// let child2 = tree.create_node(0); +// tree.add_child(parent, child2); +// let grandchild2 = tree.create_node(1); +// tree.add_child(child2, grandchild2); + +// struct AddPass; +// impl Pass for AddPass { +// fn pass_id(&self) -> PassId { +// PassId(0) +// } + +// fn dependancies(&self) -> &'static [PassId] { +// &[] +// } + +// fn dependants(&self) -> &'static [PassId] { +// &[] +// } + +// fn mask(&self) -> MemberMask { +// MemberMask(0) +// } +// } +// impl UpwardPass for AddPass { +// fn pass<'a>( +// &self, +// node: &mut i32, +// children: &mut dyn Iterator, +// _: &SendAnyMap, +// ) -> PassReturn { +// *node += children.map(|i| *i).sum::(); +// PassReturn { +// progress: true, +// mark_dirty: true, +// } +// } +// } + +// let add_pass = AnyPass::Upward(&AddPass); +// let passes = vec![&add_pass]; +// let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default(); +// dirty_nodes.insert(PassId(0), grandchild1); +// dirty_nodes.insert(PassId(0), grandchild2); +// resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new()); + +// assert_eq!(tree.get(tree.root_id()).unwrap(), &2); +// assert_eq!(tree.get(child1).unwrap(), &1); +// assert_eq!(tree.get(grandchild1).unwrap(), &1); +// assert_eq!(tree.get(child2).unwrap(), &1); +// assert_eq!(tree.get(grandchild2).unwrap(), &1); +// } + +// #[test] +// fn dependant_up_pass() { +// // 0 +// let mut tree = Tree::new(0); +// let parent = tree.root_id(); +// // 1 +// let child1 = tree.create_node(0); +// tree.add_child(parent, child1); +// // 2 +// let grandchild1 = tree.create_node(1); +// tree.add_child(child1, grandchild1); +// // 3 +// let child2 = tree.create_node(0); +// tree.add_child(parent, child2); +// // 4 +// let grandchild2 = tree.create_node(1); +// tree.add_child(child2, grandchild2); + +// struct AddPass; +// impl Pass for AddPass { +// fn pass_id(&self) -> PassId { +// PassId(0) +// } + +// fn dependancies(&self) -> &'static [PassId] { +// &[PassId(1)] +// } + +// fn dependants(&self) -> &'static [PassId] { +// &[] +// } + +// fn mask(&self) -> MemberMask { +// MemberMask(0) +// } +// } +// impl UpwardPass for AddPass { +// fn pass<'a>( +// &self, +// node: &mut i32, +// children: &mut dyn Iterator, +// _: &SendAnyMap, +// ) -> PassReturn { +// *node += children.map(|i| *i).sum::(); +// PassReturn { +// progress: true, +// mark_dirty: true, +// } +// } +// } + +// struct SubtractPass; +// impl Pass for SubtractPass { +// fn pass_id(&self) -> PassId { +// PassId(1) +// } + +// fn dependancies(&self) -> &'static [PassId] { +// &[] +// } + +// fn dependants(&self) -> &'static [PassId] { +// &[PassId(0)] +// } + +// fn mask(&self) -> MemberMask { +// MemberMask(0) +// } +// } +// impl UpwardPass for SubtractPass { +// fn pass<'a>( +// &self, +// node: &mut i32, +// children: &mut dyn Iterator, +// _: &SendAnyMap, +// ) -> PassReturn { +// *node -= children.map(|i| *i).sum::(); +// PassReturn { +// progress: true, +// mark_dirty: true, +// } +// } +// } + +// let add_pass = AnyPass::Upward(&AddPass); +// let subtract_pass = AnyPass::Upward(&SubtractPass); +// let passes = vec![&add_pass, &subtract_pass]; +// let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default(); +// dirty_nodes.insert(PassId(1), grandchild1); +// dirty_nodes.insert(PassId(1), grandchild2); +// resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new()); + +// // Tree before: +// // 0=\ +// // 0=\ +// // 1 +// // 0=\ +// // 1 +// // Tree after subtract: +// // 2=\ +// // -1=\ +// // 1 +// // -1=\ +// // 1 +// // Tree after add: +// // 2=\ +// // 0=\ +// // 1 +// // 0=\ +// // 1 +// assert_eq!(tree.get(tree.root_id()).unwrap(), &2); +// assert_eq!(tree.get(child1).unwrap(), &0); +// assert_eq!(tree.get(grandchild1).unwrap(), &1); +// assert_eq!(tree.get(child2).unwrap(), &0); +// assert_eq!(tree.get(grandchild2).unwrap(), &1); +// }