From a8566b4e71bd3d77b9054ce22eb2a4bea018ab28 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 7 Mar 2023 16:00:43 -0600 Subject: [PATCH] finish shipyard migration in native-core --- Cargo.toml | 1 + packages/native-core-macro/src/lib.rs | 128 ++++++++++++-- packages/native-core/Cargo.toml | 1 + packages/native-core/src/dioxus.rs | 3 +- packages/native-core/src/passes.rs | 236 +++++++++++--------------- packages/native-core/src/real_dom.rs | 194 ++++++++++++++------- packages/native-core/src/tree.rs | 158 ++++++++--------- 7 files changed, 414 insertions(+), 307 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index af0a1b916..e32940e18 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ members = [ "packages/rsx", "packages/tui", "packages/native-core", + "packages/native-core-macro", "packages/rsx-rosetta", "packages/signals", "packages/hot-reload", diff --git a/packages/native-core-macro/src/lib.rs b/packages/native-core-macro/src/lib.rs index 21fbb7e89..098b4c8c6 100644 --- a/packages/native-core-macro/src/lib.rs +++ b/packages/native-core-macro/src/lib.rs @@ -1,22 +1,126 @@ extern crate proc_macro; -mod sorted_slice; +use std::collections::HashSet; 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, -}; +use quote::quote; +use syn::Type; /// A helper attribute for deriving `State` for a struct. #[proc_macro_attribute] -pub fn my_attribute(_: TokenStream, input: TokenStream) -> TokenStream { +pub fn partial_derive_pass(_: TokenStream, input: TokenStream) -> TokenStream { let impl_block: syn::ItemImpl = syn::parse(input).unwrap(); + + let parent_dependencies = impl_block + .items + .iter() + .find_map(|item| { + if let syn::ImplItem::Type(syn::ImplItemType { + attrs, ident, ty, .. + }) = item + { + (ident == "ParentDependencies").then_some(ty) + } else { + None + } + }) + .unwrap(); + let child_dependencies = impl_block + .items + .iter() + .find_map(|item| { + if let syn::ImplItem::Type(syn::ImplItemType { + attrs, ident, ty, .. + }) = item + { + (ident == "ChildDependencies").then_some(ty) + } else { + None + } + }) + .unwrap(); + let node_dependencies = impl_block + .items + .iter() + .find_map(|item| { + if let syn::ImplItem::Type(syn::ImplItemType { + attrs, ident, ty, .. + }) = item + { + (ident == "NodeDependencies").then_some(ty) + } else { + None + } + }) + .unwrap(); + + let this_type = &impl_block.self_ty; + + let mut combined_dependencies = HashSet::new(); + + match parent_dependencies { + Type::Tuple(tuple) => { + for type_ in &tuple.elems { + combined_dependencies.insert(type_.clone()); + } + } + _ => panic!("ParentDependencies must be a tuple"), + } + match child_dependencies { + Type::Tuple(tuple) => { + for type_ in &tuple.elems { + combined_dependencies.insert(type_.clone()); + } + } + _ => panic!("ChildDependencies must be a tuple"), + } + match node_dependencies { + Type::Tuple(tuple) => { + for type_ in &tuple.elems { + combined_dependencies.insert(type_.clone()); + } + } + _ => panic!("NodeDependencies must be a tuple"), + } + combined_dependencies.insert(*this_type.clone()); + + let combined_dependencies = combined_dependencies.into_iter(); + let combined_dependencies = quote!((#(#combined_dependencies),*)); + quote!(#impl_block).into() } + +// pub trait State: Any + Send + Sync { +// /// This is a tuple of (T: Pass, ..) of states read from the parent required to run this pass +// type ParentDependencies: Dependancy; +// /// This is a tuple of (T: Pass, ..) of states read from the children required to run this pass +// type ChildDependencies: Dependancy; +// /// This is a tuple of (T: Pass, ..) of states read from the node required to run this pass +// type NodeDependencies: Dependancy; +// /// A tuple of all the dependencies combined +// type CombinedDependencies: Dependancy; +// /// This is a mask of what aspects of the node are required to run this pass +// const NODE_MASK: NodeMaskBuilder<'static>; +// +// /// Update this state in a node, returns if the state was updated +// fn update<'a>( +// &mut self, +// node_view: NodeView, +// node: ::ElementBorrowed<'a>, +// parent: Option<::ElementBorrowed<'a>>, +// children: Option::ElementBorrowed<'a>>>, +// context: &SendAnyMap, +// ) -> bool; +// +// /// Create a new instance of this state +// fn create<'a>( +// node_view: NodeView, +// node: ::ElementBorrowed<'a>, +// parent: Option<::ElementBorrowed<'a>>, +// children: Option::ElementBorrowed<'a>>>, +// context: &SendAnyMap, +// ) -> Self; +// +// /// Create a workload system for this state +// fn workload_system(dependants: FxHashSet) -> WorkloadSystem; +// } diff --git a/packages/native-core/Cargo.toml b/packages/native-core/Cargo.toml index d5e724e86..5b5868de9 100644 --- a/packages/native-core/Cargo.toml +++ b/packages/native-core/Cargo.toml @@ -29,6 +29,7 @@ lightningcss = "1.0.0-alpha.39" rayon = "1.6.1" shipyard = "0.6.2" +shipyard_hierarchy = "0.6.0" [dev-dependencies] diff --git a/packages/native-core/src/dioxus.rs b/packages/native-core/src/dioxus.rs index ffc80c1c7..4deada6ab 100644 --- a/packages/native-core/src/dioxus.rs +++ b/packages/native-core/src/dioxus.rs @@ -1,3 +1,4 @@ +use crate::tree::TreeMut; use dioxus_core::{BorrowedAttributeValue, ElementId, Mutations, TemplateNode}; use rustc_hash::{FxHashMap, FxHashSet}; use shipyard::Component; @@ -155,7 +156,7 @@ impl DioxusState { 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); + rdom.tree_mut().insert_before(old_node_id, new); } } SetAttribute { diff --git a/packages/native-core/src/passes.rs b/packages/native-core/src/passes.rs index 31b873dde..b93ee074f 100644 --- a/packages/native-core/src/passes.rs +++ b/packages/native-core/src/passes.rs @@ -1,7 +1,10 @@ use anymap::AnyMap; use parking_lot::RwLock; use rustc_hash::{FxHashMap, FxHashSet}; -use shipyard::{Component, IntoBorrow, Unique, View, WorkloadSystem}; +use shipyard::{ + BorrowInfo, Component, IntoBorrow, IntoWorkloadSystem, Unique, UniqueView, View, + WorkloadSystem, World, +}; use std::any::{Any, TypeId}; use std::collections::BTreeMap; use std::marker::PhantomData; @@ -9,7 +12,9 @@ use std::sync::Arc; use crate::node::FromAnyValue; use crate::node_ref::{NodeMaskBuilder, NodeView}; -use crate::SendAnyMap; +use crate::real_dom::{DirtyNodesResult, SendAnyMapWrapper}; +use crate::tree::{TreeMut, TreeRef, TreeRefView}; +use crate::{FxDashSet, SendAnyMap}; use crate::{NodeId, NodeMask}; #[derive(Default)] @@ -108,6 +113,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; + /// A tuple of all the dependencies combined type CombinedDependencies: Dependancy; /// This is a mask of what aspects of the node are required to run this pass const NODE_MASK: NodeMaskBuilder<'static>; @@ -130,39 +136,93 @@ pub trait State: Any + Send + Sync { children: Option::ElementBorrowed<'a>>>, context: &SendAnyMap, ) -> Self; + + /// Create a workload system for this state + fn workload_system(dependants: FxHashSet) -> WorkloadSystem; +} + +pub struct RunPassView<'a> { + type_id: TypeId, + dependants: FxHashSet, + pass_direction: PassDirection, + tree: TreeRefView<'a>, + nodes_updated: UniqueView<'a, DirtyNodesResult>, + dirty: UniqueView<'a, DirtyNodeStates>, + ctx: UniqueView<'a, SendAnyMapWrapper>, +} + +impl<'a> RunPassView<'a> { + pub fn borrow( + type_id: TypeId, + dependants: FxHashSet, + pass_direction: PassDirection, + world: &'a World, + ) -> Self { + Self { + type_id, + dependants, + pass_direction, + tree: world.borrow().unwrap(), + nodes_updated: world.borrow().unwrap(), + dirty: world.borrow().unwrap(), + ctx: world.borrow().unwrap(), + } + } +} + +pub fn run_pass(view: RunPassView, mut update_node: impl FnMut(NodeId, &SendAnyMap) -> bool) { + let RunPassView { + type_id, + dependants, + pass_direction, + tree, + nodes_updated, + dirty, + ctx, + } = view; + let ctx = ctx.as_ref(); + match pass_direction { + PassDirection::ParentToChild => { + while let Some((height, id)) = dirty.pop_front(type_id) { + let id = tree.id_at(id).unwrap(); + if (update_node)(id, ctx) { + nodes_updated.insert(id); + for id in tree.children_ids(id).unwrap() { + for dependant in &dependants { + dirty.insert(*dependant, id, height + 1); + } + } + } + } + } + PassDirection::ChildToParent => { + while let Some((height, id)) = dirty.pop_back(type_id) { + let id = tree.id_at(id).unwrap(); + if (update_node)(id, ctx) { + nodes_updated.insert(id); + if let Some(id) = tree.parent_id(id) { + for dependant in &dependants { + dirty.insert(*dependant, id, height - 1); + } + } + } + } + } + PassDirection::AnyOrder => { + while let Some((height, id)) = dirty.pop_back(type_id) { + let id = tree.id_at(id).unwrap(); + if (update_node)(id, ctx) { + nodes_updated.insert(id); + for dependant in &dependants { + dirty.insert(*dependant, id, height); + } + } + } + } + } } 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, @@ -174,9 +234,9 @@ pub trait AnyState: State { parent_dependant: !Self::parent_type_ids().is_empty(), child_dependant: !Self::child_type_ids().is_empty(), dependants: FxHashSet::default(), - mask: node_mask.clone(), + mask: node_mask, pass_direction: Self::pass_direction(), - workload: Some(Self::workload_system()), + workload: Self::workload_system, phantom: PhantomData, } } @@ -224,58 +284,11 @@ pub struct TypeErasedPass { pub(crate) combined_dependancy_type_ids: FxHashSet, pub(crate) dependants: FxHashSet, pub(crate) mask: NodeMask, - pub(crate) workload: Option, + pub(crate) workload: fn(FxHashSet) -> WorkloadSystem, 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); -// } -// } -// } -// } -// } -// } -// } - #[derive(Debug)] pub enum PassDirection { ParentToChild, @@ -300,7 +313,7 @@ impl<'a> AnyMapLike<'a> for &'a SendAnyMap { } pub trait Dependancy { - type ElementBorrowed<'a>: IntoBorrow; + type ElementBorrowed<'a>: IntoBorrow + BorrowInfo; fn type_ids() -> Box<[TypeId]> { Box::new([]) @@ -330,60 +343,3 @@ 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); - -// 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 5908f8e4b..c87564dab 100644 --- a/packages/native-core/src/real_dom.rs +++ b/packages/native-core/src/real_dom.rs @@ -1,10 +1,8 @@ use rustc_hash::{FxHashMap, FxHashSet}; use shipyard::error::GetStorage; use shipyard::track::Untracked; -use shipyard::{ - Component, Get, IntoBorrow, ScheduledWorkload, System, Unique, View, ViewMut, Workload, - WorkloadSystem, -}; +use shipyard::{Component, Get, IntoBorrow, ScheduledWorkload, Unique, View, ViewMut, Workload}; +use shipyard::{SystemModificator, World}; use std::any::TypeId; use std::collections::VecDeque; use std::ops::{Deref, DerefMut}; @@ -17,17 +15,33 @@ use crate::node_ref::{NodeMask, NodeMaskBuilder}; use crate::node_watcher::NodeWatcher; use crate::passes::{DirtyNodeStates, TypeErasedPass}; use crate::prelude::AttributeMaskBuilder; -use crate::tree::Tree; +use crate::tree::{TreeMut, TreeMutView, TreeRef, TreeRefView}; use crate::NodeId; use crate::{FxDashSet, SendAnyMap}; #[derive(Unique)] -struct SendAnyMapWrapper(SendAnyMap); +pub struct SendAnyMapWrapper(SendAnyMap); + +impl Deref for SendAnyMapWrapper { + type Target = SendAnyMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} #[derive(Unique, Default)] -struct DirtyNodes(FxDashSet); +pub struct DirtyNodesResult(FxDashSet); -pub(crate) struct NodesDirty { +impl Deref for DirtyNodesResult { + type Target = FxDashSet; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +pub struct NodesDirty { passes_updated: FxHashMap>, nodes_updated: FxHashMap, pub(crate) passes: Box<[TypeErasedPass]>, @@ -76,31 +90,27 @@ type NodeWatchers = Arc + Send + Sync>>>>; /// # Custom values /// To allow custom values to be passed into attributes implement FromAnyValue on a type that can represent your custom value and specify the V generic to be that type. If you have many different custom values, it can be useful to use a enum type to represent the varients. pub struct RealDom { - pub(crate) tree: Tree, + pub(crate) world: World, nodes_listening: FxHashMap>, pub(crate) dirty_nodes: NodesDirty, node_watchers: NodeWatchers, workload: ScheduledWorkload, + root_id: NodeId, phantom: std::marker::PhantomData, } impl RealDom { pub fn new(mut passes: Box<[TypeErasedPass]>) -> RealDom { - let mut tree = Tree::new(); - 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 = construct_workload(&mut passes); let (workload, _) = workload.build().unwrap(); - let root_id = tree.root(); + let mut world = World::new(); let root_node: NodeType = NodeType::Element(ElementNode { tag: "Root".to_string(), namespace: Some("Root".to_string()), attributes: FxHashMap::default(), listeners: FxHashSet::default(), }); - tree.insert(root_id, root_node); + let root_id = world.add_entity(root_node); // resolve dependants for each pass for i in 1..passes.len() { @@ -122,7 +132,7 @@ impl RealDom { nodes_updated.insert(root_id, NodeMaskBuilder::ALL.build()); RealDom { - tree, + world, nodes_listening: FxHashMap::default(), dirty_nodes: NodesDirty { passes_updated, @@ -131,19 +141,27 @@ impl RealDom { }, node_watchers: Default::default(), workload, + root_id, phantom: std::marker::PhantomData, } } + pub fn tree_mut(&self) -> TreeMutView { + self.world.borrow().unwrap() + } + + pub fn tree_ref(&self) -> TreeRefView { + self.world.borrow().unwrap() + } + pub fn create_node(&mut self, node: NodeType) -> NodeMut<'_, V> { - let mut node_entry = self.tree.create_node(); - let id = node_entry.id(); + let id = self.world.add_entity(node); + self.tree_mut().create_node(id); self.dirty_nodes .passes_updated .entry(id) .or_default() .extend(self.dirty_nodes.passes.iter().map(|x| x.this_type_id)); - node_entry.insert(node); let watchers = self.node_watchers.clone(); for watcher in &*watchers.read().unwrap() { watcher.on_node_added(NodeMut::new(id, self)); @@ -157,7 +175,7 @@ impl RealDom { if let Some(nodes) = self.nodes_listening.get(event) { let mut listening: Vec<_> = nodes .iter() - .map(|id| (*id, self.tree.height(*id).unwrap())) + .map(|id| (*id, self.tree_ref().height(*id).unwrap())) .collect(); listening.sort_by(|(_, h1), (_, h2)| h1.cmp(h2).reverse()); listening @@ -171,26 +189,29 @@ impl RealDom { /// Returns the id of the root node. pub fn root_id(&self) -> NodeId { - self.tree.root() + self.root_id } pub fn get(&self, id: NodeId) -> Option> { - self.tree.contains(id).then_some(NodeRef { id, dom: self }) + self.tree_ref() + .contains(id) + .then_some(NodeRef { id, dom: self }) } pub fn get_mut(&mut self, id: NodeId) -> Option> { - self.tree.contains(id).then(|| NodeMut::new(id, self)) + let contains = { self.tree_ref().contains(id) }; + contains.then(|| NodeMut::new(id, self)) } fn borrow_raw<'a, B: IntoBorrow>(&'a self) -> Result where B::Borrow: shipyard::Borrow<'a, View = B>, { - self.tree.nodes.borrow() + self.world.borrow() } fn borrow_node_type_mut(&self) -> Result>, GetStorage> { - self.tree.nodes.borrow() + self.world.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. @@ -202,34 +223,36 @@ impl RealDom { let nodes_updated = std::mem::take(&mut self.dirty_nodes.nodes_updated); let dirty_nodes = DirtyNodeStates::with_passes(self.dirty_nodes.passes.iter().map(|p| p.this_type_id)); + let tree = self.tree_ref(); for (node_id, passes) in passes { // remove any nodes that were created and then removed in the same mutations from the dirty nodes list - if let Some(height) = self.tree.height(node_id) { + if let Some(height) = tree.height(node_id) { for pass in passes { dirty_nodes.insert(pass, node_id, height); } } } - 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()); + let _ = self.world.remove_unique::(); + let _ = self.world.remove_unique::(); + self.world.add_unique(dirty_nodes); + self.world.add_unique(SendAnyMapWrapper(ctx)); + self.world.add_unique(DirtyNodesResult::default()); - self.workload.run_with_world(&self.tree.nodes).unwrap(); + self.workload.run_with_world(&self.world).unwrap(); - let dirty = self.tree.remove_unique::().unwrap(); + let dirty = self.world.remove_unique::().unwrap(); (dirty.0, nodes_updated) } pub fn traverse_depth_first(&self, mut f: impl FnMut(NodeRef)) { let mut stack = vec![self.root_id()]; + let tree = self.tree_ref(); while let Some(id) = stack.pop() { if let Some(node) = self.get(id) { f(node); - if let Some(children) = self.tree.children_ids(id) { + if let Some(children) = tree.children_ids(id) { stack.extend(children.iter().copied().rev()); } } @@ -239,10 +262,11 @@ impl RealDom { pub fn traverse_breadth_first(&self, mut f: impl FnMut(NodeRef)) { let mut queue = VecDeque::new(); queue.push_back(self.root_id()); + let tree = self.tree_ref(); while let Some(id) = queue.pop_front() { if let Some(node) = self.get(id) { f(node); - if let Some(children) = self.tree.children_ids(id) { + if let Some(children) = tree.children_ids(id) { for id in children { queue.push_back(id); } @@ -254,8 +278,10 @@ impl RealDom { pub fn traverse_depth_first_mut(&mut self, mut f: impl FnMut(NodeMut)) { 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::>(); + let tree = self.tree_ref(); + if let Some(mut children) = tree.children_ids(id) { + drop(tree); + children.reverse(); if let Some(node) = self.get_mut(id) { let node = node; f(node); @@ -269,8 +295,9 @@ impl RealDom { let mut queue = VecDeque::new(); 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(); + let tree = self.tree_ref(); + if let Some(children) = tree.children_ids(id) { + drop(tree); if let Some(node) = self.get_mut(id) { f(node); for id in children { @@ -349,7 +376,7 @@ pub trait NodeImmutable: Sized { #[inline] fn child_ids(&self) -> Option> { - self.real_dom().tree.children_ids(self.id()) + self.real_dom().tree_ref().children_ids(self.id()) } #[inline] @@ -368,7 +395,7 @@ pub trait NodeImmutable: Sized { #[inline] fn parent_id(&self) -> Option { - self.real_dom().tree.parent_id(self.id()) + self.real_dom().tree_ref().parent_id(self.id()) } #[inline] @@ -382,7 +409,7 @@ pub trait NodeImmutable: Sized { #[inline] fn next(&self) -> Option> { let parent = self.parent_id()?; - let children = self.real_dom().tree.children_ids(parent)?; + let children = self.real_dom().tree_ref().children_ids(parent)?; let index = children.iter().position(|id| *id == self.id())?; if index + 1 < children.len() { Some(NodeRef { @@ -397,7 +424,7 @@ pub trait NodeImmutable: Sized { #[inline] fn prev(&self) -> Option> { let parent = self.parent_id()?; - let children = self.real_dom().tree.children_ids(parent)?; + let children = self.real_dom().tree_ref().children_ids(parent)?; let index = children.iter().position(|id| *id == self.id())?; if index > 0 { Some(NodeRef { @@ -411,7 +438,7 @@ pub trait NodeImmutable: Sized { #[inline] fn height(&self) -> u16 { - self.real_dom().tree.height(self.id()).unwrap() + self.real_dom().tree_ref().height(self.id()).unwrap() } } @@ -501,13 +528,13 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { .entry(self.id) .or_default() .insert(TypeId::of::()); - self.dom.tree.insert(self.id, value); + self.dom.world.add_component(self.id, value); } #[inline] pub fn next_mut(self) -> Option> { let parent = self.parent_id()?; - let children = self.dom.tree.children_ids(parent)?; + let children = self.dom.tree_mut().children_ids(parent)?; let index = children.iter().position(|id| *id == self.id)?; if index + 1 < children.len() { Some(NodeMut::new(children[index + 1], self.dom)) @@ -519,7 +546,7 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { #[inline] pub fn prev_mut(self) -> Option> { let parent = self.parent_id()?; - let children = self.dom.tree.children_ids(parent)?; + let children = self.dom.tree_ref().children_ids(parent)?; let index = children.iter().position(|id| *id == self.id)?; if index > 0 { Some(NodeMut::new(children[index - 1], self.dom)) @@ -532,29 +559,31 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { pub fn add_child(&mut self, child: NodeId) { self.dom.dirty_nodes.mark_child_changed(self.id); self.dom.dirty_nodes.mark_parent_added_or_removed(child); - self.dom.tree.add_child(self.id, child); + self.dom.tree_mut().add_child(self.id, child); NodeMut::new(child, self.dom).mark_moved(); } #[inline] pub fn insert_after(&mut self, old: NodeId) { let id = self.id(); - if let Some(parent_id) = self.dom.tree.parent_id(old) { + let parent_id = { self.dom.tree_ref().parent_id(old) }; + if let Some(parent_id) = parent_id { self.dom.dirty_nodes.mark_child_changed(parent_id); self.dom.dirty_nodes.mark_parent_added_or_removed(id); } - self.dom.tree.insert_after(old, id); + self.dom.tree_mut().insert_after(old, id); self.mark_moved(); } #[inline] pub fn insert_before(&mut self, old: NodeId) { let id = self.id(); - if let Some(parent_id) = self.dom.tree.parent_id(old) { + let parent_id = { self.dom.tree_ref().parent_id(old) }; + if let Some(parent_id) = parent_id { self.dom.dirty_nodes.mark_child_changed(parent_id); self.dom.dirty_nodes.mark_parent_added_or_removed(id); } - self.dom.tree.insert_before(old, id); + self.dom.tree_mut().insert_before(old, id); self.mark_moved(); } @@ -563,11 +592,11 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { let id = self.id(); { let RealDom { - tree, + world, nodes_listening, .. } = &mut self.dom; - let mut view: ViewMut> = tree.nodes.borrow().unwrap(); + let mut view: ViewMut> = world.borrow().unwrap(); if let NodeType::Element(ElementNode { listeners, .. }) | NodeType::Text(TextNode { listeners, .. }) = (&mut view).get(id).unwrap() { @@ -578,7 +607,8 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { } } self.mark_removed(); - if let Some(parent_id) = self.real_dom_mut().tree.parent_id(id) { + let parent_id = { self.dom.tree_ref().parent_id(id) }; + if let Some(parent_id) = parent_id { self.real_dom_mut() .dirty_nodes .mark_child_changed(parent_id); @@ -589,7 +619,7 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { self.dom.get_mut(child).unwrap().remove(); } } - self.dom.tree.remove_single(id); + self.dom.tree_mut().remove_single(id); } #[inline] @@ -604,19 +634,19 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { .mark_parent_added_or_removed(new); } let id = self.id(); - self.dom.tree.replace(id, new); + self.dom.tree_mut().replace(id, new); } #[inline] pub fn add_event_listener(&mut self, event: &str) { let id = self.id(); let RealDom { - tree, + world, dirty_nodes, nodes_listening, .. } = &mut self.dom; - let mut view: ViewMut> = tree.nodes.borrow().unwrap(); + let mut view: ViewMut> = world.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 @@ -640,12 +670,12 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { pub fn remove_event_listener(&mut self, event: &str) { let id = self.id(); let RealDom { - tree, + world, dirty_nodes, nodes_listening, .. } = &mut self.dom; - let mut view: ViewMut> = tree.nodes.borrow().unwrap(); + let mut view: ViewMut> = world.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 @@ -674,9 +704,9 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> { pub fn node_type_mut(&mut self) -> NodeTypeMut<'_, V> { let id = self.id(); let RealDom { - tree, dirty_nodes, .. + world, dirty_nodes, .. } = &mut self.dom; - let view: ViewMut> = tree.nodes.borrow().unwrap(); + let view: ViewMut> = world.borrow().unwrap(); let node_type = ViewEntryMut::new(view, id); match &*node_type { NodeType::Element(_) => NodeTypeMut::Element(ElementNodeMut { @@ -857,3 +887,37 @@ impl ElementNodeMut<'_, V> { &self.element().listeners } } + +fn construct_workload(passes: &mut [TypeErasedPass]) -> Workload { + let mut workload = Workload::new("Main Workload"); + let mut unresloved_workloads = passes + .iter_mut() + .enumerate() + .map(|(i, pass)| { + let workload = Some((pass.workload)(pass.dependants.clone())); + (i, pass, workload) + }) + .collect::>(); + // set all the labels + for (id, _, workload) in &mut unresloved_workloads { + *workload = Some(workload.take().unwrap().tag(id.to_string())); + } + // mark any dependancies + for i in 0..unresloved_workloads.len() { + let (_, pass, _) = &unresloved_workloads[i]; + for ty_id in pass.combined_dependancy_type_ids.clone() { + let &(dependancy_id, _, _) = unresloved_workloads + .iter() + .find(|(_, pass, _)| pass.this_type_id == ty_id) + .unwrap(); + let (_, _, workload) = &mut unresloved_workloads[i]; + *workload = workload + .take() + .map(|workload| workload.tag(dependancy_id.to_string())); + } + } + for (_, _, mut workload_system) in unresloved_workloads { + workload = workload.with_system(workload_system.take().unwrap()); + } + workload +} diff --git a/packages/native-core/src/tree.rs b/packages/native-core/src/tree.rs index 0d8bab7c9..f1c542a3c 100644 --- a/packages/native-core/src/tree.rs +++ b/packages/native-core/src/tree.rs @@ -1,63 +1,65 @@ use crate::NodeId; -use shipyard::{Component, EntitiesView, EntityId, Get, Unique, View, ViewMut, World}; +use shipyard::{Component, EntitiesViewMut, Get, View, ViewMut}; use std::fmt::Debug; #[derive(PartialEq, Eq, Clone, Debug, Component)] -pub(crate) struct Node { +pub struct Node { parent: Option, children: Vec, height: u16, } -#[derive(Debug)] -pub(crate) struct Tree { - pub(crate) nodes: World, - root: NodeId, +pub type TreeRefView<'a> = View<'a, Node>; +pub type TreeMutView<'a> = (EntitiesViewMut<'a>, ViewMut<'a, Node>); + +pub trait TreeRef { + fn parent_id(&self, id: NodeId) -> Option; + fn children_ids(&self, id: NodeId) -> Option>; + fn height(&self, id: NodeId) -> Option; + fn contains(&self, id: NodeId) -> bool; } -impl Tree { - pub fn new() -> Self { - let mut nodes = World::default(); - let node = Node { - parent: None, - children: Vec::new(), - height: 0, - }; - let root = nodes.add_entity((node,)); - Self { nodes, root } +pub trait TreeMut: TreeRef { + fn remove(&mut self, id: NodeId); + fn remove_single(&mut self, id: NodeId); + fn set_height(&mut self, node: NodeId, height: u16); + fn create_node(&mut self, id: NodeId); + fn add_child(&mut self, parent: NodeId, new: NodeId); + fn replace(&mut self, old_id: NodeId, new_id: NodeId); + fn insert_before(&mut self, old_id: NodeId, new_id: NodeId); + fn insert_after(&mut self, old_id: NodeId, new_id: NodeId); +} + +impl<'a> TreeRef for TreeRefView<'a> { + fn parent_id(&self, id: NodeId) -> Option { + self.get(id).unwrap().parent } - pub fn add_unique(&mut self, data: T) { - self.nodes.add_unique(data); + fn children_ids(&self, id: NodeId) -> Option> { + Some(self.get(id).unwrap().children.clone()) } - pub fn remove_unique( - &mut self, - ) -> Result { - self.nodes.remove_unique::() + fn height(&self, id: NodeId) -> Option { + Some(self.get(id).unwrap().height) } - fn node_data(&self) -> View { - self.nodes.borrow().unwrap() + fn contains(&self, id: NodeId) -> bool { + self.get(id).is_ok() } +} - fn node_data_mut(&self) -> ViewMut { - self.nodes.borrow().unwrap() - } - - pub fn remove(&mut self, id: NodeId) { - fn recurse(tree: &mut Tree, id: NodeId) { +impl<'a> TreeMut for TreeMutView<'a> { + fn remove(&mut self, id: NodeId) { + fn recurse<'a>(tree: &mut TreeMutView<'a>, id: NodeId) { let children = tree.children_ids(id); if let Some(children) = children { for child in children { recurse(tree, child); } } - - tree.nodes.delete_entity(id); } { - let mut node_data_mut = self.node_data_mut(); + let mut node_data_mut = &mut self.1; if let Some(parent) = node_data_mut.get(id).unwrap().parent { let parent = (&mut node_data_mut).get(parent).unwrap(); parent.children.retain(|&child| child != id); @@ -67,21 +69,19 @@ impl Tree { recurse(self, id); } - pub fn remove_single(&mut self, id: NodeId) { + fn remove_single(&mut self, id: NodeId) { { - let mut node_data_mut = self.node_data_mut(); + let mut node_data_mut = &mut self.1; if let Some(parent) = node_data_mut.get(id).unwrap().parent { let parent = (&mut node_data_mut).get(parent).unwrap(); parent.children.retain(|&child| child != id); } } - - self.nodes.delete_entity(id); } fn set_height(&mut self, node: NodeId, height: u16) { let children = { - let mut node_data_mut = self.node_data_mut(); + let mut node_data_mut = &mut self.1; let mut node = (&mut node_data_mut).get(node).unwrap(); node.height = height; node.children.clone() @@ -91,19 +91,23 @@ impl Tree { } } - pub fn create_node(&mut self) -> NodeBuilder<'_> { - let node = self.nodes.add_entity((Node { - parent: None, - children: Vec::new(), - height: 0, - },)); - NodeBuilder { tree: self, node } + fn create_node(&mut self, id: NodeId) { + let (entities, node_data_mut) = self; + entities.add_component( + id, + node_data_mut, + Node { + parent: None, + children: Vec::new(), + height: 0, + }, + ); } - pub fn add_child(&mut self, parent: NodeId, new: NodeId) { + fn add_child(&mut self, parent: NodeId, new: NodeId) { let height; { - let mut node_state = self.node_data_mut(); + let mut node_state = &mut self.1; (&mut node_state).get(new).unwrap().parent = Some(parent); let parent = (&mut node_state).get(parent).unwrap(); parent.children.push(new); @@ -112,9 +116,9 @@ impl Tree { self.set_height(new, height); } - pub fn replace(&mut self, old_id: NodeId, new_id: NodeId) { + fn replace(&mut self, old_id: NodeId, new_id: NodeId) { { - let mut node_state = self.node_data_mut(); + let mut node_state = &mut self.1; // update the parent's link to the child if let Some(parent_id) = node_state.get(old_id).unwrap().parent { let parent = (&mut node_state).get(parent_id).unwrap(); @@ -125,7 +129,6 @@ impl Tree { } } let height = parent.height + 1; - drop(node_state); self.set_height(new_id, height); } } @@ -133,8 +136,8 @@ impl Tree { self.remove(old_id); } - pub fn insert_before(&mut self, old_id: NodeId, new_id: NodeId) { - let mut node_state = self.node_data_mut(); + fn insert_before(&mut self, old_id: NodeId, new_id: NodeId) { + let mut node_state = &mut self.1; let old_node = node_state.get(old_id).unwrap(); let parent_id = old_node.parent.expect("tried to insert before root"); (&mut node_state).get(new_id).unwrap().parent = Some(parent_id); @@ -146,12 +149,11 @@ 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 mut node_state = self.node_data_mut(); + fn insert_after(&mut self, old_id: NodeId, new_id: NodeId) { + let mut node_state = &mut self.1; let old_node = node_state.get(old_id).unwrap(); let parent_id = old_node.parent.expect("tried to insert before root"); (&mut node_state).get(new_id).unwrap().parent = Some(parent_id); @@ -163,36 +165,29 @@ 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 insert(&mut self, id: NodeId, value: T) { - self.nodes.add_component(id, value); - } - - pub fn contains(&self, id: NodeId) -> bool { - self.nodes.borrow::().unwrap().is_alive(id) - } - - pub fn root(&self) -> NodeId { - self.root - } - - pub fn parent_id(&self, id: NodeId) -> Option { - let node_data = self.node_data(); +impl<'a> TreeRef for TreeMutView<'a> { + fn parent_id(&self, id: NodeId) -> Option { + let node_data = &self.1; node_data.get(id).unwrap().parent } - pub fn children_ids(&self, id: NodeId) -> Option> { - let node_data = self.node_data(); + fn children_ids(&self, id: NodeId) -> Option> { + let node_data = &self.1; node_data.get(id).map(|node| node.children.clone()).ok() } - pub fn height(&self, id: NodeId) -> Option { - let node_data = self.node_data(); + fn height(&self, id: NodeId) -> Option { + let node_data = &self.1; node_data.get(id).map(|node| node.height).ok() } + + fn contains(&self, id: NodeId) -> bool { + self.1.get(id).is_ok() + } } #[test] @@ -326,18 +321,3 @@ fn deletion() { assert_eq!(*tree.get::(parent).unwrap(), 0); assert_eq!(tree.get::(after), None); } - -pub struct NodeBuilder<'a> { - tree: &'a mut Tree, - node: EntityId, -} - -impl<'a> NodeBuilder<'a> { - pub fn insert(&mut self, component: T) { - self.tree.insert(self.node, component); - } - - pub fn id(&self) -> EntityId { - self.node - } -}