From b91e010ac7de7ab06d6ad3a5f5f662f764d38201 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 28 Feb 2023 13:26:49 -0600 Subject: [PATCH] WIP: use shipyard ecs --- packages/native-core-macro/.gitignore | 2 + packages/native-core-macro/Cargo.toml | 26 + packages/native-core-macro/README.md | 43 ++ packages/native-core-macro/src/lib.rs | 22 + packages/native-core/Cargo.toml | 4 +- packages/native-core/src/dioxus.rs | 26 +- packages/native-core/src/lib.rs | 4 +- packages/native-core/src/node.rs | 3 +- packages/native-core/src/passes.rs | 353 ++++++------ packages/native-core/src/real_dom.rs | 298 +++++++--- packages/native-core/src/tree.rs | 512 +++--------------- .../src/utils/persistant_iterator.rs | 12 +- 12 files changed, 567 insertions(+), 738 deletions(-) create mode 100644 packages/native-core-macro/.gitignore create mode 100644 packages/native-core-macro/Cargo.toml create mode 100644 packages/native-core-macro/README.md create mode 100644 packages/native-core-macro/src/lib.rs diff --git a/packages/native-core-macro/.gitignore b/packages/native-core-macro/.gitignore new file mode 100644 index 000000000..96ef6c0b9 --- /dev/null +++ b/packages/native-core-macro/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/packages/native-core-macro/Cargo.toml b/packages/native-core-macro/Cargo.toml new file mode 100644 index 000000000..ed8648f93 --- /dev/null +++ b/packages/native-core-macro/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "dioxus-native-core-macro" +version = "0.3.0" +edition = "2021" +description = "Build natively rendered apps with Dioxus" +license = "MIT/Apache-2.0" +repository = "https://github.com/DioxusLabs/dioxus/" +homepage = "https://dioxuslabs.com" +documentation = "https://dioxuslabs.com" +keywords = ["dom", "ui", "gui", "react"] + + +[lib] +proc-macro = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[dependencies] +syn = { version = "1.0.11", features = ["extra-traits", "full"] } +quote = "1.0" + +[dev-dependencies] +smallvec = "1.6" +rustc-hash = "1.1.0" +anymap = "0.12.1" +dioxus = { path = "../dioxus" } +dioxus-native-core = { path = "../native-core" } diff --git a/packages/native-core-macro/README.md b/packages/native-core-macro/README.md new file mode 100644 index 000000000..6b8c13590 --- /dev/null +++ b/packages/native-core-macro/README.md @@ -0,0 +1,43 @@ +# Dioxus Native Core Macro + +[![Crates.io][crates-badge]][crates-url] +[![MIT licensed][mit-badge]][mit-url] +[![Build Status][actions-badge]][actions-url] +[![Discord chat][discord-badge]][discord-url] + +[crates-badge]: https://img.shields.io/crates/v/dioxus-native-core-macro.svg +[crates-url]: https://crates.io/crates/dioxus-native-core-macro + +[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg +[mit-url]: https://github.com/dioxuslabs/dioxus/blob/master/LICENSE + +[actions-badge]: https://github.com/dioxuslabs/dioxus/actions/workflows/main.yml/badge.svg +[actions-url]: https://github.com/dioxuslabs/dioxus/actions?query=workflow%3ACI+branch%3Amaster + +[discord-badge]: https://img.shields.io/discord/899851952891002890.svg?logo=discord&style=flat-square +[discord-url]: https://discord.gg/XgGxMSkvUM + +[Website](https://dioxuslabs.com) | +[Guides](https://dioxuslabs.com/docs/0.3/guide/en/) | +[API Docs](https://docs.rs/dioxus-native-core-macro/latest/dioxus_native_core_macro) | +[Chat](https://discord.gg/XgGxMSkvUM) + + +## Overview + +`dioxus-native-core-macro` provides a handful of macros used by native-core for native renderers like TUI, Blitz, and Freya to derive their state. + + +## Contributing + +- Report issues on our [issue tracker](https://github.com/dioxuslabs/dioxus/issues). +- Join the discord and ask questions! + +## License +This project is licensed under the [MIT license]. + +[mit license]: https://github.com/DioxusLabs/dioxus/blob/master/LICENSE-MIT + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Dioxus by you shall be licensed as MIT without any additional +terms or conditions. diff --git a/packages/native-core-macro/src/lib.rs b/packages/native-core-macro/src/lib.rs new file mode 100644 index 000000000..21fbb7e89 --- /dev/null +++ b/packages/native-core-macro/src/lib.rs @@ -0,0 +1,22 @@ +extern crate proc_macro; + +mod sorted_slice; + +use proc_macro::TokenStream; +use quote::{quote, ToTokens, __private::Span}; +use sorted_slice::StrSlice; +use syn::parenthesized; +use syn::parse::ParseBuffer; +use syn::punctuated::Punctuated; +use syn::{ + self, + parse::{Parse, ParseStream, Result}, + parse_macro_input, parse_quote, Error, Field, Ident, Token, Type, +}; + +/// A helper attribute for deriving `State` for a struct. +#[proc_macro_attribute] +pub fn my_attribute(_: TokenStream, input: TokenStream) -> TokenStream { + let impl_block: syn::ItemImpl = syn::parse(input).unwrap(); + quote!(#impl_block).into() +} diff --git a/packages/native-core/Cargo.toml b/packages/native-core/Cargo.toml index 2e748563c..d5e724e86 100644 --- a/packages/native-core/Cargo.toml +++ b/packages/native-core/Cargo.toml @@ -28,6 +28,8 @@ hashbrown = { version = "0.13.2", features = ["raw"] } lightningcss = "1.0.0-alpha.39" rayon = "1.6.1" +shipyard = "0.6.2" + [dev-dependencies] rand = "0.8.5" @@ -37,4 +39,4 @@ dioxus-native-core = { path = ".", features = ["dioxus"] } [features] default = [] -dioxus = ["dioxus-core"] \ No newline at end of file +dioxus = ["dioxus-core"] diff --git a/packages/native-core/src/dioxus.rs b/packages/native-core/src/dioxus.rs index f7426f1d6..ffc80c1c7 100644 --- a/packages/native-core/src/dioxus.rs +++ b/packages/native-core/src/dioxus.rs @@ -1,5 +1,6 @@ use dioxus_core::{BorrowedAttributeValue, ElementId, Mutations, TemplateNode}; use rustc_hash::{FxHashMap, FxHashSet}; +use shipyard::Component; use crate::{ node::{ @@ -11,6 +12,9 @@ use crate::{ NodeId, NodeMut, RealDom, }; +#[derive(Component)] +struct ElementIdComponent(ElementId); + pub struct DioxusState { templates: FxHashMap>, stack: Vec, @@ -19,10 +23,9 @@ pub struct DioxusState { impl DioxusState { pub fn create(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)); + root.insert(ElementIdComponent(ElementId(0))); Self { templates: FxHashMap::default(), stack: vec![root_id], @@ -40,7 +43,7 @@ impl DioxusState { fn set_element_id(&mut self, mut node: NodeMut, element_id: ElementId) { let node_id = node.id(); - node.insert(element_id); + node.insert(ElementIdComponent(element_id)); if self.node_id_mapping.len() <= element_id.0 { self.node_id_mapping.resize(element_id.0 + 1, None); } @@ -104,9 +107,11 @@ impl DioxusState { 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(); + let node_type_mut = node.node_type_mut(); + if let NodeTypeMut::Text(mut text) = node_type_mut { + *text.text_mut() = value.to_string(); } else { + drop(node_type_mut); node.set_type(NodeType::Text(TextNode { text: value.to_string(), listeners: FxHashSet::default(), @@ -161,7 +166,8 @@ impl DioxusState { } => { 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() { + let mut node_type_mut = node.node_type_mut(); + if let NodeTypeMut::Element(element) = &mut node_type_mut { if let BorrowedAttributeValue::None = &value { element.remove_attributes(&OwnedAttributeDiscription { name: name.to_string(), @@ -181,8 +187,9 @@ impl DioxusState { 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(); + let node_type_mut = node.node_type_mut(); + if let NodeTypeMut::Text(mut text) = node_type_mut { + *text.text_mut() = value.to_string(); } } NewEventListener { name, id } => { @@ -260,7 +267,8 @@ fn create_template_node(rdom: &mut RealDom, node: &TemplateNode) -> NodeId { pub trait NodeImmutableDioxusExt: NodeImmutable { fn mounted_id(&self) -> Option { - self.get().copied() + let id = self.get::(); + id.map(|id| id.0) } } diff --git a/packages/native-core/src/lib.rs b/packages/native-core/src/lib.rs index ee65c35a4..74c5e947c 100644 --- a/packages/native-core/src/lib.rs +++ b/packages/native-core/src/lib.rs @@ -6,7 +6,6 @@ pub use passes::AnyMapLike; pub use passes::{Dependancy, State, TypeErasedPass}; pub use real_dom::{NodeMut, NodeRef, RealDom}; use rustc_hash::FxHasher; -pub use tree::NodeId; #[cfg(feature = "dioxus")] pub mod dioxus; @@ -18,13 +17,14 @@ mod passes; pub mod real_dom; pub mod tree; pub mod utils; +pub use shipyard::EntityId as NodeId; pub mod prelude { pub use crate::node::{ElementNode, FromAnyValue, NodeType, OwnedAttributeView, TextNode}; pub use crate::node_ref::{AttributeMaskBuilder, NodeMaskBuilder, NodeView}; pub use crate::passes::{Dependancy, State}; pub use crate::real_dom::{NodeImmutable, NodeMut, NodeRef, RealDom}; - pub use crate::tree::NodeId; + pub use crate::NodeId; pub use crate::SendAnyMap; } diff --git a/packages/native-core/src/node.rs b/packages/native-core/src/node.rs index 51e096a97..1e6331c86 100644 --- a/packages/native-core/src/node.rs +++ b/packages/native-core/src/node.rs @@ -1,4 +1,5 @@ use rustc_hash::{FxHashMap, FxHashSet}; +use shipyard::Component; use std::{any::Any, fmt::Debug}; #[derive(Debug, Clone, Default)] @@ -25,7 +26,7 @@ impl TextNode { } /// 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, Component)] pub enum NodeType { Text(TextNode), Element(ElementNode), diff --git a/packages/native-core/src/passes.rs b/packages/native-core/src/passes.rs index 5a25c0424..31b873dde 100644 --- a/packages/native-core/src/passes.rs +++ b/packages/native-core/src/passes.rs @@ -1,17 +1,15 @@ use anymap::AnyMap; -use core::panic; use parking_lot::RwLock; use rustc_hash::{FxHashMap, FxHashSet}; +use shipyard::{Component, IntoBorrow, Unique, View, WorkloadSystem}; use std::any::{Any, TypeId}; use std::collections::BTreeMap; use std::marker::PhantomData; use std::sync::Arc; -use crate::node::{FromAnyValue, NodeType}; +use crate::node::FromAnyValue; use crate::node_ref::{NodeMaskBuilder, NodeView}; -use crate::real_dom::RealDom; -use crate::tree::{SlabEntry, Tree, TreeStateView}; -use crate::{FxDashSet, SendAnyMap}; +use crate::SendAnyMap; use crate::{NodeId, NodeMask}; #[derive(Default)] @@ -21,7 +19,7 @@ struct DirtyNodes { impl DirtyNodes { pub fn add_node(&mut self, node_id: NodeId) { - let node_id = node_id.0; + let node_id = node_id.uindex(); let index = node_id / 64; let bit = node_id % 64; let encoded = 1 << bit; @@ -37,17 +35,17 @@ impl DirtyNodes { self.passes_dirty.iter().all(|dirty| *dirty == 0) } - pub fn pop(&mut self) -> Option { + pub fn pop(&mut self) -> Option { let index = self.passes_dirty.iter().position(|dirty| *dirty != 0)?; let passes = self.passes_dirty[index]; let node_id = passes.trailing_zeros(); let encoded = 1 << node_id; self.passes_dirty[index] &= !encoded; - Some(NodeId((index * 64) + node_id as usize)) + Some((index * 64) + node_id as usize) } } -#[derive(Clone)] +#[derive(Clone, Unique)] pub struct DirtyNodeStates { dirty: Arc>>>, } @@ -76,7 +74,7 @@ impl DirtyNodeStates { } } - fn pop_front(&self, pass_id: TypeId) -> Option<(u16, NodeId)> { + fn pop_front(&self, pass_id: TypeId) -> Option<(u16, usize)> { let mut values = self.dirty.get(&pass_id)?.write(); let mut value = values.first_entry()?; let height = *value.key(); @@ -89,7 +87,7 @@ impl DirtyNodeStates { Some((height, id)) } - fn pop_back(&self, pass_id: TypeId) -> Option<(u16, NodeId)> { + fn pop_back(&self, pass_id: TypeId) -> Option<(u16, usize)> { let mut values = self.dirty.get(&pass_id)?.write(); let mut value = values.last_entry()?; let height = *value.key(); @@ -110,6 +108,7 @@ pub trait State: Any + Send + Sync { type ChildDependencies: Dependancy; /// This is a tuple of (T: Pass, ..) of states read from the node required to run this pass type NodeDependencies: Dependancy; + type CombinedDependencies: Dependancy; /// This is a mask of what aspects of the node are required to run this pass const NODE_MASK: NodeMaskBuilder<'static>; @@ -131,47 +130,43 @@ pub trait State: Any + Send + Sync { children: Option::ElementBorrowed<'a>>>, context: &SendAnyMap, ) -> Self; +} - fn validate() { - // 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::child_type_ids() - .iter() - .collect::>() - .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"); - } - } +pub trait AnyState: State { + fn workload_system() -> WorkloadSystem; + // Box::new( + // move |node_id: NodeId, tree: &mut TreeStateView, context: &SendAnyMap| { + // debug_assert!(!Self::NodeDependencies::type_ids() + // .iter() + // .any(|id| *id == TypeId::of::())); + // // get all of the states from the tree view + // // Safety: No node has itself as a parent or child. + // 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 = 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(view, node, parent, children, context)); + // true + // } else { + // myself + // .value + // .as_mut() + // .unwrap() + // .update(view, node, parent, children, context) + // } + // }, + // ) as PassCallback fn to_type_erased() -> TypeErasedPass where Self: Sized, { - Self::validate(); let node_mask = Self::NODE_MASK.build(); TypeErasedPass { this_type_id: TypeId::of::(), @@ -181,35 +176,7 @@ pub trait State: Any + Send + Sync { dependants: FxHashSet::default(), mask: node_mask.clone(), pass_direction: Self::pass_direction(), - pass: Box::new( - move |node_id: NodeId, tree: &mut TreeStateView, context: &SendAnyMap| { - debug_assert!(!Self::NodeDependencies::type_ids() - .iter() - .any(|id| *id == TypeId::of::())); - // get all of the states from the tree view - // Safety: No node has itself as a parent or child. - 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 = 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(view, node, parent, children, context)); - true - } else { - myself - .value - .as_mut() - .unwrap() - .update(view, node, parent, children, context) - } - }, - ) as PassCallback, - create: Box::new(|tree: &mut Tree| tree.insert_slab::()) as CreatePassCallback, + workload: Some(Self::workload_system()), phantom: PhantomData, } } @@ -257,58 +224,57 @@ pub struct TypeErasedPass { pub(crate) combined_dependancy_type_ids: FxHashSet, pub(crate) dependants: FxHashSet, pub(crate) mask: NodeMask, - pass: PassCallback, - pub(crate) create: CreatePassCallback, + pub(crate) workload: Option, pub(crate) pass_direction: PassDirection, phantom: PhantomData, } -impl TypeErasedPass { - fn resolve( - &self, - mut tree: TreeStateView, - dirty: &DirtyNodeStates, - nodes_updated: &FxDashSet, - ctx: &SendAnyMap, - ) { - match self.pass_direction { - PassDirection::ParentToChild => { - while let Some((height, id)) = dirty.pop_front(self.this_type_id) { - if (self.pass)(id, &mut tree, ctx) { - nodes_updated.insert(id); - for id in tree.children_ids(id).unwrap() { - for dependant in &self.dependants { - dirty.insert(*dependant, *id, height + 1); - } - } - } - } - } - PassDirection::ChildToParent => { - while let Some((height, id)) = dirty.pop_back(self.this_type_id) { - if (self.pass)(id, &mut tree, ctx) { - nodes_updated.insert(id); - if let Some(id) = tree.parent_id(id) { - for dependant in &self.dependants { - dirty.insert(*dependant, id, height - 1); - } - } - } - } - } - PassDirection::AnyOrder => { - while let Some((height, id)) = dirty.pop_back(self.this_type_id) { - if (self.pass)(id, &mut tree, ctx) { - nodes_updated.insert(id); - for dependant in &self.dependants { - dirty.insert(*dependant, id, height); - } - } - } - } - } - } -} +// impl TypeErasedPass { +// fn resolve( +// &self, +// mut tree: TreeStateView, +// dirty: &DirtyNodeStates, +// nodes_updated: &FxDashSet, +// ctx: &SendAnyMap, +// ) { +// match self.pass_direction { +// PassDirection::ParentToChild => { +// while let Some((height, id)) = dirty.pop_front(self.this_type_id) { +// if (self.pass)(id, &mut tree, ctx) { +// nodes_updated.insert(id); +// for id in tree.children_ids(id).unwrap() { +// for dependant in &self.dependants { +// dirty.insert(*dependant, *id, height + 1); +// } +// } +// } +// } +// } +// PassDirection::ChildToParent => { +// while let Some((height, id)) = dirty.pop_back(self.this_type_id) { +// if (self.pass)(id, &mut tree, ctx) { +// nodes_updated.insert(id); +// if let Some(id) = tree.parent_id(id) { +// for dependant in &self.dependants { +// dirty.insert(*dependant, id, height - 1); +// } +// } +// } +// } +// } +// PassDirection::AnyOrder => { +// while let Some((height, id)) = dirty.pop_back(self.this_type_id) { +// if (self.pass)(id, &mut tree, ctx) { +// nodes_updated.insert(id); +// for dependant in &self.dependants { +// dirty.insert(*dependant, id, height); +// } +// } +// } +// } +// } +// } +// } #[derive(Debug)] pub enum PassDirection { @@ -317,9 +283,6 @@ pub enum PassDirection { AnyOrder, } -type PassCallback = Box bool + Send + Sync>; -type CreatePassCallback = Box; - pub trait AnyMapLike<'a> { fn get(self) -> Option<&'a T>; } @@ -337,25 +300,17 @@ impl<'a> AnyMapLike<'a> for &'a SendAnyMap { } pub trait Dependancy { - type ElementBorrowed<'a> - where - Self: 'a; + type ElementBorrowed<'a>: IntoBorrow; - fn borrow_elements_from<'a, T: AnyMapLike<'a> + Copy>( - map: T, - ) -> Option>; - fn type_ids() -> Box<[TypeId]>; + fn type_ids() -> Box<[TypeId]> { + Box::new([]) + } } macro_rules! impl_dependancy { ($($t:ident),*) => { - impl< $($t: Any + Send + Sync),* > Dependancy for ($($t,)*) { - type ElementBorrowed<'a> = ($(&'a $t,)*) where Self: 'a; - - #[allow(unused_variables, clippy::unused_unit, non_snake_case)] - fn borrow_elements_from<'a, T: AnyMapLike<'a> + Copy>(map: T) -> Option> { - Some(($(map.get::<$t>()?,)*)) - } + impl< $($t: Send + Sync + Component),* > Dependancy for ($($t,)*) { + type ElementBorrowed<'a> = ($(View<'a, $t>,)*); fn type_ids() -> Box<[TypeId]> { Box::new([$(TypeId::of::<$t>()),*]) @@ -375,66 +330,60 @@ impl_dependancy!(A, B, C, D, E, F, G); impl_dependancy!(A, B, C, D, E, F, G, H); impl_dependancy!(A, B, C, D, E, F, G, H, I); impl_dependancy!(A, B, C, D, E, F, G, H, I, J); -impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K); -impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L); -impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L, M); -impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L, M, N); -impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O); -impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P); -pub fn resolve_passes( - dom: &mut RealDom, - dirty_nodes: DirtyNodeStates, - ctx: SendAnyMap, - parallel: bool, -) -> FxDashSet { - let passes = &dom.dirty_nodes.passes; - let mut resolved_passes: FxHashSet = FxHashSet::default(); - let mut resolving = Vec::new(); - let nodes_updated = Arc::new(FxDashSet::default()); - let ctx = Arc::new(ctx); - let mut pass_indexes_remaining: Vec<_> = (0..passes.len()).collect::>(); - while !pass_indexes_remaining.is_empty() { - let mut currently_in_use = FxHashSet::::default(); - let dynamically_borrowed_tree = dom.tree.dynamically_borrowed(); - rayon::in_place_scope(|s| { - let mut i = 0; - while i < pass_indexes_remaining.len() { - let passes_idx = pass_indexes_remaining[i]; - let pass = &passes[passes_idx]; - let pass_id = pass.this_type_id; - // check if the pass is ready to be run - if pass.combined_dependancy_type_ids.iter().all(|d| { - (resolved_passes.contains(d) || *d == pass_id) && !currently_in_use.contains(d) - }) { - pass_indexes_remaining.remove(i); - resolving.push(pass_id); - currently_in_use.insert(pass.this_type_id); - let tree_view = dynamically_borrowed_tree.view( - pass.combined_dependancy_type_ids - .iter() - .filter(|id| **id != pass.this_type_id) - .copied() - .chain(std::iter::once(TypeId::of::>())), - [pass.this_type_id], - ); - let dirty_nodes = dirty_nodes.clone(); - let nodes_updated = nodes_updated.clone(); - let ctx = ctx.clone(); - if parallel { - s.spawn(move |_| { - pass.resolve(tree_view, &dirty_nodes, &nodes_updated, &ctx); - }); - } else { - pass.resolve(tree_view, &dirty_nodes, &nodes_updated, &ctx); - } - } else { - i += 1; - } - } - }); - resolved_passes.extend(resolving.iter().copied()); - resolving.clear() - } - std::sync::Arc::try_unwrap(nodes_updated).unwrap() -} +// pub fn resolve_passes( +// dom: &mut RealDom, +// dirty_nodes: DirtyNodeStates, +// ctx: SendAnyMap, +// parallel: bool, +// ) -> FxDashSet { +// let passes = &dom.dirty_nodes.passes; +// let mut resolved_passes: FxHashSet = FxHashSet::default(); +// let mut resolving = Vec::new(); +// let nodes_updated = Arc::new(FxDashSet::default()); +// let ctx = Arc::new(ctx); +// let mut pass_indexes_remaining: Vec<_> = (0..passes.len()).collect::>(); +// while !pass_indexes_remaining.is_empty() { +// let mut currently_in_use = FxHashSet::::default(); +// let dynamically_borrowed_tree = dom.tree.dynamically_borrowed(); +// rayon::in_place_scope(|s| { +// let mut i = 0; +// while i < pass_indexes_remaining.len() { +// let passes_idx = pass_indexes_remaining[i]; +// let pass = &passes[passes_idx]; +// let pass_id = pass.this_type_id; +// // check if the pass is ready to be run +// if pass.combined_dependancy_type_ids.iter().all(|d| { +// (resolved_passes.contains(d) || *d == pass_id) && !currently_in_use.contains(d) +// }) { +// pass_indexes_remaining.remove(i); +// resolving.push(pass_id); +// currently_in_use.insert(pass.this_type_id); +// let tree_view = dynamically_borrowed_tree.view( +// pass.combined_dependancy_type_ids +// .iter() +// .filter(|id| **id != pass.this_type_id) +// .copied() +// .chain(std::iter::once(TypeId::of::>())), +// [pass.this_type_id], +// ); +// let dirty_nodes = dirty_nodes.clone(); +// let nodes_updated = nodes_updated.clone(); +// let ctx = ctx.clone(); +// if parallel { +// s.spawn(move |_| { +// pass.resolve(tree_view, &dirty_nodes, &nodes_updated, &ctx); +// }); +// } else { +// pass.resolve(tree_view, &dirty_nodes, &nodes_updated, &ctx); +// } +// } else { +// i += 1; +// } +// } +// }); +// resolved_passes.extend(resolving.iter().copied()); +// resolving.clear() +// } +// std::sync::Arc::try_unwrap(nodes_updated).unwrap() +// } diff --git a/packages/native-core/src/real_dom.rs b/packages/native-core/src/real_dom.rs index ac9d5385f..5908f8e4b 100644 --- a/packages/native-core/src/real_dom.rs +++ b/packages/native-core/src/real_dom.rs @@ -1,6 +1,13 @@ use rustc_hash::{FxHashMap, FxHashSet}; -use std::any::{Any, TypeId}; +use shipyard::error::GetStorage; +use shipyard::track::Untracked; +use shipyard::{ + Component, Get, IntoBorrow, ScheduledWorkload, System, Unique, View, ViewMut, Workload, + WorkloadSystem, +}; +use std::any::TypeId; use std::collections::VecDeque; +use std::ops::{Deref, DerefMut}; use std::sync::{Arc, RwLock}; use crate::node::{ @@ -8,11 +15,18 @@ use crate::node::{ }; use crate::node_ref::{NodeMask, NodeMaskBuilder}; use crate::node_watcher::NodeWatcher; -use crate::passes::{resolve_passes, DirtyNodeStates, TypeErasedPass}; +use crate::passes::{DirtyNodeStates, TypeErasedPass}; use crate::prelude::AttributeMaskBuilder; -use crate::tree::{NodeId, Tree}; +use crate::tree::Tree; +use crate::NodeId; use crate::{FxDashSet, SendAnyMap}; +#[derive(Unique)] +struct SendAnyMapWrapper(SendAnyMap); + +#[derive(Unique, Default)] +struct DirtyNodes(FxDashSet); + pub(crate) struct NodesDirty { passes_updated: FxHashMap>, nodes_updated: FxHashMap, @@ -66,16 +80,19 @@ pub struct RealDom { nodes_listening: FxHashMap>, pub(crate) dirty_nodes: NodesDirty, node_watchers: NodeWatchers, + workload: ScheduledWorkload, phantom: std::marker::PhantomData, } impl RealDom { pub fn new(mut passes: Box<[TypeErasedPass]>) -> RealDom { let mut tree = Tree::new(); - tree.insert_slab::>(); - for pass in passes.iter() { - (pass.create)(&mut tree); + let mut workload = Workload::new("Main Workload"); + for pass in &mut *passes { + let system = pass.workload.take().unwrap(); + workload = workload.with_system(system); } + let (workload, _) = workload.build().unwrap(); let root_id = tree.root(); let root_node: NodeType = NodeType::Element(ElementNode { tag: "Root".to_string(), @@ -101,7 +118,6 @@ impl RealDom { let mut passes_updated = FxHashMap::default(); let mut nodes_updated = FxHashMap::default(); - let root_id = NodeId(0); passes_updated.insert(root_id, passes.iter().map(|x| x.this_type_id).collect()); nodes_updated.insert(root_id, NodeMaskBuilder::ALL.build()); @@ -114,6 +130,7 @@ impl RealDom { passes, }, node_watchers: Default::default(), + workload, phantom: std::marker::PhantomData, } } @@ -152,12 +169,6 @@ impl RealDom { } } - /// Return the number of nodes in the dom. - pub fn size(&self) -> usize { - // The dom has a root node, ignore it. - self.tree.size() - 1 - } - /// Returns the id of the root node. pub fn root_id(&self) -> NodeId { self.tree.root() @@ -171,16 +182,21 @@ impl RealDom { 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_state_mut_raw(&mut self, id: NodeId) -> Option<&mut T> { - self.tree.get_mut(id) + fn borrow_raw<'a, B: IntoBorrow>(&'a self) -> Result + where + B::Borrow: shipyard::Borrow<'a, View = B>, + { + self.tree.nodes.borrow() + } + + fn borrow_node_type_mut(&self) -> Result>, GetStorage> { + self.tree.nodes.borrow() } /// 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, - parallel: bool, ) -> (FxDashSet, FxHashMap) { let passes = std::mem::take(&mut self.dirty_nodes.passes_updated); let nodes_updated = std::mem::take(&mut self.dirty_nodes.nodes_updated); @@ -195,10 +211,17 @@ impl RealDom { } } - ( - resolve_passes(self, dirty_nodes, ctx, parallel), - nodes_updated, - ) + let _ = self.tree.remove_unique::(); + let _ = self.tree.remove_unique::(); + self.tree.add_unique(dirty_nodes); + self.tree.add_unique(SendAnyMapWrapper(ctx)); + self.tree.add_unique(DirtyNodes::default()); + + self.workload.run_with_world(&self.tree.nodes).unwrap(); + + let dirty = self.tree.remove_unique::().unwrap(); + + (dirty.0, nodes_updated) } pub fn traverse_depth_first(&self, mut f: impl FnMut(NodeRef)) { @@ -221,7 +244,7 @@ impl RealDom { f(node); if let Some(children) = self.tree.children_ids(id) { for id in children { - queue.push_back(*id); + queue.push_back(id); } } } @@ -258,32 +281,74 @@ impl RealDom { } } - pub fn insert_slab(&mut self) { - self.tree.insert_slab::(); - } - pub fn add_node_watcher(&mut self, watcher: impl NodeWatcher + 'static + Send + Sync) { self.node_watchers.write().unwrap().push(Box::new(watcher)); } } +pub struct ViewEntry<'a, V: Component + Send + Sync> { + view: View<'a, V>, + id: NodeId, +} + +impl<'a, V: Component + Send + Sync> ViewEntry<'a, V> { + fn new(view: View<'a, V>, id: NodeId) -> Self { + Self { view, id } + } +} + +impl<'a, V: Component + Send + Sync> Deref for ViewEntry<'a, V> { + type Target = V; + + fn deref(&self) -> &Self::Target { + &self.view[self.id] + } +} + +pub struct ViewEntryMut<'a, V: Component + Send + Sync> { + view: ViewMut<'a, V, Untracked>, + id: NodeId, +} + +impl<'a, V: Component + Send + Sync> ViewEntryMut<'a, V> { + fn new(view: ViewMut<'a, V, Untracked>, id: NodeId) -> Self { + Self { view, id } + } +} + +impl<'a, V: Component + Send + Sync> Deref for ViewEntryMut<'a, V> { + type Target = V; + + fn deref(&self) -> &Self::Target { + self.view.get(self.id).unwrap() + } +} + +impl<'a, V: Component + Send + Sync> DerefMut for ViewEntryMut<'a, V> { + fn deref_mut(&mut self) -> &mut Self::Target { + (&mut self.view).get(self.id).unwrap() + } +} + pub trait NodeImmutable: Sized { fn real_dom(&self) -> &RealDom; fn id(&self) -> NodeId; #[inline] - fn node_type(&self) -> &NodeType { + fn node_type(&self) -> ViewEntry> { self.get().unwrap() } #[inline] - fn get(&self) -> Option<&T> { - self.real_dom().tree.get(self.id()) + fn get<'a, T: Component + Sync + Send>(&'a self) -> Option> { + // self.real_dom().tree.get(self.id()) + let view: View<'a, T> = self.real_dom().borrow_raw().ok()?; + Some(ViewEntry::new(view, self.id())) } #[inline] - fn child_ids(&self) -> Option<&[NodeId]> { + fn child_ids(&self) -> Option> { self.real_dom().tree.children_ids(self.id()) } @@ -413,7 +478,9 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { } #[inline] - pub fn get_mut(&mut self) -> Option<&mut T> { + pub fn get_mut + Sync + Send>( + &mut self, + ) -> Option> { // mark the node state as dirty self.dom .dirty_nodes @@ -421,11 +488,12 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { .entry(self.id) .or_default() .insert(TypeId::of::()); - self.dom.tree.get_mut(self.id) + let view_mut: ViewMut = self.dom.borrow_raw().ok()?; + Some(ViewEntryMut::new(view_mut, self.id)) } #[inline] - pub fn insert(&mut self, value: T) { + pub fn insert(&mut self, value: T) { // mark the node state as dirty self.dom .dirty_nodes @@ -493,17 +561,20 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { #[inline] pub fn remove(&mut self) { let id = self.id(); - if let NodeType::Element(ElementNode { listeners, .. }) - | NodeType::Text(TextNode { listeners, .. }) = - self.dom.get_state_mut_raw::>(id).unwrap() { - let listeners = std::mem::take(listeners); - for event in listeners { - self.dom - .nodes_listening - .get_mut(&event) - .unwrap() - .remove(&id); + let RealDom { + tree, + nodes_listening, + .. + } = &mut self.dom; + let mut view: ViewMut> = tree.nodes.borrow().unwrap(); + if let NodeType::Element(ElementNode { listeners, .. }) + | NodeType::Text(TextNode { listeners, .. }) = (&mut view).get(id).unwrap() + { + let listeners = std::mem::take(listeners); + for event in listeners { + nodes_listening.get_mut(&event).unwrap().remove(&id); + } } } self.mark_removed(); @@ -539,22 +610,27 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { #[inline] pub fn add_event_listener(&mut self, event: &str) { let id = self.id(); - let node_type: &mut NodeType = self.dom.tree.get_mut(self.id).unwrap(); + let RealDom { + tree, + dirty_nodes, + nodes_listening, + .. + } = &mut self.dom; + let mut view: ViewMut> = tree.nodes.borrow().unwrap(); + let node_type: &mut NodeType = (&mut view).get(self.id).unwrap(); if let NodeType::Element(ElementNode { listeners, .. }) | NodeType::Text(TextNode { listeners, .. }) = node_type { - self.dom - .dirty_nodes - .mark_dirty(self.id, NodeMaskBuilder::new().with_listeners().build()); + dirty_nodes.mark_dirty(self.id, NodeMaskBuilder::new().with_listeners().build()); listeners.insert(event.to_string()); - match self.dom.nodes_listening.get_mut(event) { + match 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); + nodes_listening.insert(event.to_string(), hs); } } } @@ -563,16 +639,21 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { #[inline] pub fn remove_event_listener(&mut self, event: &str) { let id = self.id(); - let node_type: &mut NodeType = self.dom.tree.get_mut(self.id).unwrap(); + let RealDom { + tree, + dirty_nodes, + nodes_listening, + .. + } = &mut self.dom; + let mut view: ViewMut> = tree.nodes.borrow().unwrap(); + let node_type: &mut NodeType = (&mut view).get(self.id).unwrap(); if let NodeType::Element(ElementNode { listeners, .. }) | NodeType::Text(TextNode { listeners, .. }) = node_type { - self.dom - .dirty_nodes - .mark_dirty(self.id, NodeMaskBuilder::new().with_listeners().build()); + dirty_nodes.mark_dirty(self.id, NodeMaskBuilder::new().with_listeners().build()); listeners.remove(event); - self.dom.nodes_listening.get_mut(event).unwrap().remove(&id); + nodes_listening.get_mut(event).unwrap().remove(&id); } } @@ -591,28 +672,32 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { } pub fn node_type_mut(&mut self) -> NodeTypeMut<'_, V> { - let Self { id, dom } = self; + let id = self.id(); let RealDom { - dirty_nodes, tree, .. - } = dom; - let node_type = tree.get_mut(*id).unwrap(); - match node_type { - NodeType::Element(element) => NodeTypeMut::Element(ElementNodeMut { - id: *id, - element, + tree, dirty_nodes, .. + } = &mut self.dom; + let view: ViewMut> = tree.nodes.borrow().unwrap(); + let node_type = ViewEntryMut::new(view, id); + match &*node_type { + NodeType::Element(_) => NodeTypeMut::Element(ElementNodeMut { + id, + element: node_type, + dirty_nodes, + }), + NodeType::Text(_) => NodeTypeMut::Text(TextNodeMut { + id, + text: node_type, dirty_nodes, }), - NodeType::Text(text) => { - dirty_nodes.mark_dirty(self.id, NodeMaskBuilder::new().with_text().build()); - - NodeTypeMut::Text(&mut text.text) - } NodeType::Placeholder => NodeTypeMut::Placeholder, } } pub fn set_type(&mut self, new: NodeType) { - *self.dom.tree.get_mut::>(self.id).unwrap() = new; + { + let mut view: ViewMut> = self.dom.borrow_node_type_mut().unwrap(); + *(&mut view).get(self.id).unwrap() = new; + } self.dom .dirty_nodes .mark_dirty(self.id, NodeMaskBuilder::ALL.build()) @@ -638,39 +723,94 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { pub enum NodeTypeMut<'a, V: FromAnyValue + Send + Sync = ()> { Element(ElementNodeMut<'a, V>), - Text(&'a mut String), + Text(TextNodeMut<'a, V>), Placeholder, } +pub struct TextNodeMut<'a, V: FromAnyValue + Send + Sync = ()> { + id: NodeId, + text: ViewEntryMut<'a, NodeType>, + dirty_nodes: &'a mut NodesDirty, +} + +impl TextNodeMut<'_, V> { + pub fn text(&self) -> &str { + match &*self.text { + NodeType::Text(text) => &text.text, + _ => unreachable!(), + } + } + + pub fn text_mut(&mut self) -> &mut String { + self.dirty_nodes + .mark_dirty(self.id, NodeMaskBuilder::new().with_text().build()); + match &mut *self.text { + NodeType::Text(text) => &mut text.text, + _ => unreachable!(), + } + } +} + +impl Deref for TextNodeMut<'_, V> { + type Target = String; + + fn deref(&self) -> &Self::Target { + match &*self.text { + NodeType::Text(text) => &text.text, + _ => unreachable!(), + } + } +} + +impl DerefMut for TextNodeMut<'_, V> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.text_mut() + } +} + pub struct ElementNodeMut<'a, V: FromAnyValue + Send + Sync = ()> { id: NodeId, - element: &'a mut ElementNode, + element: ViewEntryMut<'a, NodeType>, dirty_nodes: &'a mut NodesDirty, } impl ElementNodeMut<'_, V> { + fn element(&self) -> &ElementNode { + match &*self.element { + NodeType::Element(element) => element, + _ => unreachable!(), + } + } + + fn element_mut(&mut self) -> &mut ElementNode { + match &mut *self.element { + NodeType::Element(element) => element, + _ => unreachable!(), + } + } + pub fn tag(&self) -> &str { - &self.element.tag + &self.element().tag } pub fn tag_mut(&mut self) -> &mut String { self.dirty_nodes .mark_dirty(self.id, NodeMaskBuilder::new().with_tag().build()); - &mut self.element.tag + &mut self.element_mut().tag } pub fn namespace(&self) -> Option<&str> { - self.element.namespace.as_deref() + self.element().namespace.as_deref() } pub fn namespace_mut(&mut self) -> &mut Option { self.dirty_nodes .mark_dirty(self.id, NodeMaskBuilder::new().with_namespace().build()); - &mut self.element.namespace + &mut self.element_mut().namespace } pub fn attributes(&self) -> &FxHashMap> { - &self.element.attributes + &self.element().attributes } pub fn set_attribute( @@ -684,7 +824,7 @@ impl ElementNodeMut<'_, V> { .with_attrs(AttributeMaskBuilder::Some(&[&name.name])) .build(), ); - self.element.attributes.insert(name, value) + self.element_mut().attributes.insert(name, value) } pub fn remove_attributes( @@ -697,7 +837,7 @@ impl ElementNodeMut<'_, V> { .with_attrs(AttributeMaskBuilder::Some(&[&name.name])) .build(), ); - self.element.attributes.remove(name) + self.element_mut().attributes.remove(name) } pub fn get_attribute_mut( @@ -710,10 +850,10 @@ impl ElementNodeMut<'_, V> { .with_attrs(AttributeMaskBuilder::Some(&[&name.name])) .build(), ); - self.element.attributes.get_mut(name) + self.element_mut().attributes.get_mut(name) } pub fn listeners(&self) -> &FxHashSet { - &self.element.listeners + &self.element().listeners } } diff --git a/packages/native-core/src/tree.rs b/packages/native-core/src/tree.rs index 1ba4f0bda..0d8bab7c9 100644 --- a/packages/native-core/src/tree.rs +++ b/packages/native-core/src/tree.rs @@ -1,16 +1,8 @@ -use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard, RwLockWriteGuard}; -use rustc_hash::{FxHashMap, FxHasher}; -use std::any::{Any, TypeId}; -use std::collections::VecDeque; +use crate::NodeId; +use shipyard::{Component, EntitiesView, EntityId, Get, Unique, View, ViewMut, World}; use std::fmt::Debug; -use std::hash::BuildHasherDefault; -use crate::{AnyMapLike, Dependancy}; - -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Hash)] -pub struct NodeId(pub usize); - -#[derive(PartialEq, Eq, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug, Component)] pub(crate) struct Node { parent: Option, children: Vec, @@ -19,60 +11,55 @@ pub(crate) struct Node { #[derive(Debug)] pub(crate) struct Tree { - nodes: AnySlab, + pub(crate) nodes: World, root: NodeId, } impl Tree { pub fn new() -> Self { - let mut nodes = AnySlab::default(); - let mut node = nodes.insert(); - node.insert(Node { + let mut nodes = World::default(); + let node = Node { parent: None, children: Vec::new(), height: 0, - }); - let root = node.id(); + }; + let root = nodes.add_entity((node,)); Self { nodes, root } } - pub(crate) fn insert_slab(&mut self) { - self.nodes.get_or_insert_slab_mut::(); + pub fn add_unique(&mut self, data: T) { + self.nodes.add_unique(data); } - fn node_slab(&self) -> &SlabStorage { - self.nodes.read_slab() + pub fn remove_unique( + &mut self, + ) -> Result { + self.nodes.remove_unique::() } - pub fn get_node_data(&self, id: NodeId) -> &Node { - self.node_slab().get(id).unwrap() + fn node_data(&self) -> View { + self.nodes.borrow().unwrap() } - pub fn try_get_node_data(&self, id: NodeId) -> Option<&Node> { - self.node_slab().get(id) - } - - fn node_slab_mut(&mut self) -> &mut SlabStorage { - self.nodes.write_slab() - } - - pub fn get_node_data_mut(&mut self, id: NodeId) -> &mut Node { - self.node_slab_mut().get_mut(id).unwrap() + fn node_data_mut(&self) -> ViewMut { + self.nodes.borrow().unwrap() } pub fn remove(&mut self, id: NodeId) { fn recurse(tree: &mut Tree, id: NodeId) { - let children = { tree.get_node_data(id).children.clone() }; - for child in children { - recurse(tree, child); + let children = tree.children_ids(id); + if let Some(children) = children { + for child in children { + recurse(tree, child); + } } - tree.nodes.remove(id); + tree.nodes.delete_entity(id); } { - let node_data_mut = self.node_slab_mut(); + let mut node_data_mut = self.node_data_mut(); if let Some(parent) = node_data_mut.get(id).unwrap().parent { - let parent = node_data_mut.get_mut(parent).unwrap(); + let parent = (&mut node_data_mut).get(parent).unwrap(); parent.children.retain(|&child| child != id); } } @@ -82,19 +69,20 @@ impl Tree { pub fn remove_single(&mut self, id: NodeId) { { - let node_data_mut = self.node_slab_mut(); + let mut node_data_mut = self.node_data_mut(); if let Some(parent) = node_data_mut.get(id).unwrap().parent { - let parent = node_data_mut.get_mut(parent).unwrap(); + let parent = (&mut node_data_mut).get(parent).unwrap(); parent.children.retain(|&child| child != id); } } - self.nodes.remove(id); + self.nodes.delete_entity(id); } fn set_height(&mut self, node: NodeId, height: u16) { let children = { - let mut node = self.get_node_data_mut(node); + let mut node_data_mut = self.node_data_mut(); + let mut node = (&mut node_data_mut).get(node).unwrap(); node.height = height; node.children.clone() }; @@ -103,31 +91,33 @@ impl Tree { } } - pub fn create_node(&mut self) -> EntryBuilder<'_> { - let mut node = self.nodes.insert(); - node.insert(Node { + pub fn create_node(&mut self) -> NodeBuilder<'_> { + let node = self.nodes.add_entity((Node { parent: None, children: Vec::new(), height: 0, - }); - node + },)); + NodeBuilder { tree: self, node } } pub fn add_child(&mut self, parent: NodeId, new: NodeId) { - let node_state = self.node_slab_mut(); - node_state.get_mut(new).unwrap().parent = Some(parent); - let parent = node_state.get_mut(parent).unwrap(); - parent.children.push(new); - let height = parent.height + 1; + let height; + { + let mut node_state = self.node_data_mut(); + (&mut node_state).get(new).unwrap().parent = Some(parent); + let parent = (&mut node_state).get(parent).unwrap(); + parent.children.push(new); + height = parent.height + 1; + } self.set_height(new, height); } pub fn replace(&mut self, old_id: NodeId, new_id: NodeId) { { - let node_state = self.node_slab_mut(); + let mut node_state = self.node_data_mut(); // update the parent's link to the child if let Some(parent_id) = node_state.get(old_id).unwrap().parent { - let parent = node_state.get_mut(parent_id).unwrap(); + let parent = (&mut node_state).get(parent_id).unwrap(); for id in &mut parent.children { if *id == old_id { *id = new_id; @@ -135,6 +125,7 @@ impl Tree { } } let height = parent.height + 1; + drop(node_state); self.set_height(new_id, height); } } @@ -143,11 +134,11 @@ impl Tree { } pub fn insert_before(&mut self, old_id: NodeId, new_id: NodeId) { - let node_state = self.node_slab_mut(); + let mut node_state = self.node_data_mut(); let old_node = node_state.get(old_id).unwrap(); let parent_id = old_node.parent.expect("tried to insert before root"); - node_state.get_mut(new_id).unwrap().parent = Some(parent_id); - let parent = node_state.get_mut(parent_id).unwrap(); + (&mut node_state).get(new_id).unwrap().parent = Some(parent_id); + let parent = (&mut node_state).get(parent_id).unwrap(); let index = parent .children .iter() @@ -155,15 +146,16 @@ impl Tree { .unwrap(); parent.children.insert(index, new_id); let height = parent.height + 1; + drop(node_state); self.set_height(new_id, height); } pub fn insert_after(&mut self, old_id: NodeId, new_id: NodeId) { - let node_state = self.node_slab_mut(); + let mut node_state = self.node_data_mut(); let old_node = node_state.get(old_id).unwrap(); let parent_id = old_node.parent.expect("tried to insert before root"); - node_state.get_mut(new_id).unwrap().parent = Some(parent_id); - let parent = node_state.get_mut(parent_id).unwrap(); + (&mut node_state).get(new_id).unwrap().parent = Some(parent_id); + let parent = (&mut node_state).get(parent_id).unwrap(); let index = parent .children .iter() @@ -171,35 +163,16 @@ impl Tree { .unwrap(); parent.children.insert(index + 1, new_id); let height = parent.height + 1; + drop(node_state); self.set_height(new_id, height); } - pub fn size(&self) -> usize { - self.nodes.len() - } - - pub fn dynamically_borrowed(&mut self) -> DynamicallyBorrowedTree<'_> { - DynamicallyBorrowedTree { - nodes: self.nodes.dynamically_borrowed(), - } - } - - pub fn get(&self, id: NodeId) -> Option<&T> { - self.nodes.try_read_slab().and_then(|slab| slab.get(id)) - } - - pub fn get_mut(&mut self, id: NodeId) -> Option<&mut T> { - self.nodes - .try_write_slab() - .and_then(|slab| slab.get_mut(id)) - } - - pub fn insert(&mut self, id: NodeId, value: T) { - self.nodes.get_or_insert_slab_mut().insert(id, value); + pub fn insert(&mut self, id: NodeId, value: T) { + self.nodes.add_component(id, value); } pub fn contains(&self, id: NodeId) -> bool { - self.nodes.contains(id) + self.nodes.borrow::().unwrap().is_alive(id) } pub fn root(&self) -> NodeId { @@ -207,128 +180,18 @@ impl Tree { } pub fn parent_id(&self, id: NodeId) -> Option { - self.try_get_node_data(id).and_then(|node| node.parent) + let node_data = self.node_data(); + node_data.get(id).unwrap().parent } - pub fn children_ids(&self, id: NodeId) -> Option<&[NodeId]> { - self.try_get_node_data(id).map(|node| &*node.children) + pub fn children_ids(&self, id: NodeId) -> Option> { + let node_data = self.node_data(); + node_data.get(id).map(|node| node.children.clone()).ok() } pub fn height(&self, id: NodeId) -> Option { - self.try_get_node_data(id).map(|node| node.height) - } -} - -pub(crate) struct DynamicallyBorrowedTree<'a> { - nodes: DynamiclyBorrowedAnySlabView<'a>, -} - -impl<'a> DynamicallyBorrowedTree<'a> { - pub fn view( - &self, - immutable: impl IntoIterator, - mutable: impl IntoIterator, - ) -> TreeStateView<'_, 'a> { - let nodes_data = self.node_slab(); - let mut nodes = FxHashMap::default(); - for id in immutable { - nodes.insert(id, MaybeRead::Read(self.nodes.get_slab(id).unwrap())); - } - for id in mutable { - nodes.insert(id, MaybeRead::Write(self.nodes.get_slab_mut(id).unwrap())); - } - - TreeStateView { nodes_data, nodes } - } - - fn node_slab(&self) -> MappedRwLockReadGuard> { - RwLockReadGuard::map(self.nodes.get_slab(TypeId::of::()).unwrap(), |slab| { - slab.as_any().downcast_ref().unwrap() - }) - } -} - -enum MaybeRead<'a, 'b> { - Read(RwLockReadGuard<'a, &'b mut dyn AnySlabStorageImpl>), - Write(RwLockWriteGuard<'a, &'b mut dyn AnySlabStorageImpl>), -} - -#[derive(Clone, Copy)] -pub struct TreeStateViewEntry<'a, 'b> { - view: &'a TreeStateView<'a, 'b>, - id: NodeId, -} - -impl<'a, 'b> AnyMapLike<'a> for TreeStateViewEntry<'a, 'b> { - fn get(self) -> Option<&'a T> { - let slab = self.view.get_slab(); - slab.and_then(|slab| slab.get(self.id)) - } -} - -pub struct TreeStateView<'a, 'b> { - nodes_data: MappedRwLockReadGuard<'a, SlabStorage>, - nodes: FxHashMap>, -} - -impl<'a, 'b> TreeStateView<'a, 'b> { - pub fn get_slab(&self) -> Option<&SlabStorage> { - self.nodes - .get(&TypeId::of::()) - .and_then(|gaurd| match gaurd { - MaybeRead::Read(gaurd) => gaurd.as_any().downcast_ref::>(), - MaybeRead::Write(gaurd) => gaurd.as_any().downcast_ref::>(), - }) - } - - pub fn get_slab_mut(&mut self) -> Option<&mut SlabStorage> { - self.nodes - .get_mut(&TypeId::of::()) - .and_then(|gaurd| match gaurd { - MaybeRead::Read(_gaurd) => None, - MaybeRead::Write(gaurd) => gaurd.as_any_mut().downcast_mut::>(), - }) - } - - pub fn children_ids(&self, id: NodeId) -> Option<&[NodeId]> { - self.nodes_data.get(id).map(|node| &*node.children) - } - - pub fn parent_id(&self, id: NodeId) -> Option { - self.nodes_data.get(id).and_then(|node| node.parent) - } - - pub fn height(&self, id: NodeId) -> Option { - self.nodes_data.get(id).map(|n| n.height) - } - - pub fn get(&self, id: NodeId) -> Option> { - T::borrow_elements_from(self.entry(id)) - } - - pub fn get_single(&self, id: NodeId) -> Option<&T> { - self.get_slab().and_then(|slab| slab.get(id)) - } - - pub fn get_mut(&mut self, id: NodeId) -> Option<&mut T> { - self.get_slab_mut().and_then(|slab| slab.get_mut(id)) - } - - pub fn entry(&self, id: NodeId) -> TreeStateViewEntry<'_, 'b> { - TreeStateViewEntry { view: self, id } - } - - pub fn children(&self, id: NodeId) -> Option>> { - let ids = self.children_ids(id); - ids.and_then(|ids| { - ids.iter() - .map(|id| T::borrow_elements_from(self.entry(*id))) - .collect() - }) - } - - pub fn parent(&self, id: NodeId) -> Option> { - T::borrow_elements_from(self.entry(self.parent_id(id)?)) + let node_data = self.node_data(); + node_data.get(id).map(|node| node.height).ok() } } @@ -464,244 +327,17 @@ fn deletion() { assert_eq!(tree.get::(after), None); } -#[derive(Debug)] -pub struct SlabStorage { - data: Vec>, +pub struct NodeBuilder<'a> { + tree: &'a mut Tree, + node: EntityId, } -impl Default for SlabStorage { - fn default() -> Self { - Self { data: Vec::new() } +impl<'a> NodeBuilder<'a> { + pub fn insert(&mut self, component: T) { + self.tree.insert(self.node, component); + } + + pub fn id(&self) -> EntityId { + self.node } } - -trait AnySlabStorageImpl: Any + Send + Sync { - fn remove(&mut self, id: NodeId); - fn as_any(&self) -> &dyn Any; - fn as_any_mut(&mut self) -> &mut dyn Any; -} - -impl SlabStorage { - fn get(&self, id: NodeId) -> Option<&T> { - self.data.get(id.0).and_then(|x| x.as_ref()) - } - - fn get_mut(&mut self, id: NodeId) -> Option<&mut T> { - self.data.get_mut(id.0).and_then(|x| x.as_mut()) - } - - pub fn entry(&mut self, id: NodeId) -> SlabEntry<'_, T> { - let idx = id.0; - if idx >= self.data.len() { - self.data.resize_with(idx + 1, || None); - } - SlabEntry { - value: &mut self.data[idx], - } - } - - fn insert(&mut self, id: NodeId, value: T) { - let idx = id.0; - if idx >= self.data.len() { - self.data.resize_with(idx + 1, || None); - } - self.data[idx] = Some(value); - } -} - -pub struct SlabEntry<'a, T> { - pub value: &'a mut Option, -} - -impl<'a, T> SlabEntry<'a, T> { - pub fn or_insert_with T>(self, f: F) -> &'a mut T { - self.value.get_or_insert_with(f) - } - - pub fn or_insert(self, value: T) -> &'a mut T { - self.value.get_or_insert(value) - } - - pub fn or_default(self) -> &'a mut T - where - T: Default, - { - self.value.get_or_insert_with(Default::default) - } -} - -impl AnySlabStorageImpl for SlabStorage { - fn remove(&mut self, id: NodeId) { - if let Some(entry) = self.data.get_mut(id.0) { - let _ = entry.take(); - } - } - - fn as_any(&self) -> &dyn Any { - self - } - - fn as_any_mut(&mut self) -> &mut dyn Any { - self - } -} - -pub(crate) struct DynamiclyBorrowedAnySlabView<'a> { - data: hashbrown::HashMap< - TypeId, - RwLock<&'a mut dyn AnySlabStorageImpl>, - BuildHasherDefault, - >, -} - -impl<'a> DynamiclyBorrowedAnySlabView<'a> { - fn get_slab<'b>( - &'b self, - type_id: TypeId, - ) -> Option> { - self.data.get(&type_id).map(|x| x.read()) - } - - fn get_slab_mut<'b>( - &'b self, - type_id: TypeId, - ) -> Option> { - self.data.get(&type_id).map(|x| x.write()) - } -} - -pub(crate) struct AnySlab { - data: hashbrown::HashMap, BuildHasherDefault>, - filled: Vec, - free: VecDeque, - len: usize, -} - -impl Debug for AnySlab { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("AnySlab") - .field("data", &self.data.keys().collect::>()) - .field("free", &self.free) - .field("len", &self.len) - .finish() - } -} - -impl Default for AnySlab { - fn default() -> Self { - Self::new() - } -} - -impl AnySlab { - fn new() -> Self { - Self { - data: Default::default(), - filled: Default::default(), - free: VecDeque::new(), - len: 0, - } - } - - fn try_read_slab(&self) -> Option<&SlabStorage> { - self.data - .get(&TypeId::of::()) - .map(|x| x.as_any().downcast_ref().unwrap()) - } - - fn read_slab(&self) -> &SlabStorage { - self.try_read_slab().unwrap() - } - - fn try_write_slab(&mut self) -> Option<&mut SlabStorage> { - self.data - .get_mut(&TypeId::of::()) - .map(|x| x.as_any_mut().downcast_mut().unwrap()) - } - - fn write_slab(&mut self) -> &mut SlabStorage { - self.try_write_slab().unwrap() - } - - fn get_or_insert_slab_mut(&mut self) -> &mut SlabStorage { - self.data - .entry(TypeId::of::()) - .or_insert_with(|| Box::>::default()) - .as_any_mut() - .downcast_mut() - .unwrap() - } - - fn insert(&mut self) -> EntryBuilder<'_> { - let id = if let Some(id) = self.free.pop_front() { - self.filled[id.0] = true; - id - } else { - let id = self.len; - self.filled.push(true); - self.len += 1; - NodeId(id) - }; - EntryBuilder { id, inner: self } - } - - fn remove(&mut self, id: NodeId) { - for slab in self.data.values_mut() { - slab.remove(id); - } - self.filled[id.0] = true; - self.free.push_back(id); - } - - fn len(&self) -> usize { - self.len - self.free.len() - } - - fn contains(&self, id: NodeId) -> bool { - self.filled.get(id.0).copied().unwrap_or_default() - } - - fn dynamically_borrowed(&mut self) -> DynamiclyBorrowedAnySlabView<'_> { - DynamiclyBorrowedAnySlabView { - data: self - .data - .iter_mut() - .map(|(k, v)| (*k, RwLock::new(&mut **v))) - .collect(), - } - } -} - -pub(crate) struct EntryBuilder<'a> { - id: NodeId, - inner: &'a mut AnySlab, -} - -impl EntryBuilder<'_> { - pub fn insert(&mut self, value: T) { - self.inner - .get_or_insert_slab_mut::() - .insert(self.id, value); - } - - pub fn id(&self) -> NodeId { - self.id - } -} - -#[test] -fn remove() { - let mut slab = AnySlab::new(); - let mut node1 = slab.insert(); - node1.insert(0i32); - let node1_id = node1.id(); - let mut node2 = slab.insert(); - node2.insert(0i32); - - assert_eq!(slab.len(), 2); - - slab.remove(node1_id); - - assert!(slab.read_slab::().get(node1_id).is_none()); - assert_eq!(slab.len(), 1); -} diff --git a/packages/native-core/src/utils/persistant_iterator.rs b/packages/native-core/src/utils/persistant_iterator.rs index 0e87c03f2..2469e3ce4 100644 --- a/packages/native-core/src/utils/persistant_iterator.rs +++ b/packages/native-core/src/utils/persistant_iterator.rs @@ -73,7 +73,7 @@ pub struct PersistantElementIter { impl PersistantElementIter { pub fn create(rdom: &mut RealDom) -> Self { - let inner = Arc::new(Mutex::new(smallvec::smallvec![NodeId(0)])); + let inner = Arc::new(Mutex::new(smallvec::smallvec![rdom.root_id()])); rdom.add_node_watcher(PersistantElementIterUpdater { stack: inner.clone(), @@ -87,7 +87,7 @@ impl PersistantElementIter { pub fn next(&mut self, rdom: &RealDom) -> ElementProduced { let mut stack = self.stack.lock().unwrap(); if stack.is_empty() { - let id = NodeId(0); + let id = rdom.root_id(); let new = id; stack.push(new); ElementProduced::Looped(id) @@ -113,7 +113,7 @@ impl PersistantElementIter { // otherwise, continue the loop and go to the parent } else { // if there is no parent, loop back to the root - let new = NodeId(0); + let new = rdom.root_id(); stack.clear(); stack.push(new); return ElementProduced::Looped(new); @@ -139,7 +139,7 @@ impl PersistantElementIter { } let mut stack = self.stack.lock().unwrap(); if stack.is_empty() { - let id = NodeId(0); + let id = rdom.root_id(); let last = push_back(&mut stack, rdom.get(id).unwrap()); ElementProduced::Looped(last) } else if let Some(current) = stack.pop().and_then(|last| rdom.get(last)) { @@ -154,13 +154,13 @@ impl PersistantElementIter { ElementProduced::Progressed(*parent) } else { // if there is no parent, loop back to the root - let id = NodeId(0); + let id = rdom.root_id(); let last = push_back(&mut stack, rdom.get(id).unwrap()); ElementProduced::Looped(last) } } else { // if there is no parent, loop back to the root - let id = NodeId(0); + let id = rdom.root_id(); let last = push_back(&mut stack, rdom.get(id).unwrap()); ElementProduced::Looped(last) }