Start implementing proc macro for updates
This commit is contained in:
parent
4370853e23
commit
7ee6ef0a08
3 changed files with 284 additions and 52 deletions
|
@ -13,6 +13,3 @@ ron.workspace = true
|
||||||
utilities.workspace = true
|
utilities.workspace = true
|
||||||
|
|
||||||
update_macros = { path = "../update_macros" }
|
update_macros = { path = "../update_macros" }
|
||||||
|
|
||||||
[features]
|
|
||||||
timings = []
|
|
||||||
|
|
|
@ -4,15 +4,10 @@ use std::ops::{Deref, DerefMut};
|
||||||
use std::{any::TypeId, marker::PhantomData};
|
use std::{any::TypeId, marker::PhantomData};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
#[cfg(feature = "timings")]
|
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
#[cfg(feature = "timings")]
|
|
||||||
use super::super::timings::Timings;
|
|
||||||
|
|
||||||
use crate::resources::Resource as ResourceTrait;
|
use crate::resources::Resource as ResourceTrait;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use update_macros::{implement_pair_update, implement_single_update};
|
use update_macros::{implement_pair_update, implement_single_update};
|
||||||
|
@ -1152,18 +1147,12 @@ impl From<ArchetypePair> for Update {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Updates {
|
pub struct Updates {
|
||||||
#[cfg(feature = "timings")]
|
updates: Vec<(u32, Update)>,
|
||||||
timings: Timings,
|
|
||||||
|
|
||||||
updates: Vec<(String, u32, Update)>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Updates {
|
impl Default for Updates {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
#[cfg(feature = "timings")]
|
|
||||||
timings: Timings::default,
|
|
||||||
|
|
||||||
updates: Vec::new(),
|
updates: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1171,22 +1160,9 @@ impl Default for Updates {
|
||||||
|
|
||||||
impl Updates {
|
impl Updates {
|
||||||
pub(crate) fn update(&mut self, world: &mut World) -> Result<()> {
|
pub(crate) fn update(&mut self, world: &mut World) -> Result<()> {
|
||||||
#[cfg(feature = "timings")]
|
|
||||||
if let Some(timings) = self.timings.check_timing(world.now(), None) {
|
|
||||||
if !timings.is_empty() {
|
|
||||||
println!("timings: {:#?}", timings);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "timings")]
|
|
||||||
let timings = &mut self.timings;
|
|
||||||
|
|
||||||
self.updates
|
self.updates
|
||||||
.iter()
|
.iter()
|
||||||
.try_for_each(|(_name, _, update)| -> Result<()> {
|
.try_for_each(|(_, update)| -> Result<()> {
|
||||||
#[cfg(feature = "timings")]
|
|
||||||
let before = Instant::now();
|
|
||||||
|
|
||||||
match update {
|
match update {
|
||||||
Update::Single(archetype) => {
|
Update::Single(archetype) => {
|
||||||
archetype.execute(world)?;
|
archetype.execute(world)?;
|
||||||
|
@ -1196,9 +1172,6 @@ impl Updates {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "timings")]
|
|
||||||
timings.add(_name, Instant::now().duration_since(before));
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
@ -1210,7 +1183,7 @@ impl Updates {
|
||||||
entity_object: &EntityObject,
|
entity_object: &EntityObject,
|
||||||
entities: &IndexMap<Entity, EntityObject>,
|
entities: &IndexMap<Entity, EntityObject>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
for (_, _, update) in self.updates.iter_mut() {
|
for (_, update) in self.updates.iter_mut() {
|
||||||
match update {
|
match update {
|
||||||
Update::Single(archetype) => {
|
Update::Single(archetype) => {
|
||||||
archetype.add_entity(entity_object)?;
|
archetype.add_entity(entity_object)?;
|
||||||
|
@ -1225,7 +1198,7 @@ impl Updates {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn remove_entity(&mut self, entity: Entity) {
|
pub(crate) fn remove_entity(&mut self, entity: Entity) {
|
||||||
for (_, _, update) in self.updates.iter_mut() {
|
for (_, update) in self.updates.iter_mut() {
|
||||||
match update {
|
match update {
|
||||||
Update::Single(archetype) => {
|
Update::Single(archetype) => {
|
||||||
archetype.remove_entity(entity);
|
archetype.remove_entity(entity);
|
||||||
|
@ -1244,13 +1217,10 @@ impl Updates {
|
||||||
// self.timings.clear();
|
// self.timings.clear();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
pub(crate) fn add(&mut self, name: &str, priority: u32, update: Update) -> Result<()> {
|
pub(crate) fn add(&mut self, priority: u32, update: Update) -> Result<()> {
|
||||||
#[cfg(feature = "timings")]
|
self.updates.push((priority, update));
|
||||||
self.timings.add_timing_afterwards(name);
|
|
||||||
|
|
||||||
self.updates.push((name.to_string(), priority, update));
|
|
||||||
self.updates
|
self.updates
|
||||||
.sort_by(|(_, lhs_prio, _), (_, rhs_prio, _)| lhs_prio.cmp(rhs_prio));
|
.sort_by(|(lhs_prio, _), (rhs_prio, _)| lhs_prio.cmp(rhs_prio));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,46 +16,113 @@ impl Query {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn types(&self) -> proc_macro2::TokenStream {
|
pub fn types(&self) -> TokenStream2 {
|
||||||
let component_list = self
|
let component_list = self
|
||||||
.components
|
.components
|
||||||
.iter()
|
.iter()
|
||||||
.map(|c| quote! { #c, })
|
.map(|c| quote! { #c })
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let components = if component_list.len() == 1 {
|
let components = if component_list.len() == 1 {
|
||||||
let component = &component_list[0];
|
let component = &component_list[0];
|
||||||
quote! { #component }
|
quote! { #component }
|
||||||
} else {
|
} else {
|
||||||
quote! { ( #(#component_list)* ) }
|
quote! { ( #( #component_list, )* ) }
|
||||||
};
|
};
|
||||||
|
|
||||||
components
|
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 = &entites[#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::<Vec<_>>();
|
||||||
|
let query_ident = format_ident!("query_{index}");
|
||||||
|
let entity_ident = format_ident!("entity_{index}");
|
||||||
|
|
||||||
|
(
|
||||||
|
quote! {
|
||||||
|
let #entity_name = &entities[#index];
|
||||||
|
let #entity_ident = entity_name.as_entity();
|
||||||
|
|
||||||
|
#(
|
||||||
|
let #component_name = UnsafeComponentStore::from(
|
||||||
|
entity.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<Ident> {
|
||||||
|
&self.components
|
||||||
|
}
|
||||||
|
|
||||||
pub fn filter(&self) -> &Ident {
|
pub fn filter(&self) -> &Ident {
|
||||||
&self.filter
|
&self.filter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToTokens for Query {
|
impl ToTokens for Query {
|
||||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
let component_list = self
|
let component_list = self
|
||||||
.components
|
.components
|
||||||
.iter()
|
.iter()
|
||||||
.map(|c| quote! { &mut #c, })
|
.map(|c| quote! { &mut #c })
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let components = if component_list.len() == 1 {
|
let components = if component_list.len() == 1 {
|
||||||
let component = &component_list[0];
|
let component = &component_list[0];
|
||||||
quote! { #component }
|
quote! { #component }
|
||||||
} else {
|
} else {
|
||||||
quote! { ( #(#component_list)* ) }
|
quote! { ( #( #component_list, )* ) }
|
||||||
};
|
};
|
||||||
|
|
||||||
let filter = self.filter.clone();
|
let filter = self.filter.clone();
|
||||||
|
|
||||||
proc_macro2::TokenStream::from(quote! {
|
TokenStream2::from(quote! {
|
||||||
Query<#components, #filter>
|
Query<#components, #filter>
|
||||||
})
|
})
|
||||||
.to_tokens(tokens);
|
.to_tokens(tokens);
|
||||||
|
@ -68,6 +135,10 @@ struct Update {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Update {
|
impl Update {
|
||||||
|
const MIN_RESOURCE: usize = 0;
|
||||||
|
const MIN_COMPONENTS: usize = 1;
|
||||||
|
const MIN_QUERIES: usize = 1;
|
||||||
|
|
||||||
pub fn new(queries: impl Iterator<Item = usize>, resources: usize) -> Self {
|
pub fn new(queries: impl Iterator<Item = usize>, resources: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
queries: queries
|
queries: queries
|
||||||
|
@ -85,14 +156,208 @@ impl Update {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn query_types(&self)
|
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, )* )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn filter_requirements(&self) -> TokenStream2 {
|
||||||
|
let filter_requirements = self
|
||||||
|
.queries
|
||||||
|
.iter()
|
||||||
|
.map(|query| query.filter())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#( #filter_requirements: CheckFilter + 'static, )*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn query_types(&self) -> TokenStream2 {
|
||||||
|
let query_types = self
|
||||||
|
.queries
|
||||||
|
.iter()
|
||||||
|
.map(|query| query.types())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
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::<Vec<_>>();
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#( #component_requirements, )*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resource_types(&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 query_types = self.query_types();
|
||||||
|
let resource_types = self.resource_types();
|
||||||
|
|
||||||
|
// 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::<Vec<_>>();
|
||||||
|
|
||||||
|
let check_entities = self
|
||||||
|
.queries
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(index, query)| query.check_entity(index))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let component_stores = self
|
||||||
|
.queries
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(index, query)| query.component_store_and_query(index))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
TokenStream2::from(quote! {
|
||||||
|
impl<Func, #filter_types, #query_types, #resource_types> 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| {
|
||||||
|
let e = entity.as_entity();
|
||||||
|
let f = f.clone();
|
||||||
|
|
||||||
|
Ok(Box::new(move |commands, world| {
|
||||||
|
|
||||||
|
|
||||||
|
f(commands )
|
||||||
|
}))
|
||||||
|
}),
|
||||||
|
|
||||||
|
entities: IndexMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Func, #filter_types, #query_types, #resource_types> 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_types, #query_types, #resource_types> 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 {
|
pub fn update(max_components: usize, max_queries: usize) -> TokenStream {
|
||||||
|
let updates = (Update::MIN_QUERIES..max_queries)
|
||||||
|
.map(|query_count| {
|
||||||
|
//
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
TokenStream::from(quote! {
|
TokenStream::from(quote! {
|
||||||
impl<Func, Filter, >
|
#( #updates )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue