From 50735ddb31b4643ecee88ed5d69aaef959b7af44 Mon Sep 17 00:00:00 2001 From: hodasemi Date: Mon, 14 Apr 2025 20:40:07 +0200 Subject: [PATCH] Split proc macro crate --- Cargo.toml | 2 +- update_macro_base/Cargo.toml | 9 + update_macro_base/src/lib.rs | 424 +++++++++++++++++ update_macros/Cargo.toml | 2 + update_macros/src/lib.rs | 42 +- update_macros/src/pair_update.rs | 89 ---- update_macros/src/single_update.rs | 70 --- update_macros/src/update.rs | 703 ++++++++--------------------- 8 files changed, 614 insertions(+), 727 deletions(-) create mode 100644 update_macro_base/Cargo.toml create mode 100644 update_macro_base/src/lib.rs delete mode 100644 update_macros/src/pair_update.rs delete mode 100644 update_macros/src/single_update.rs diff --git a/Cargo.toml b/Cargo.toml index 014a2b3..6a5200c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [workspace] resolver = "2" -members = ["ecs", "update_macros"] +members = ["ecs", "update_macros", "update_macro_base"] [workspace.dependencies] anyhow = { version = "1.0.86", features = ["backtrace"] } diff --git a/update_macro_base/Cargo.toml b/update_macro_base/Cargo.toml new file mode 100644 index 0000000..db2bd74 --- /dev/null +++ b/update_macro_base/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "update_macro_base" +version = "0.1.0" +edition = "2024" + +[dependencies] +syn = { workspace = true } +quote = { workspace = true } +proc-macro2 = { workspace = true } diff --git a/update_macro_base/src/lib.rs b/update_macro_base/src/lib.rs new file mode 100644 index 0000000..9d5dfb4 --- /dev/null +++ b/update_macro_base/src/lib.rs @@ -0,0 +1,424 @@ +use proc_macro2::TokenStream as TokenStream2; +use quote::{ToTokens, format_ident, quote}; +use syn::Ident; + +pub struct Query { + components: Vec, + filter: Ident, +} + +impl Query { + fn new(components: impl Iterator, filter_id: usize) -> Self { + Self { + components: components.collect(), + filter: format_ident!("Filter{filter_id}"), + } + } + + fn types(&self) -> TokenStream2 { + let component_list = self + .components + .iter() + .map(|c| quote! { #c }) + .collect::>(); + + let components = if component_list.len() == 1 { + let component = &component_list[0]; + quote! { #component } + } else { + quote! { ( #( #component_list, )* ) } + }; + + components + } + + fn dedup_checks(&self) -> TokenStream2 { + let components = &self.components; + let filter = &self.filter; + + quote! { + #( #filter::verify_dedup::<#components>(); )* + } + } + + fn check_entity(&self, index: usize) -> TokenStream2 { + let components = &self.components; + let filter = &self.filter; + + quote! { + { + let mut complies = true; + + #( + if !entity.components.contains::<#components>() { + complies = false; + } + )* + + if !#filter::check(entity) { + complies = false; + } + + if complies { + comply_queries.push(#index); + } + } + } + } + + fn component_store_and_query(&self, index: usize) -> (TokenStream2, TokenStream2, Ident) { + let components = &self.components; + let entity_name = format_ident!("entity_{index}"); + let component_names = self + .components + .iter() + .map(|component| format_ident!("q_{index}_{component}")) + .collect::>(); + let query_ident = format_ident!("query_{index}"); + let entity_ident = format_ident!("e_{index}"); + + ( + quote! { + let #entity_name = &entities[#index]; + let #entity_ident = #entity_name.as_entity(); + + #( + #[allow(non_snake_case)] + let #component_names = UnsafeComponentStore::from( + #entity_name.get_component::<#components>()? + ); + )* + }, + if component_names.len() == 1 { + let component_name = &component_names[0]; + + quote! { + let #query_ident = Query { + entity: #entity_ident, + c: unsafe { #component_name.as_mut() }, + filter: PhantomData, + }; + } + } else { + quote! { + let #query_ident = Query { + entity: #entity_ident, + c: unsafe { ( #( #component_names.as_mut(), )* ) }, + filter: PhantomData, + }; + } + }, + query_ident, + ) + } + + fn components(&self) -> &Vec { + &self.components + } + + fn filter(&self) -> &Ident { + &self.filter + } +} + +impl ToTokens for Query { + fn to_tokens(&self, tokens: &mut TokenStream2) { + let component_list = self + .components + .iter() + .map(|c| quote! { &mut #c }) + .collect::>(); + + let components = if component_list.len() == 1 { + let component = &component_list[0]; + quote! { #component } + } else { + quote! { ( #( #component_list, )* ) } + }; + + let filter = self.filter.clone(); + + TokenStream2::from(quote! { + Query<#components, #filter> + }) + .to_tokens(tokens); + } +} + +pub struct Update { + queries: Vec, + resources: Vec, +} + +impl Update { + pub const MIN_RESOURCE: usize = 0; + pub const MIN_COMPONENTS: usize = 1; + + pub fn new(queries: impl Iterator, resources: usize) -> Self { + Self { + queries: queries + .enumerate() + .map(|(query, component_count)| { + Query::new( + (0..component_count).map(|component| format_ident!("C{component}Q{query}")), + query, + ) + }) + .collect(), + resources: (0..resources) + .map(|resource| format_ident!("Res{resource}")) + .collect(), + } + } + + fn filter_types(&self) -> TokenStream2 { + let filter_types = self + .queries + .iter() + .map(|query| query.filter()) + .collect::>(); + + if filter_types.len() == 1 { + let filter = &filter_types[0]; + + quote! { + #filter + } + } else { + quote! { + ( #( #filter_types, )* ) + } + } + } + + fn filter_type_impls(&self) -> TokenStream2 { + let filter_types = self + .queries + .iter() + .map(|query| query.filter()) + .collect::>(); + + quote! { + #( #filter_types, )* + } + } + + fn filter_requirements(&self) -> TokenStream2 { + let filter_requirements = self + .queries + .iter() + .map(|query| query.filter()) + .collect::>(); + + quote! { + #( #filter_requirements: CheckFilter + 'static, )* + } + } + + fn query_types(&self) -> TokenStream2 { + let query_types = self + .queries + .iter() + .map(|query| query.types()) + .collect::>(); + + quote! { + ( #( #query_types, )* ) + } + } + + fn query_type_impls(&self) -> TokenStream2 { + let query_types = self + .queries + .iter() + .map(|query| query.components()) + .flatten() + .collect::>(); + + quote! { + #( #query_types, )* + } + } + + fn component_requirements(&self) -> TokenStream2 { + let component_requirements = self + .queries + .iter() + .map(|query| { + query.components.iter().map(|component| { + quote! { + #component: EntityComponent + ComponentDebug, + } + }) + }) + .flatten() + .collect::>(); + + quote! { + #( #component_requirements )* + } + } + + fn resource_store(&self) -> (TokenStream2, Vec) { + let resource_types = &self.resources; + let resource_idents = self + .resources + .iter() + .map(|resource| format_ident!("res_{resource}")) + .collect::>(); + + if self.resources.is_empty() { + (quote! {}, Vec::new()) + } else { + ( + quote! { + #[allow(non_snake_case)] + let ( + #( #resource_idents, )* + ): ( + #( &mut #resource_types, )* + ) = world.resources.get_mut()?; + }, + resource_idents, + ) + } + } + + fn resource_types(&self) -> TokenStream2 { + let resource_types = &self.resources; + + quote! { + ( #( #resource_types, )* ) + } + } + + fn resource_type_impls(&self) -> TokenStream2 { + let resource_types = &self.resources; + + quote! { + #( #resource_types, )* + } + } + + fn reource_requirement(&self) -> TokenStream2 { + let resource_types = &self.resources; + + quote! { + #( #resource_types: ResourceTrait, )* + } + } +} + +pub struct ResourceTokens { + pub resource_types: TokenStream2, + pub resource_type_impls: TokenStream2, + pub resources: TokenStream2, + pub resource_requirement: TokenStream2, + pub resource_store: TokenStream2, + pub resource_idents: Vec, +} + +pub struct QueryTokens<'a> { + pub filter_types: TokenStream2, + pub filter_type_impls: TokenStream2, + pub query_types: TokenStream2, + pub query_type_impls: TokenStream2, + pub queries: &'a [Query], + pub filter_requirements: TokenStream2, + pub component_requirements: TokenStream2, + pub query_count: usize, + pub verify_dedup: Vec, + pub check_entities: Vec, + pub component_stores: Vec, + pub query_structs: Vec, + pub query_idents: Vec, +} + +impl Update { + pub fn resourece_tokens(&self) -> ResourceTokens { + let resource_types = self.resource_types(); + let resource_type_impls = self.resource_type_impls(); + + let resources = if self.resources.is_empty() { + quote! {} + } else { + let resources = &self.resources; + + quote! { + #( &mut #resources, )* + } + }; + + let resource_requirement = self.reource_requirement(); + let (resource_store, resource_idents) = self.resource_store(); + + ResourceTokens { + resource_types, + resource_type_impls, + resources, + resource_requirement, + resource_store, + resource_idents, + } + } + + pub fn query_tokens(&self) -> QueryTokens<'_> { + let filter_types = self.filter_types(); + let filter_type_impls = self.filter_type_impls(); + let query_types = self.query_types(); + let query_type_impls = self.query_type_impls(); + + let queries = &self.queries; + + let filter_requirements = self.filter_requirements(); + let component_requirements = self.component_requirements(); + + let query_count = self.queries.len(); + + let verify_dedup = self + .queries + .iter() + .map(|query| query.dedup_checks()) + .collect::>(); + + let check_entities = self + .queries + .iter() + .enumerate() + .map(|(index, query)| query.check_entity(index)) + .collect::>(); + + let component_stores_and_queries = self + .queries + .iter() + .enumerate() + .map(|(index, query)| query.component_store_and_query(index)) + .collect::>(); + + let mut component_stores = Vec::new(); + let mut query_structs = Vec::new(); + let mut query_idents = Vec::new(); + + for (component_store, query_struct, query_ident) in component_stores_and_queries { + component_stores.push(component_store); + query_structs.push(query_struct); + query_idents.push(query_ident); + } + + QueryTokens { + filter_types, + filter_type_impls, + query_types, + query_type_impls, + queries, + filter_requirements, + component_requirements, + query_count, + verify_dedup, + check_entities, + component_stores, + query_structs, + query_idents, + } + } +} diff --git a/update_macros/Cargo.toml b/update_macros/Cargo.toml index 40fcede..53b21d5 100644 --- a/update_macros/Cargo.toml +++ b/update_macros/Cargo.toml @@ -11,3 +11,5 @@ proc-macro = true syn = { workspace = true } quote = { workspace = true } proc-macro2 = { workspace = true } + +update_macro_base = { path = "../update_macro_base" } diff --git a/update_macros/src/lib.rs b/update_macros/src/lib.rs index 82b848e..b91bb67 100644 --- a/update_macros/src/lib.rs +++ b/update_macros/src/lib.rs @@ -1,15 +1,11 @@ -mod pair_update; -mod single_update; mod update; -use pair_update::pair_update; -use single_update::single_update; use update::update; use proc_macro::TokenStream; use quote::quote; use syn::{ - DeriveInput, Ident, LitInt, Result, + DeriveInput, LitInt, Result, parse::{Parse, ParseStream}, parse_macro_input, token::Comma, @@ -40,42 +36,6 @@ pub fn implement_updates(input: TokenStream) -> TokenStream { update(input.max_components, input.max_resources) } -struct InputInfo { - macro_ident: Ident, - start: usize, - end: usize, -} - -impl Parse for InputInfo { - fn parse(input: ParseStream) -> Result { - let macro_ident = input.parse::()?; - input.parse::()?; - let start = input.parse::()?.base10_parse()?; - input.parse::()?; - let end = input.parse::()?.base10_parse()?; - - Ok(Self { - macro_ident, - start, - end, - }) - } -} - -#[proc_macro] -pub fn implement_pair_update(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as InputInfo); - - pair_update(input) -} - -#[proc_macro] -pub fn implement_single_update(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as InputInfo); - - single_update(input) -} - #[proc_macro_derive(Resource)] pub fn derive_resource(input: TokenStream) -> TokenStream { let ast = parse_macro_input!(input as DeriveInput); diff --git a/update_macros/src/pair_update.rs b/update_macros/src/pair_update.rs deleted file mode 100644 index 0471a6e..0000000 --- a/update_macros/src/pair_update.rs +++ /dev/null @@ -1,89 +0,0 @@ -use proc_macro::TokenStream; -use proc_macro2::{Span, TokenStream as TokenStream2}; -use quote::{format_ident, quote}; -use syn::{Ident, LitInt}; - -use crate::InputInfo; - -struct TupleType { - little: Ident, - big: Ident, -} - -pub fn pair_update(input: InputInfo) -> TokenStream { - let mut generic_count = Vec::new(); - - for lhs in input.start..=input.end { - for rhs in input.start..=input.end { - generic_count.push((lhs, rhs)); - } - } - - let generic_tuples: Vec<(Vec, Vec)> = generic_count - .iter() - .map(|(lhs_count, rhs_count)| { - let lhs = (input.start..(input.start + lhs_count)) - .map(|i| TupleType { - little: format_ident!("l{}", i), - big: format_ident!("L{}", i), - }) - .collect(); - - let rhs = (input.start..(input.start + rhs_count)) - .map(|i| TupleType { - little: format_ident!("r{}", i), - big: format_ident!("R{}", i), - }) - .collect(); - - (lhs, rhs) - }) - .collect(); - - let invocations: Vec = generic_tuples - .iter() - .map(|(lhs, rhs)| { - let lhs_expr = LitInt::new(&format!("{}", lhs.len()), Span::call_site()); - let rhs_expr = LitInt::new(&format!("{}", rhs.len()), Span::call_site()); - - let lhs_args: Vec = lhs - .iter() - .map(|tuple| { - let little = &tuple.little; - let big = &tuple.big; - - quote! { - [#little: #big], - } - }) - .collect(); - - let rhs_args: Vec = rhs - .iter() - .map(|tuple| { - let little = &tuple.little; - let big = &tuple.big; - - quote! { - [#little: #big], - } - }) - .collect(); - - let macro_ident = &input.macro_ident; - - quote! { - #macro_ident!( - #lhs_expr, (#(#lhs_args)*), - #rhs_expr, (#(#rhs_args)*) - ); - } - }) - .collect(); - - TokenStream::from(quote! { - #( - #invocations - )* - }) -} diff --git a/update_macros/src/single_update.rs b/update_macros/src/single_update.rs deleted file mode 100644 index d81866a..0000000 --- a/update_macros/src/single_update.rs +++ /dev/null @@ -1,70 +0,0 @@ -use proc_macro::TokenStream; -use proc_macro2::TokenStream as TokenStream2; -use quote::{format_ident, quote}; -use syn::Ident; - -use crate::InputInfo; - -const MIN_RESOURCE: usize = 1; - -pub fn single_update(input: InputInfo) -> TokenStream { - let mut generic_counts = Vec::new(); - - for components in input.start..=input.end { - for resources in MIN_RESOURCE..=input.end { - generic_counts.push((components, resources)); - } - } - - let generics: Vec<(Vec, Vec)> = generic_counts - .into_iter() - .map(|(component_count, resource_count)| { - let components = (input.start..(input.start + component_count)) - .map(|i| format_ident!("t{}", i)) - .collect(); - - let resources = (MIN_RESOURCE..(MIN_RESOURCE + resource_count)) - .map(|i| format_ident!("r{}", i)) - .collect(); - - (components, resources) - }) - .collect(); - - let resource_invocations: Vec = generics - .iter() - .map(|(components, resources)| { - let macro_ident = &input.macro_ident; - - quote! { - #macro_ident!(#(#components,)* [#(#resources,)*]); - } - }) - .collect(); - - let generate_inputs: Vec> = (input.start..=input.end) - .map(|count| { - (input.start..(input.start + count)) - .map(|i| format_ident!("t{}", i)) - .collect() - }) - .collect(); - - let empty_resource_invocations: Vec = generate_inputs - .iter() - .map(|t| { - let macro_ident = &input.macro_ident; - - quote! { - #macro_ident!(#(#t,)*); - } - }) - .collect(); - - TokenStream::from(quote! { - #( - #empty_resource_invocations - #resource_invocations - )* - }) -} diff --git a/update_macros/src/update.rs b/update_macros/src/update.rs index cdfc00a..079c627 100644 --- a/update_macros/src/update.rs +++ b/update_macros/src/update.rs @@ -1,581 +1,229 @@ use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; -use quote::{ToTokens, format_ident, quote}; -use syn::Ident; +use quote::quote; -struct Query { - components: Vec, - filter: Ident, -} +use update_macro_base::*; -impl Query { - pub fn new(components: impl Iterator, filter_id: usize) -> Self { - Self { - components: components.collect(), - filter: format_ident!("Filter{filter_id}"), - } - } +pub fn resource_only_events_and_systems(update: &Update) -> TokenStream2 { + let resource_tokens = update.resourece_tokens(); - pub fn types(&self) -> TokenStream2 { - let component_list = self - .components - .iter() - .map(|c| quote! { #c }) - .collect::>(); + let resource_types = &resource_tokens.resource_types; + let resource_type_impls = &resource_tokens.resource_type_impls; + let resources = &resource_tokens.resources; + let resource_requirement = &resource_tokens.resource_requirement; + let resource_store = &resource_tokens.resource_store; + let resource_idents = &resource_tokens.resource_idents; - let components = if component_list.len() == 1 { - let component = &component_list[0]; - quote! { #component } - } else { - quote! { ( #( #component_list, )* ) } - }; + quote! { + impl EventReader for Events + where + Func: Fn(&P, &mut Commands, #resources ) -> Result<()> + Send + Sync + 'static, + #resource_requirement + P: std::any::Any + Send + Sync, + { + fn add_reader(&mut self, func: Func) { + match self.events.get_mut(&TypeId::of::

()) { + Some((_, listener)) => listener.push(std::sync::Arc::new(move |world, payload| { + let typed_payload: &P = payload.downcast_ref().unwrap(); + let mut commands = Commands::new(world.now()); - components - } + #resource_store + func(typed_payload, &mut commands, #( #resource_idents, )*)?; - pub fn dedup_checks(&self) -> TokenStream2 { - let components = &self.components; - let filter = &self.filter; + commands.apply_deferred(world)?; - quote! { - #( #filter::verify_dedup::<#components>(); )* - } - } - - pub fn check_entity(&self, index: usize) -> TokenStream2 { - let components = &self.components; - let filter = &self.filter; - - quote! { - { - let mut complies = true; - - #( - if !entity.components.contains::<#components>() { - complies = false; - } - )* - - if !#filter::check(entity) { - complies = false; - } - - if complies { - comply_queries.push(#index); + Ok(()) + })), + None => panic!("register event type first!"), } } } - } - pub fn component_store_and_query(&self, index: usize) -> (TokenStream2, TokenStream2, Ident) { - let components = &self.components; - let entity_name = format_ident!("entity_{index}"); - let component_names = self - .components - .iter() - .map(|component| format_ident!("q_{index}_{component}")) - .collect::>(); - let query_ident = format_ident!("query_{index}"); - let entity_ident = format_ident!("e_{index}"); - - ( - quote! { - let #entity_name = &entities[#index]; - let #entity_ident = #entity_name.as_entity(); - - #( - #[allow(non_snake_case)] - let #component_names = UnsafeComponentStore::from( - #entity_name.get_component::<#components>()? - ); - )* - }, - if component_names.len() == 1 { - let component_name = &component_names[0]; - - quote! { - let #query_ident = Query { - entity: #entity_ident, - c: unsafe { #component_name.as_mut() }, - filter: PhantomData, - }; - } - } else { - quote! { - let #query_ident = Query { - entity: #entity_ident, - c: unsafe { ( #( #component_names.as_mut(), )* ) }, - filter: PhantomData, - }; - } - }, - query_ident, - ) - } - - pub fn components(&self) -> &Vec { - &self.components - } - - pub fn filter(&self) -> &Ident { - &self.filter - } -} - -impl ToTokens for Query { - fn to_tokens(&self, tokens: &mut TokenStream2) { - let component_list = self - .components - .iter() - .map(|c| quote! { &mut #c }) - .collect::>(); - - let components = if component_list.len() == 1 { - let component = &component_list[0]; - quote! { #component } - } else { - quote! { ( #( #component_list, )* ) } - }; - - let filter = self.filter.clone(); - - TokenStream2::from(quote! { - Query<#components, #filter> - }) - .to_tokens(tokens); - } -} - -struct Update { - queries: Vec, - resources: Vec, -} - -impl Update { - const MIN_RESOURCE: usize = 0; - const MIN_COMPONENTS: usize = 1; - - pub fn new(queries: impl Iterator, resources: usize) -> Self { - Self { - queries: queries - .enumerate() - .map(|(query, component_count)| { - Query::new( - (0..component_count).map(|component| format_ident!("C{component}Q{query}")), - query, - ) - }) - .collect(), - resources: (0..resources) - .map(|resource| format_ident!("Res{resource}")) - .collect(), - } - } - - pub fn filter_types(&self) -> TokenStream2 { - let filter_types = self - .queries - .iter() - .map(|query| query.filter()) - .collect::>(); - - if filter_types.len() == 1 { - let filter = &filter_types[0]; - - quote! { - #filter + impl AddSystem<#resource_types, Func, ()> for WorldBuilder + where + Func: Fn(&mut Commands, #resources ) -> Result + Send + Sync + 'static, + #resource_requirement + { + fn add_system(&mut self, priority: u32, func: Func) { + self.systems.push((priority, Box::new(move |world: &mut World, commands: &mut Commands| { + #resource_store + func(commands, #( #resource_idents, )*) + }))); + self.systems.sort_by_key(|(priority, _)| *priority); } - } else { - quote! { - ( #( #filter_types, )* ) + } + + impl AddSystem<#resource_types, Func, World> for WorldBuilder + where + Func: Fn(&World, &mut Commands, #resources ) -> Result + Send + Sync + 'static, + #resource_requirement + { + fn add_system(&mut self, priority: u32, func: Func) { + self.systems.push((priority, Box::new(move |world: &mut World, commands: &mut Commands| { + let w = unsafe { utilities::unsafe_life_time::remove_life_time(world) }; + #resource_store + func(w, commands, #( #resource_idents, )*) + }))); + self.systems.sort_by_key(|(priority, _)| *priority); } } } +} - pub fn filter_type_impls(&self) -> TokenStream2 { - let filter_types = self - .queries - .iter() - .map(|query| query.filter()) - .collect::>(); +fn events_and_systems(update: &Update) -> TokenStream2 { + let query_tokens = update.query_tokens(); - quote! { - #( #filter_types, )* - } - } + let filter_types = &query_tokens.filter_types; + let filter_type_impls = &query_tokens.filter_type_impls; + let query_types = &query_tokens.query_types; + let query_type_impls = &query_tokens.query_type_impls; + let queries = query_tokens.queries; + let filter_requirements = &query_tokens.filter_requirements; + let component_requirements = &query_tokens.component_requirements; + let query_count = query_tokens.query_count; + let verify_dedup = &query_tokens.verify_dedup; + let check_entities = &query_tokens.check_entities; + let component_stores = &query_tokens.component_stores; + let query_structs = &query_tokens.query_structs; + let query_idents = &query_tokens.query_idents; - pub fn filter_requirements(&self) -> TokenStream2 { - let filter_requirements = self - .queries - .iter() - .map(|query| query.filter()) - .collect::>(); + let resource_tokens = update.resourece_tokens(); - quote! { - #( #filter_requirements: CheckFilter + 'static, )* - } - } + let resource_types = &resource_tokens.resource_types; + let resource_type_impls = &resource_tokens.resource_type_impls; + let resources = &resource_tokens.resources; + let resource_requirement = &resource_tokens.resource_requirement; + let resource_store = &resource_tokens.resource_store; + let resource_idents = &resource_tokens.resource_idents; - pub fn query_types(&self) -> TokenStream2 { - let query_types = self - .queries - .iter() - .map(|query| query.types()) - .collect::>(); + quote! { + impl CreateArchetype<#query_types, #resource_types, Func, #filter_types> for Archetype + where + Func: Fn(&mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + Clone + 'static, + #filter_requirements + #component_requirements + #resource_requirement + { + fn create(f: Func) -> Self { + #( #verify_dedup )* - quote! { - ( #( #query_types, )* ) - } - } + Self { + queries: #query_count, - pub fn query_type_impls(&self) -> TokenStream2 { - let query_types = self - .queries - .iter() - .map(|query| query.components()) - .flatten() - .collect::>(); + check_entity: Box::new(move |entity| { + let mut comply_queries = Vec::new(); - quote! { - #( #query_types, )* - } - } + #( #check_entities )* - pub fn component_requirements(&self) -> TokenStream2 { - let component_requirements = self - .queries - .iter() - .map(|query| { - query.components.iter().map(|component| { - quote! { - #component: EntityComponent + ComponentDebug, - } - }) - }) - .flatten() - .collect::>(); + if comply_queries.is_empty() { + None + } else { + Some(comply_queries) + } + }), - quote! { - #( #component_requirements )* - } - } + create_callback: Box::new(move |entities| { + #( #component_stores )* - pub fn resource_store(&self) -> (TokenStream2, Vec) { - let resource_types = &self.resources; - let resource_idents = self - .resources - .iter() - .map(|resource| format_ident!("res_{resource}")) - .collect::>(); - - if self.resources.is_empty() { - (quote! {}, Vec::new()) - } else { - ( - quote! { - #[allow(non_snake_case)] - let ( - #( #resource_idents, )* - ): ( - #( &mut #resource_types, )* - ) = world.resources.get_mut()?; - }, - resource_idents, - ) - } - } - - pub fn resource_types(&self) -> TokenStream2 { - let resource_types = &self.resources; - - quote! { - ( #( #resource_types, )* ) - } - } - - pub fn resource_type_impls(&self) -> TokenStream2 { - let resource_types = &self.resources; - - quote! { - #( #resource_types, )* - } - } - - pub fn reource_requirement(&self) -> TokenStream2 { - let resource_types = &self.resources; - - quote! { - #( #resource_types: ResourceTrait, )* - } - } - - pub fn resource_only_events_and_systems(&self) -> TokenStream2 { - let resource_types = self.resource_types(); - let resource_type_impls = self.resource_type_impls(); - - let resources = if self.resources.is_empty() { - quote! {} - } else { - let resources = &self.resources; - - quote! { - #( &mut #resources, )* - } - }; - - let reource_requirement = self.reource_requirement(); - let (resource_store, resource_idents) = self.resource_store(); - - quote! { - impl EventReader for Events - where - Func: Fn(&P, &mut Commands, #resources ) -> Result<()> + Send + Sync + 'static, - #reource_requirement - P: std::any::Any + Send + Sync, - { - fn add_reader(&mut self, func: Func) { - match self.events.get_mut(&TypeId::of::

()) { - Some((_, listener)) => listener.push(std::sync::Arc::new(move |world, payload| { - let typed_payload: &P = payload.downcast_ref().unwrap(); - let mut commands = Commands::new(world.now()); + let f = f.clone(); + Ok(Box::new(move |commands, world| { + #( #query_structs )* #resource_store - func(typed_payload, &mut commands, #( #resource_idents, )*)?; - commands.apply_deferred(world)?; + f(commands, #( #query_idents, )* #( #resource_idents, )* ) + })) + }), - Ok(()) - })), - None => panic!("register event type first!"), - } - } - } - - impl AddSystem<#resource_types, Func, ()> for WorldBuilder - where - Func: Fn(&mut Commands, #resources ) -> Result + Send + Sync + 'static, - #reource_requirement - { - fn add_system(&mut self, priority: u32, func: Func) { - self.systems.push((priority, Box::new(move |world: &mut World, commands: &mut Commands| { - #resource_store - func(commands, #( #resource_idents, )*) - }))); - self.systems.sort_by_key(|(priority, _)| *priority); - } - } - - impl AddSystem<#resource_types, Func, World> for WorldBuilder - where - Func: Fn(&World, &mut Commands, #resources ) -> Result + Send + Sync + 'static, - #reource_requirement - { - fn add_system(&mut self, priority: u32, func: Func) { - self.systems.push((priority, Box::new(move |world: &mut World, commands: &mut Commands| { - let w = unsafe { utilities::unsafe_life_time::remove_life_time(world) }; - #resource_store - func(w, commands, #( #resource_idents, )*) - }))); - self.systems.sort_by_key(|(priority, _)| *priority); + entities: IndexMap::new(), } } } - } -} -impl ToTokens for Update { - fn to_tokens(&self, tokens: &mut TokenStream2) { - // generics to specify trait implementations - let filter_types = self.filter_types(); - let filter_type_impls = self.filter_type_impls(); - let query_types = self.query_types(); - let query_type_impls = self.query_type_impls(); - let resource_types = self.resource_types(); - let resource_type_impls = self.resource_type_impls(); - - // panic!("{resource_type_impls}"); - - // function parameter - let queries = &self.queries; - let resources = if self.resources.is_empty() { - quote! {} - } else { - let resources = &self.resources; - - quote! { - #( &mut #resources, )* + impl AddUpdates<#query_types, #resource_types, Func, #filter_types> for Updates + where + Func: Fn(&mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + Clone + 'static, + #filter_requirements + #component_requirements + #resource_requirement + { + fn add_update( + &mut self, + priority: u32, + func: Func, + ) -> Result<()> { + self.add(priority, Archetype::create(func)) } - }; - - // trait requirements - let filter_requirements = self.filter_requirements(); - let component_requirements = self.component_requirements(); - let reource_requirement = self.reource_requirement(); - - let query_count = self.queries.len(); - - let verify_dedup = self - .queries - .iter() - .map(|query| query.dedup_checks()) - .collect::>(); - - let check_entities = self - .queries - .iter() - .enumerate() - .map(|(index, query)| query.check_entity(index)) - .collect::>(); - - let component_stores_and_queries = self - .queries - .iter() - .enumerate() - .map(|(index, query)| query.component_store_and_query(index)) - .collect::>(); - - let mut component_stores = Vec::new(); - let mut query_structs = Vec::new(); - let mut query_idents = Vec::new(); - - for (component_store, query_struct, query_ident) in component_stores_and_queries { - component_stores.push(component_store); - query_structs.push(query_struct); - query_idents.push(query_ident); } - let (resource_store, resource_idents) = self.resource_store(); + impl AddUpdates<#query_types, #resource_types, Func, #filter_types> for WorldBuilder + where + Func: Fn(&mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + Clone + 'static, + #filter_requirements + #component_requirements + #resource_requirement + { + fn add_update( + &mut self, + priority: u32, + func: Func, + ) -> Result<()> { + self.updates.add_update(priority, func) + } + } - TokenStream2::from(quote! { - impl CreateArchetype<#query_types, #resource_types, Func, #filter_types> for Archetype - where - Func: Fn(&mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + Clone + 'static, - #filter_requirements - #component_requirements - #reource_requirement - { - fn create(f: Func) -> Self { - #( #verify_dedup )* + impl EventReader for Events + where + Func: Fn(&P, &mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + 'static, + #filter_requirements + #component_requirements + #resource_requirement + P: std::any::Any + Send + Sync, + { + fn add_reader(&mut self, func: Func) { + match self.events.get_mut(&TypeId::of::

()) { + Some((_, listener)) => listener.push(std::sync::Arc::new(move |world, payload| { + let typed_payload: &P = payload.downcast_ref().unwrap(); + let mut commands = Commands::new(world.now()); - Self { - queries: #query_count, + #resource_store - check_entity: Box::new(move |entity| { + let mut complying_entities: Vec> = vec![Vec::new(); #query_count]; + + for entity in world.entities.values() { let mut comply_queries = Vec::new(); #( #check_entities )* - if comply_queries.is_empty() { - None - } else { - Some(comply_queries) + if !comply_queries.is_empty() { + comply_queries + .into_iter() + .for_each(|q| complying_entities[q].push(entity)); } - }), + } - create_callback: Box::new(move |entities| { + // check if one of the queries could not be fullfilled + for queryable_entities in complying_entities.iter() { + if queryable_entities.is_empty() { + return Ok(()); + } + } + + for entities in complying_entities.into_iter().multi_cartesian_product() { #( #component_stores )* + #( #query_structs )* - let f = f.clone(); + func(typed_payload, &mut commands, #( #query_idents, )* #( #resource_idents, )*)?; + } - Ok(Box::new(move |commands, world| { - #( #query_structs )* - #resource_store + commands.apply_deferred(world)?; - f(commands, #( #query_idents, )* #( #resource_idents, )* ) - })) - }), - - entities: IndexMap::new(), - } + Ok(()) + })), + None => panic!("register event type first!"), } } - - impl AddUpdates<#query_types, #resource_types, Func, #filter_types> for Updates - where - Func: Fn(&mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + Clone + 'static, - #filter_requirements - #component_requirements - #reource_requirement - { - fn add_update( - &mut self, - priority: u32, - func: Func, - ) -> Result<()> { - self.add(priority, Archetype::create(func)) - } - } - - impl AddUpdates<#query_types, #resource_types, Func, #filter_types> for WorldBuilder - where - Func: Fn(&mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + Clone + 'static, - #filter_requirements - #component_requirements - #reource_requirement - { - fn add_update( - &mut self, - priority: u32, - func: Func, - ) -> Result<()> { - self.updates.add_update(priority, func) - } - } - - impl EventReader for Events - where - Func: Fn(&P, &mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + 'static, - #filter_requirements - #component_requirements - #reource_requirement - P: std::any::Any + Send + Sync, - { - fn add_reader(&mut self, func: Func) { - match self.events.get_mut(&TypeId::of::

()) { - Some((_, listener)) => listener.push(std::sync::Arc::new(move |world, payload| { - let typed_payload: &P = payload.downcast_ref().unwrap(); - let mut commands = Commands::new(world.now()); - - #resource_store - - let mut complying_entities: Vec> = vec![Vec::new(); #query_count]; - - for entity in world.entities.values() { - let mut comply_queries = Vec::new(); - - #( #check_entities )* - - if !comply_queries.is_empty() { - comply_queries - .into_iter() - .for_each(|q| complying_entities[q].push(entity)); - } - } - - // check if one of the queries could not be fullfilled - for queryable_entities in complying_entities.iter() { - if queryable_entities.is_empty() { - return Ok(()); - } - } - - for entities in complying_entities.into_iter().multi_cartesian_product() { - #( #component_stores )* - #( #query_structs )* - - func(typed_payload, &mut commands, #( #query_idents, )* #( #resource_idents, )*)?; - } - - commands.apply_deferred(world)?; - - Ok(()) - })), - None => panic!("register event type first!"), - } - } - } - }) - .to_tokens(tokens); + } } } @@ -610,7 +258,10 @@ pub fn update(max_components: usize, max_resources: usize) -> TokenStream { for query in queries.iter() { for resource_count in resources.iter() { - updates.push(Update::new(query.iter().cloned(), *resource_count)); + updates.push(events_and_systems(&Update::new( + query.iter().cloned(), + *resource_count, + ))); } } @@ -618,7 +269,7 @@ pub fn update(max_components: usize, max_resources: usize) -> TokenStream { for resource_count in resources.iter() { let q = - Update::new(vec![1].into_iter(), *resource_count).resource_only_events_and_systems(); + resource_only_events_and_systems(&Update::new(vec![1].into_iter(), *resource_count)); events.push(q); }