Split proc macro crate

This commit is contained in:
hodasemi 2025-04-14 20:40:07 +02:00
parent 951060882e
commit 50735ddb31
8 changed files with 614 additions and 727 deletions

View file

@ -1,7 +1,7 @@
[workspace] [workspace]
resolver = "2" resolver = "2"
members = ["ecs", "update_macros"] members = ["ecs", "update_macros", "update_macro_base"]
[workspace.dependencies] [workspace.dependencies]
anyhow = { version = "1.0.86", features = ["backtrace"] } anyhow = { version = "1.0.86", features = ["backtrace"] }

View file

@ -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 }

View file

@ -0,0 +1,424 @@
use proc_macro2::TokenStream as TokenStream2;
use quote::{ToTokens, format_ident, quote};
use syn::Ident;
pub struct Query {
components: Vec<Ident>,
filter: Ident,
}
impl Query {
fn new(components: impl Iterator<Item = Ident>, 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::<Vec<_>>();
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::<Vec<_>>();
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<Ident> {
&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::<Vec<_>>();
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<Query>,
resources: Vec<Ident>,
}
impl Update {
pub const MIN_RESOURCE: usize = 0;
pub const MIN_COMPONENTS: usize = 1;
pub fn new(queries: impl Iterator<Item = usize>, 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::<Vec<_>>();
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::<Vec<_>>();
quote! {
#( #filter_types, )*
}
}
fn filter_requirements(&self) -> TokenStream2 {
let filter_requirements = self
.queries
.iter()
.map(|query| query.filter())
.collect::<Vec<_>>();
quote! {
#( #filter_requirements: CheckFilter + 'static, )*
}
}
fn query_types(&self) -> TokenStream2 {
let query_types = self
.queries
.iter()
.map(|query| query.types())
.collect::<Vec<_>>();
quote! {
( #( #query_types, )* )
}
}
fn query_type_impls(&self) -> TokenStream2 {
let query_types = self
.queries
.iter()
.map(|query| query.components())
.flatten()
.collect::<Vec<_>>();
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::<Vec<_>>();
quote! {
#( #component_requirements )*
}
}
fn resource_store(&self) -> (TokenStream2, Vec<Ident>) {
let resource_types = &self.resources;
let resource_idents = self
.resources
.iter()
.map(|resource| format_ident!("res_{resource}"))
.collect::<Vec<_>>();
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<Ident>,
}
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<TokenStream2>,
pub check_entities: Vec<TokenStream2>,
pub component_stores: Vec<TokenStream2>,
pub query_structs: Vec<TokenStream2>,
pub query_idents: Vec<Ident>,
}
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::<Vec<_>>();
let check_entities = self
.queries
.iter()
.enumerate()
.map(|(index, query)| query.check_entity(index))
.collect::<Vec<_>>();
let component_stores_and_queries = self
.queries
.iter()
.enumerate()
.map(|(index, query)| query.component_store_and_query(index))
.collect::<Vec<_>>();
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,
}
}
}

View file

@ -11,3 +11,5 @@ proc-macro = true
syn = { workspace = true } syn = { workspace = true }
quote = { workspace = true } quote = { workspace = true }
proc-macro2 = { workspace = true } proc-macro2 = { workspace = true }
update_macro_base = { path = "../update_macro_base" }

View file

