use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; use quote::{ToTokens, format_ident, quote}; use syn::Ident; struct Query { components: Vec, filter: Ident, } impl Query { pub fn new(components: impl Iterator, filter_id: usize) -> Self { Self { components: components.collect(), filter: format_ident!("Filter{filter_id}"), } } pub 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 } pub fn dedup_checks(&self) -> TokenStream2 { let components = &self.components; let filter = &self.filter; quote! { #( #filter::verify_dedup::<#components>(); )* } } pub fn check_entity(&self, index: usize) -> TokenStream2 { let components = &self.components; let filter = &self.filter; quote! { { let entity = &entities[#index]; #( if !entity.components.contains::<#components>() { return false; } )* if !#filter::check(entity) { return false; } } } } 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_name = 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(); #( let #component_name = UnsafeComponentStore::from( #entity_name.get_component::<#components>()? ); )* }, quote! { let #query_ident = Query { entity: #entity_ident, c: unsafe { ( #( #component_name.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 MAX_RESOURCE: usize = 10; const MIN_COMPONENTS: usize = 1; const MIN_QUERIES: 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 } } else { quote! { ( #( #filter_types, )* ) } } } pub fn filter_type_impls(&self) -> TokenStream2 { let filter_types = self .queries .iter() .map(|query| query.filter()) .collect::>(); quote! { #( #filter_types, )* } } pub fn filter_requirements(&self) -> TokenStream2 { let filter_requirements = self .queries .iter() .map(|query| query.filter()) .collect::>(); quote! { #( #filter_requirements: CheckFilter + 'static, )* } } pub fn query_types(&self) -> TokenStream2 { let query_types = self .queries .iter() .map(|query| query.types()) .collect::>(); quote! { ( #( #query_types, )* ) } } pub fn query_type_impls(&self) -> TokenStream2 { let query_types = self .queries .iter() .map(|query| query.components()) .flatten() .collect::>(); quote! { #( #query_types, )* } } 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::>(); quote! { #( #component_requirements )* } } 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::>(); ( quote! { 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, )* } } } 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, )* } }; // trait requirements let filter_requirements = self.filter_requirements(); let component_requirements = self.component_requirements(); let reource_requirement = self.reource_requirement(); 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(); 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 )* Self { check_entity: Box::new(move |entities| { #( #check_entities )* true }), create_callback: Box::new(move |entities| { #( #component_stores )* let f = f.clone(); Ok(Box::new(move |commands, world| { #( #query_structs )* #resource_store f(commands, #( #query_idents, )* #( #resource_idents, )*) })) }), entities: IndexMap::new(), } } } 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) } } }) .to_tokens(tokens); } } pub fn update(max_components: usize, max_queries: usize) -> TokenStream { // let updates = (Update::MIN_QUERIES..max_queries) // .map(|query_count| { // let queries = (1..query_count).map(|q| { // }) // }) // .collect::>(); let mut query_counts = Vec::new(); for components in Update::MIN_COMPONENTS..=max_components { query_counts.push(components); } let mut resources = Vec::new(); for resource in Update::MIN_RESOURCE..Update::MAX_RESOURCE { resources.push(resource); } let updates = vec![Update::new(vec![2, 2].into_iter(), 1)]; TokenStream::from(quote! { #( #updates )* }) }