diff --git a/packages/native-core-macro/src/lib.rs b/packages/native-core-macro/src/lib.rs index 098b4c8c6..42c76cb04 100644 --- a/packages/native-core-macro/src/lib.rs +++ b/packages/native-core-macro/src/lib.rs @@ -4,7 +4,7 @@ use std::collections::HashSet; use proc_macro::TokenStream; use quote::quote; -use syn::Type; +use syn::{ItemImpl, Type}; /// A helper attribute for deriving `State` for a struct. #[proc_macro_attribute] @@ -58,36 +58,125 @@ pub fn partial_derive_pass(_: TokenStream, input: TokenStream) -> TokenStream { let mut combined_dependencies = HashSet::new(); - match parent_dependencies { + let parent_dependencies = match parent_dependencies { Type::Tuple(tuple) => { + let mut parent_dependencies = Vec::new(); for type_ in &tuple.elems { combined_dependencies.insert(type_.clone()); + parent_dependencies.push(type_.clone()); } + parent_dependencies } _ => panic!("ParentDependencies must be a tuple"), - } - match child_dependencies { + }; + let child_dependencies = match child_dependencies { Type::Tuple(tuple) => { + let mut child_dependencies = Vec::new(); for type_ in &tuple.elems { combined_dependencies.insert(type_.clone()); + child_dependencies.push(type_.clone()); } + child_dependencies } _ => panic!("ChildDependencies must be a tuple"), - } - match node_dependencies { + }; + let node_dependencies = match node_dependencies { Type::Tuple(tuple) => { + let mut node_dependencies = Vec::new(); for type_ in &tuple.elems { combined_dependencies.insert(type_.clone()); + node_dependencies.push(type_.clone()); } + node_dependencies } _ => panic!("NodeDependencies must be a tuple"), - } + }; combined_dependencies.insert(*this_type.clone()); - let combined_dependencies = combined_dependencies.into_iter(); + let combined_dependencies: Vec<_> = combined_dependencies.into_iter().collect(); + let parent_dependancies_idxes: Vec<_> = combined_dependencies + .iter() + .enumerate() + .filter_map(|(i, ident)| parent_dependencies.contains(ident).then_some(i)) + .collect(); + let child_dependencies_idxes: Vec<_> = combined_dependencies + .iter() + .enumerate() + .filter_map(|(i, ident)| child_dependencies.contains(ident).then_some(i)) + .collect(); + let node_dependencies_idxes: Vec<_> = combined_dependencies + .iter() + .enumerate() + .filter_map(|(i, ident)| node_dependencies.contains(ident).then_some(i)) + .collect(); + let this_type_idx = node_dependencies + .iter() + .enumerate() + .find_map(|(i, ident)| (&**this_type == ident).then_some(i)) + .unwrap(); + + let combined_dependencies = combined_dependencies.iter().map(|ident| { + if ident == &**this_type { + quote! {shipyard::ViewMut<#ident>} + } else { + quote! {shipyard::View<#ident>} + } + }); let combined_dependencies = quote!((#(#combined_dependencies),*)); - quote!(#impl_block).into() + let ItemImpl { + attrs, + defaultness, + unsafety, + impl_token, + generics, + trait_, + self_ty, + items, + .. + } = impl_block; + let for_ = trait_.as_ref().map(|t| t.2); + let trait_ = trait_.map(|t| t.1); + + // if the mutable borrow on the current type overlaps with the child or parent dependancies we need to use apply + + quote!( + #(#attrs)* + #defaultness #unsafety #impl_token #impl_token #generics #trait_ #for_ #self_ty { + #(#items)* + + fn workload_system(type_id: TypeId, dependants: FxHashSet, pass_direction: PassDirection) -> WorkloadSystem { + use shipyard::IntoWorkloadSystem; + + move |data: #combined_dependencies, run_view: RunPassView| { + shipyard::run(type_id, dependants, pass_direction, run_view, |id: NodeId, ctx: &SendAnyMap| { + // 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) + } + }) + }.into_workload_system() + } + } + ) + .into() } // pub trait State: Any + Send + Sync { diff --git a/packages/native-core/src/lib.rs b/packages/native-core/src/lib.rs index 74c5e947c..777d61760 100644 --- a/packages/native-core/src/lib.rs +++ b/packages/native-core/src/lib.rs @@ -17,6 +17,7 @@ mod passes; pub mod real_dom; pub mod tree; pub mod utils; +pub use passes::run_pass; pub use shipyard::EntityId as NodeId; pub mod prelude { diff --git a/packages/native-core/src/passes.rs b/packages/native-core/src/passes.rs index b93ee074f..99553b124 100644 --- a/packages/native-core/src/passes.rs +++ b/packages/native-core/src/passes.rs @@ -1,10 +1,7 @@ use anymap::AnyMap; use parking_lot::RwLock; use rustc_hash::{FxHashMap, FxHashSet}; -use shipyard::{ - BorrowInfo, Component, IntoBorrow, IntoWorkloadSystem, Unique, UniqueView, View, - WorkloadSystem, World, -}; +use shipyard::{BorrowInfo, Component, IntoBorrow, Unique, UniqueView, View, WorkloadSystem}; use std::any::{Any, TypeId}; use std::collections::BTreeMap; use std::marker::PhantomData; @@ -13,8 +10,8 @@ use std::sync::Arc; use crate::node::FromAnyValue; use crate::node_ref::{NodeMaskBuilder, NodeView}; use crate::real_dom::{DirtyNodesResult, SendAnyMapWrapper}; -use crate::tree::{TreeMut, TreeRef, TreeRefView}; -use crate::{FxDashSet, SendAnyMap}; +use crate::tree::{TreeRef, TreeRefView}; +use crate::SendAnyMap; use crate::{NodeId, NodeMask}; #[derive(Default)] @@ -113,8 +110,6 @@ 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>; @@ -138,43 +133,54 @@ pub trait State: Any + Send + Sync { ) -> Self; /// Create a workload system for this state - fn workload_system(dependants: FxHashSet) -> WorkloadSystem; + fn workload_system( + type_id: TypeId, + dependants: FxHashSet, + pass_direction: PassDirection, + ) -> 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(), - } +impl<'v> shipyard::Borrow<'v> for RunPassView<'v> { + type View = RunPassView<'v>; + + fn borrow( + world: &'v shipyard::World, + last_run: Option, + current: u32, + ) -> Result { + Ok(RunPassView { + tree: as shipyard::IntoBorrow>::Borrow::borrow( + world, last_run, current, + )?, + nodes_updated: + as shipyard::IntoBorrow>::Borrow::borrow( + world, last_run, current, + )?, + dirty: as shipyard::IntoBorrow>::Borrow::borrow( + world, last_run, current, + )?, + ctx: as shipyard::IntoBorrow>::Borrow::borrow( + world, last_run, current, + )?, + }) } } -pub fn run_pass(view: RunPassView, mut update_node: impl FnMut(NodeId, &SendAnyMap) -> bool) { +pub fn run_pass( + type_id: TypeId, + dependants: FxHashSet, + pass_direction: PassDirection, + view: RunPassView, + mut update_node: impl FnMut(NodeId, &SendAnyMap) -> bool, +) { let RunPassView { - type_id, - dependants, - pass_direction, tree, nodes_updated, dirty, @@ -284,7 +290,7 @@ pub struct TypeErasedPass { pub(crate) combined_dependancy_type_ids: FxHashSet, pub(crate) dependants: FxHashSet, pub(crate) mask: NodeMask, - pub(crate) workload: fn(FxHashSet) -> WorkloadSystem, + pub(crate) workload: fn(TypeId, FxHashSet, PassDirection) -> WorkloadSystem, pub(crate) pass_direction: PassDirection, phantom: PhantomData, }