@ -1,15 +1,11 @@
mod pair_update;
mod single_update;
mod update; mod update;
use pair_update::pair_update;
use single_update::single_update;
use update::update; use update::update;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use quote::quote; use quote::quote;
use syn::{ use syn::{
DeriveInput, Ident, LitInt, Result, DeriveInput, LitInt, Result,
parse::{Parse, ParseStream}, parse::{Parse, ParseStream},
parse_macro_input, parse_macro_input,
token::Comma, token::Comma,
@ -40,42 +36,6 @@ pub fn implement_updates(input: TokenStream) -> TokenStream {
update(input.max_components, input.max_resources) 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<Self> {
let macro_ident = input.parse::<Ident>()?;
input.parse::<Comma>()?;
let start = input.parse::<LitInt>()?.base10_parse()?;
input.parse::<Comma>()?;
let end = input.parse::<LitInt>()?.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)] #[proc_macro_derive(Resource)]
pub fn derive_resource(input: TokenStream) -> TokenStream { pub fn derive_resource(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput); let ast = parse_macro_input!(input as DeriveInput);

View file

@ -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<TupleType>, Vec<TupleType>)> = 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<TokenStream2> = 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<TokenStream2> = lhs
.iter()
.map(|tuple| {
let little = &tuple.little;
let big = &tuple.big;
quote! {
[#little: #big],
}
})
.collect();
let rhs_args: Vec<TokenStream2> = 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
)*
})
}

View file

@ -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<Ident>, Vec<Ident>)> = 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<TokenStream2> = generics
.iter()
.map(|(components, resources)| {
let macro_ident = &input.macro_ident;
quote! {
#macro_ident!(#(#components,)* [#(#resources,)*]);
}
})
.collect();
let generate_inputs: Vec<Vec<Ident>> = (input.start..=input.end)
.map(|count| {
(input.start..(input.start + count))
.map(|i| format_ident!("t{}", i))
.collect()
})
.collect();
let empty_resource_invocations: Vec<TokenStream2> = generate_inputs
.iter()
.map(|t| {
let macro_ident = &input.macro_ident;
quote! {
#macro_ident!(#(#t,)*);
}
})
.collect();
TokenStream::from(quote! {
#(
#empty_resource_invocations
#resource_invocations
)*
})
}

View file

