소스 검색

WIP: derive macro

= 2 년 전
부모
커밋
bab3c8d584
3개의 변경된 파일138개의 추가작업 그리고 42개의 파일을 삭제
  1. 98 9
      packages/native-core-macro/src/lib.rs
  2. 1 0
      packages/native-core/src/lib.rs
  3. 39 33
      packages/native-core/src/passes.rs

+ 98 - 9
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<TypeId>, 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::<Self>().unwrap().entry(node_id))
+                        };
+                        let node_data = tree.get_single::<NodeType<V>>(node_id).unwrap();
+                        let node = tree.get::<Self::NodeDependencies>(node_id).unwrap();
+                        let children = tree.children::<Self::ChildDependencies>(node_id);
+                        let parent = tree.parent::<Self::ParentDependencies>(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<V: FromAnyValue + Send + Sync = ()>: Any + Send + Sync {

+ 1 - 0
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 {

+ 39 - 33
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<V: FromAnyValue + Send + Sync = ()>: 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<V: FromAnyValue + Send + Sync = ()>: Any + Send + Sync {
     ) -> Self;
 
     /// Create a workload system for this state
-    fn workload_system(dependants: FxHashSet<TypeId>) -> WorkloadSystem;
+    fn workload_system(
+        type_id: TypeId,
+        dependants: FxHashSet<TypeId>,
+        pass_direction: PassDirection,
+    ) -> WorkloadSystem;
 }
 
 pub struct RunPassView<'a> {
-    type_id: TypeId,
-    dependants: FxHashSet<TypeId>,
-    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<TypeId>,
-        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<u32>,
+        current: u32,
+    ) -> Result<Self::View, shipyard::error::GetStorage> {
+        Ok(RunPassView {
+            tree: <TreeRefView<'v> as shipyard::IntoBorrow>::Borrow::borrow(
+                world, last_run, current,
+            )?,
+            nodes_updated:
+                <UniqueView<'v, DirtyNodesResult> as shipyard::IntoBorrow>::Borrow::borrow(
+                    world, last_run, current,
+                )?,
+            dirty: <UniqueView<'v, DirtyNodeStates> as shipyard::IntoBorrow>::Borrow::borrow(
+                world, last_run, current,
+            )?,
+            ctx: <UniqueView<'v, SendAnyMapWrapper> 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<TypeId>,
+    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<V: FromAnyValue + Send = ()> {
     pub(crate) combined_dependancy_type_ids: FxHashSet<TypeId>,
     pub(crate) dependants: FxHashSet<TypeId>,
     pub(crate) mask: NodeMask,
-    pub(crate) workload: fn(FxHashSet<TypeId>) -> WorkloadSystem,
+    pub(crate) workload: fn(TypeId, FxHashSet<TypeId>, PassDirection) -> WorkloadSystem,
     pub(crate) pass_direction: PassDirection,
     phantom: PhantomData<V>,
 }