@ -1,581 +1,229 @@
use proc_macro::TokenStream; use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2; use proc_macro2::TokenStream as TokenStream2;
use quote::{ToTokens, format_ident, quote}; use quote::quote;
use syn::Ident;
struct Query { use update_macro_base::*;
components: Vec<Ident>,
filter: Ident,
}
impl Query { pub fn resource_only_events_and_systems(update: &Update) -> TokenStream2 {
pub fn new(components: impl Iterator<Item = Ident>, filter_id: usize) -> Self { let resource_tokens = update.resourece_tokens();
Self {
components: components.collect(),
filter: format_ident!("Filter{filter_id}"),
}
}
pub fn types(&self) -> TokenStream2 { let resource_types = &resource_tokens.resource_types;
let component_list = self let resource_type_impls = &resource_tokens.resource_type_impls;
.components let resources = &resource_tokens.resources;
.iter() let resource_requirement = &resource_tokens.resource_requirement;
.map(|c| quote! { #c }) let resource_store = &resource_tokens.resource_store;
.collect::<Vec<_>>(); let resource_idents = &resource_tokens.resource_idents;
let components = if component_list.len() == 1 { quote! {
let component = &component_list[0]; impl<P, Func, #resource_type_impls> EventReader<P, (), #resource_types, Func, ()> for Events
quote! { #component } where
} else { Func: Fn(&P, &mut Commands, #resources ) -> Result<()> + Send + Sync + 'static,
quote! { ( #( #component_list, )* ) } #resource_requirement
}; P: std::any::Any + Send + Sync,
{
fn add_reader(&mut self, func: Func) {
match self.events.get_mut(&TypeId::of::<P>()) {
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 { commands.apply_deferred(world)?;
let components = &self.components;
let filter = &self.filter;
quote! { Ok(())
#( #filter::verify_dedup::<#components>(); )* })),
} None => panic!("register event type first!"),
}
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);
} }
} }
} }
}
pub fn component_store_and_query(&self, index: usize) -> (TokenStream2, TokenStream2, Ident) { impl<Func, #resource_type_impls> AddSystem<#resource_types, Func, ()> for WorldBuilder
let components = &self.components; where
let entity_name = format_ident!("entity_{index}"); Func: Fn(&mut Commands, #resources ) -> Result<bool> + Send + Sync + 'static,
let component_names = self #resource_requirement
.components {
.iter() fn add_system(&mut self, priority: u32, func: Func) {
.map(|component| format_ident!("q_{index}_{component}")) self.systems.push((priority, Box::new(move |world: &mut World, commands: &mut Commands| {
.collect::<Vec<_>>(); #resource_store
let query_ident = format_ident!("query_{index}"); func(commands, #( #resource_idents, )*)
let entity_ident = format_ident!("e_{index}"); })));
self.systems.sort_by_key(|(priority, _)| *priority);
(
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<Ident> {
&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::<Vec<_>>();
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<Query>,
resources: Vec<Ident>,
}
impl Update {
const MIN_RESOURCE: usize = 0;
const MIN_COMPONENTS: usize = 1;
pub fn new(queries: impl Iterator<Item = usize>, 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::<Vec<_>>();
if filter_types.len() == 1 {
let filter = &filter_types[0];
quote! {
#filter
} }
} else { }
quote! {
( #( #filter_types, )* ) impl<Func, #resource_type_impls> AddSystem<#resource_types, Func, World> for WorldBuilder
where
Func: Fn(&World, &mut Commands, #resources ) -> Result<bool> + 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 { fn events_and_systems(update: &Update) -> TokenStream2 {
let filter_types = self let query_tokens = update.query_tokens();
.queries
.iter()
.map(|query| query.filter())
.collect::<Vec<_>>();
quote! { let filter_types = &query_tokens.filter_types;
#( #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 resource_tokens = update.resourece_tokens();
let filter_requirements = self
.queries
.iter()
.map(|query| query.filter())
.collect::<Vec<_>>();
quote! { let resource_types = &resource_tokens.resource_types;
#( #filter_requirements: CheckFilter + 'static, )* 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 { quote! {
let query_types = self impl<Func, #filter_type_impls #query_type_impls #resource_type_impls> CreateArchetype<#query_types, #resource_types, Func, #filter_types> for Archetype
.queries where
.iter() Func: Fn(&mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + Clone + 'static,
.map(|query| query.types()) #filter_requirements
.collect::<Vec<_>>(); #component_requirements
#resource_requirement
{
fn create(f: Func) -> Self {
#( #verify_dedup )*
quote! { Self {
( #( #query_types, )* ) queries: #query_count,
}
}
pub fn query_type_impls(&self) -> TokenStream2 { check_entity: Box::new(move |entity| {
let query_types = self let mut comply_queries = Vec::new();
.queries
.iter()
.map(|query| query.components())
.flatten()
.collect::<Vec<_>>();
quote! { #( #check_entities )*
#( #query_types, )*
}
}
pub fn component_requirements(&self) -> TokenStream2 { if comply_queries.is_empty() {
let component_requirements = self None
.queries } else {
.iter() Some(comply_queries)
.map(|query| { }
query.components.iter().map(|component| { }),
quote! {
#component: EntityComponent + ComponentDebug,
}
})
})
.flatten()
.collect::<Vec<_>>();
quote! { create_callback: Box::new(move |entities| {
#( #component_requirements )* #( #component_stores )*
}
}
pub fn resource_store(&self) -> (TokenStream2, Vec<Ident>) { let f = f.clone();
let resource_types = &self.resources;
let resource_idents = self
.resources
.iter()
.map(|resource| format_ident!("res_{resource}"))
.collect::<Vec<_>>();
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<P, Func, #resource_type_impls> EventReader<P, (), #resource_types, Func, ()> 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::<P>()) {
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());
Ok(Box::new(move |commands, world| {
#( #query_structs )*
#resource_store #resource_store
func(typed_payload, &mut commands, #( #resource_idents, )*)?;
commands.apply_deferred(world)?; f(commands, #( #query_idents, )* #( #resource_idents, )* )
}))
}),
Ok(()) entities: IndexMap::new(),
})),
None => panic!("register event type first!"),
}
}
}
impl<Func, #resource_type_impls> AddSystem<#resource_types, Func, ()> for WorldBuilder
where
Func: Fn(&mut Commands, #resources ) -> Result<bool> + 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<Func, #resource_type_impls> AddSystem<#resource_types, Func, World> for WorldBuilder
where
Func: Fn(&World, &mut Commands, #resources ) -> Result<bool> + 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);
} }
} }
} }
}
}
impl ToTokens for Update { impl<Func, #filter_type_impls #query_type_impls #resource_type_impls> AddUpdates<#query_types, #resource_types, Func, #filter_types> for Updates
fn to_tokens(&self, tokens: &mut TokenStream2) { where
// generics to specify trait implementations Func: Fn(&mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + Clone + 'static,
let filter_types = self.filter_types(); #filter_requirements
let filter_type_impls = self.filter_type_impls(); #component_requirements
let query_types = self.query_types(); #resource_requirement
let query_type_impls = self.query_type_impls(); {
let resource_types = self.resource_types(); fn add_update(
let resource_type_impls = self.resource_type_impls(); &mut self,
priority: u32,
// panic!("{resource_type_impls}"); func: Func,
) -> Result<()> {
// function parameter self.add(priority, Archetype::create(func))
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 query_count = self.queries.len();
let verify_dedup = self
.queries
.iter()
.map(|query| query.dedup_checks())
.collect::<Vec<_>>();
let check_entities = self
.queries
.iter()
.enumerate()
.map(|(index, query)| query.check_entity(index))
.collect::<Vec<_>>();
let component_stores_and_queries = self
.queries
.iter()
.enumerate()
.map(|(index, query)| query.component_store_and_query(index))
.collect::<Vec<_>>();
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<Func, #filter_type_impls #query_type_impls #resource_type_impls> 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<P, Func, #filter_type_impls #query_type_impls #resource_type_impls> EventReader<P, #query_types, #resource_types, Func, #filter_types> for Events
impl<Func, #filter_type_impls #query_type_impls #resource_type_impls> CreateArchetype<#query_types, #resource_types, Func, #filter_types> for Archetype where
where Func: Fn(&P, &mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + 'static,
Func: Fn(&mut Commands, #( #queries, )* #resources ) -> Result<()> + Send + Sync + Clone + 'static, #filter_requirements
#filter_requirements #component_requirements
#component_requirements #resource_requirement
#reource_requirement P: std::any::Any + Send + Sync,
{ {
fn create(f: Func) -> Self { fn add_reader(&mut self, func: Func) {
#( #verify_dedup )* match self.events.get_mut(&TypeId::of::<P>()) {
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 { #resource_store
queries: #query_count,
check_entity: Box::new(move |entity| { let mut complying_entities: Vec<Vec<&EntityObject>> = vec![Vec::new(); #query_count];
for entity in world.entities.values() {
let mut comply_queries = Vec::new(); let mut comply_queries = Vec::new();
#( #check_entities )* #( #check_entities )*
if comply_queries.is_empty() { if !comply_queries.is_empty() {
None comply_queries
} else { .into_iter()
Some(comply_queries) .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 )* #( #component_stores )*
#( #query_structs )*
let f = f.clone(); func(typed_payload, &mut commands, #( #query_idents, )* #( #resource_idents, )*)?;
}
Ok(Box::new(move |commands, world| { commands.apply_deferred(world)?;
#( #query_structs )*
#resource_store
f(commands, #( #query_idents, )* #( #resource_idents, )* ) Ok(())
})) })),
}), None => panic!("register event type first!"),
entities: IndexMap::new(),
}
} }
} }
}
impl<Func, #filter_type_impls #query_type_impls #resource_type_impls> 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<Func, #filter_type_impls #query_type_impls #resource_type_impls> 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<P, Func, #filter_type_impls #query_type_impls #resource_type_impls> EventReader<P, #query_types, #resource_types, Func, #filter_types> 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::<P>()) {
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<&EntityObject>> = 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 query in queries.iter() {
for resource_count in resources.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() { for resource_count in resources.iter() {
let q = 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); events.push(q);
} }