diff options
Diffstat (limited to 'engine-ecs/src/query.rs')
| -rw-r--r-- | engine-ecs/src/query.rs | 302 |
1 files changed, 158 insertions, 144 deletions
diff --git a/engine-ecs/src/query.rs b/engine-ecs/src/query.rs index 1b7bf43..8549411 100644 --- a/engine-ecs/src/query.rs +++ b/engine-ecs/src/query.rs @@ -2,6 +2,8 @@ use std::any::type_name; use std::marker::PhantomData; use seq_macro::seq; +use paste::paste; +use util_macros::sub; use crate::component::{ Component, @@ -11,6 +13,7 @@ use crate::component::{ use crate::entity::Handle as EntityHandle; use crate::query::flexible::{Iter as FlexibleQueryIter, Query as FlexibleQuery}; use crate::system::{Metadata as SystemMetadata, Param as SystemParam}; +use crate::tuple::Tuple; use crate::uid::Uid; use crate::util::array_vec::ArrayVec; use crate::util::Array; @@ -23,28 +26,26 @@ pub mod term; pub const MAX_TERM_CNT: usize = 17; #[derive(Debug)] -pub struct Query<'world, FieldTerms, FieldlessTerms = ()> +pub struct Query<'world, TermsT> where - FieldTerms: TermWithFieldTuple, - FieldlessTerms: TermWithoutFieldTuple, + TermsT: TermTuple<'world>, { inner: FlexibleQuery<'world, MAX_TERM_CNT>, - _pd: PhantomData<(FieldTerms, FieldlessTerms)>, + _pd: PhantomData<TermsT>, } -impl<'world, FieldTerms, FieldlessTerms> Query<'world, FieldTerms, FieldlessTerms> +impl<'world, TermsT> Query<'world, TermsT> where - FieldTerms: TermWithFieldTuple, - FieldlessTerms: TermWithoutFieldTuple, + TermsT: TermTuple<'world>, { /// Iterates over the entities matching this query, the iterator item being the entity /// components. #[must_use] - pub fn iter<'query>( - &'query self, - ) -> Iter<'query, 'world, FieldTerms, FlexibleQueryIter<'query>> + pub fn iter<'this>( + &'this self, + ) -> Iter<'this, 'world, TermsT, FlexibleQueryIter<'this, 'world>> { - tracing::trace!("Searching for {}", std::any::type_name::<FieldTerms>()); + tracing::trace!("Searching for {}", std::any::type_name::<TermsT>()); Iter { world: self.inner.world(), @@ -56,11 +57,11 @@ where /// Iterates over the entities matching this query, the iterator item being the entity /// [`Uid`] and the matching entity components. #[must_use] - pub fn iter_with_euids<'query>( - &'query self, - ) -> ComponentAndEuidIter<'query, 'world, FieldTerms, FlexibleQueryIter<'query>> + pub fn iter_with_euids<'this>( + &'this self, + ) -> ComponentAndEuidIter<'this, 'world, TermsT, FlexibleQueryIter<'this, 'world>> { - tracing::trace!("Searching for {}", std::any::type_name::<FieldTerms>()); + tracing::trace!("Searching for {}", std::any::type_name::<TermsT>()); ComponentAndEuidIter { world: self.inner.world(), @@ -75,14 +76,14 @@ where /// This function exists so that a custom [`EntityHandle`] iterator can be given to /// [`Iter`] without giving the user access to a reference to the [`World`]. #[must_use] - pub fn iter_with<'query, OutIter>( - &'query self, - func: impl FnOnce(FlexibleQueryIter<'query>) -> OutIter, - ) -> Iter<'query, 'world, FieldTerms, OutIter> + pub fn iter_with<'this, OutIter>( + &'this self, + func: impl FnOnce(FlexibleQueryIter<'this, 'world>) -> OutIter, + ) -> Iter<'this, 'world, TermsT, OutIter> where - OutIter: Iterator<Item = EntityHandle<'query>>, + OutIter: Iterator<Item = EntityHandle<'world>>, { - tracing::trace!("Searching for {}", std::any::type_name::<FieldTerms>()); + tracing::trace!("Searching for {}", std::any::type_name::<TermsT>()); Iter { world: self.inner.world(), @@ -101,7 +102,7 @@ where /// Returns a new `Query` created from a [`FlexibleQuery`]. /// /// # Important notes - /// The terms in `FieldTerms` and `FieldlessTerms` must be compatible with the terms + /// The terms in `TermsT` must be compatible with the terms /// in the given [`FlexibleQuery`], otherwise any method call or iterating might /// panic. #[must_use] @@ -126,8 +127,7 @@ where { let mut terms_builder = Terms::builder(); - FieldTerms::apply_terms_to_builder(&mut terms_builder); - FieldlessTerms::apply_terms_to_builder(&mut terms_builder); + TermsT::apply_terms_to_builder(&mut terms_builder); Self { inner: world.flexible_query(terms_builder.build()), @@ -136,14 +136,13 @@ where } } -impl<'query, 'world, FieldTerms, FieldlessTerms> IntoIterator - for &'query Query<'world, FieldTerms, FieldlessTerms> +impl<'query, 'world, TermsT> IntoIterator + for &'query Query<'world, TermsT> where - FieldTerms: TermWithFieldTuple, - FieldlessTerms: TermWithoutFieldTuple, + TermsT: TermTuple<'world>, { - type IntoIter = Iter<'query, 'world, FieldTerms, FlexibleQueryIter<'query>>; - type Item = FieldTerms::Fields<'query>; + type IntoIter = Iter<'query, 'world, TermsT, FlexibleQueryIter<'query, 'world>>; + type Item = TermsT::Fields; fn into_iter(self) -> Self::IntoIter { @@ -151,11 +150,10 @@ where } } -impl<'world, FieldTerms, FieldlessTerms> SystemParam<'world> - for Query<'world, FieldTerms, FieldlessTerms> +impl<'world, TermsT> SystemParam<'world> + for Query<'world, TermsT> where - FieldTerms: TermWithFieldTuple, - FieldlessTerms: TermWithoutFieldTuple, + TermsT: TermTuple<'world>, { type Input = (); @@ -293,30 +291,24 @@ impl<const MAX_TERM_CNT: usize> TermsBuilder<MAX_TERM_CNT> } } -pub trait TermWithoutField +pub trait Term<'world> { - fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( - terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, - ); -} - -pub trait TermWithField -{ - type Field<'a>; + type AddField<Fields: Tuple>; fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, ); - fn get_field<'world>( + fn add_field<Fields: Tuple>( entity_handle: &EntityHandle<'world>, world: &'world World, - ) -> Self::Field<'world>; + fields: Fields, + ) -> Self::AddField<Fields>; } -impl<ComponentT: Component> TermWithField for &ComponentT +impl<'world, ComponentT: Component> Term<'world> for &ComponentT { - type Field<'a> = ComponentHandle<'a, ComponentT>; + type AddField<Fields: Tuple> = Fields::WithElementAtEnd<ComponentHandle<'world, ComponentT>>; fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, @@ -325,10 +317,11 @@ impl<ComponentT: Component> TermWithField for &ComponentT terms_builder.present([ComponentT::id()]); } - fn get_field<'world>( + fn add_field<Fields: Tuple>( entity_handle: &EntityHandle<'world>, _world: &'world World, - ) -> Self::Field<'world> + fields: Fields, + ) -> Self::AddField<Fields> { assert!(!ComponentT::id().is_pair()); @@ -346,18 +339,23 @@ impl<ComponentT: Component> TermWithField for &ComponentT ); }; - Self::Field::from_entity_component_ref(&component).unwrap_or_else(|err| { - panic!( - "Creating handle to component {} failed: {err}", - type_name::<ComponentT>() - ); - }) + let component = match ComponentHandle::<ComponentT>::from_entity_component_ref(&component) { + Ok(component) => component, + Err(err) => { + panic!( + "Creating handle to component {} failed: {err}", + type_name::<ComponentT>() + ); + } + }; + + fields.with_elem(component) } } -impl<ComponentT: Component> TermWithField for &mut ComponentT +impl<'world, ComponentT: Component> Term<'world> for &mut ComponentT { - type Field<'a> = ComponentHandleMut<'a, ComponentT>; + type AddField<Fields: Tuple> = Fields::WithElementAtEnd<ComponentHandleMut<'world, ComponentT>>; fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, @@ -366,10 +364,11 @@ impl<ComponentT: Component> TermWithField for &mut ComponentT terms_builder.present([ComponentT::id()]); } - fn get_field<'world>( + fn add_field<Fields: Tuple>( entity_handle: &EntityHandle<'world>, world: &'world World, - ) -> Self::Field<'world> + fields: Fields, + ) -> Self::AddField<Fields> { assert!(!ComponentT::id().is_pair()); @@ -387,81 +386,95 @@ impl<ComponentT: Component> TermWithField for &mut ComponentT ); }; - Self::Field::from_entity_component_ref(&component, world).unwrap_or_else(|err| { - panic!( - "Creating handle to component {} failed: {err}", - type_name::<ComponentT>() - ); - }) + let component = match ComponentHandleMut::<ComponentT>::from_entity_component_ref(&component, world) { + Ok(component) => component, + Err(err) => { + panic!( + "Creating mut handle to component {} failed: {err}", + type_name::<ComponentT>() + ); + } + }; + + fields.with_elem(component) } } -pub trait TermWithoutFieldTuple +impl<'world, TermT, FieldAcc> TermFieldSource<'world, FieldAcc> for TermT +where + TermT: Term<'world>, + TermT::AddField<FieldAcc>: Tuple, + FieldAcc: Tuple { - fn apply_terms_to_builder<const MAX_TERM_CNT: usize>( - terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, - ); + type NewFieldAcc = TermT::AddField<FieldAcc>; + + fn collect_field( + entity_handle: &EntityHandle<'world>, + world: &'world World, + fields: FieldAcc, + ) -> Self::NewFieldAcc + { + Self::add_field(entity_handle, world, fields) + } } -pub trait TermWithFieldTuple +pub trait TermTuple<'world> { - type Fields<'component>; + type Fields; fn apply_terms_to_builder<const MAX_TERM_CNT: usize>( terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, ); - fn get_fields<'component>( - entity_handle: &EntityHandle<'component>, - world: &'component World, - ) -> Self::Fields<'component>; + fn get_fields( + entity_handle: &EntityHandle<'world>, + world: &'world World, + ) -> Self::Fields; } -pub struct Iter<'query, 'world, FieldTerms, EntityHandleIter> +pub struct Iter<'query, 'world, TermsT, EntityHandleIter> where - FieldTerms: TermWithFieldTuple, - EntityHandleIter: Iterator<Item = EntityHandle<'query>>, + TermsT: TermTuple<'world>, + EntityHandleIter: Iterator<Item = EntityHandle<'world>>, { world: &'world World, inner: EntityHandleIter, - comps_pd: PhantomData<FieldTerms>, + comps_pd: PhantomData<(TermsT, &'query ())>, } -impl<'query, 'world, FieldTerms, EntityHandleIter> Iterator - for Iter<'query, 'world, FieldTerms, EntityHandleIter> +impl<'query, 'world, TermsT, EntityHandleIter> Iterator + for Iter<'query, 'world, TermsT, EntityHandleIter> where - FieldTerms: TermWithFieldTuple, - EntityHandleIter: Iterator<Item = EntityHandle<'query>>, - 'world: 'query, + TermsT: TermTuple<'world>, + EntityHandleIter: Iterator<Item = EntityHandle<'world>>, { - type Item = FieldTerms::Fields<'query>; + type Item = TermsT::Fields; fn next(&mut self) -> Option<Self::Item> { let entity_handle = self.inner.next()?; - Some(FieldTerms::get_fields(&entity_handle, self.world)) + Some(TermsT::get_fields(&entity_handle, self.world)) } } -pub struct ComponentAndEuidIter<'query, 'world, FieldTerms, EntityHandleIter> +pub struct ComponentAndEuidIter<'query, 'world, TermsT, EntityHandleIter> where - FieldTerms: TermWithFieldTuple, - EntityHandleIter: Iterator<Item = EntityHandle<'query>>, + TermsT: TermTuple<'world>, + EntityHandleIter: Iterator<Item = EntityHandle<'world>>, { world: &'world World, iter: EntityHandleIter, - comps_pd: PhantomData<FieldTerms>, + comps_pd: PhantomData<(TermsT, &'query ())>, } -impl<'query, 'world, FieldTerms, EntityHandleIter> Iterator - for ComponentAndEuidIter<'query, 'world, FieldTerms, EntityHandleIter> +impl<'query, 'world, TermsT, EntityHandleIter> Iterator + for ComponentAndEuidIter<'query, 'world, TermsT, EntityHandleIter> where - FieldTerms: TermWithFieldTuple, - EntityHandleIter: Iterator<Item = EntityHandle<'query>>, - 'world: 'query, + TermsT: TermTuple<'world>, + EntityHandleIter: Iterator<Item = EntityHandle<'world>>, { - type Item = (Uid, FieldTerms::Fields<'query>); + type Item = (Uid, TermsT::Fields); fn next(&mut self) -> Option<Self::Item> { @@ -469,16 +482,50 @@ where Some(( entity_handle.uid(), - FieldTerms::get_fields(&entity_handle, self.world), + TermsT::get_fields(&entity_handle, self.world), )) } } -macro_rules! impl_term_sequence { +pub trait TermFieldSource<'world, FieldAcc> +{ + type NewFieldAcc; + + fn collect_field( + entity_handle: &EntityHandle<'world>, + world: &'world World, + fields: FieldAcc, + ) -> Self::NewFieldAcc; +} + +macro_rules! term_field_source_new_field_acc { + (overflow) => { + () + }; + + ($index: tt) => { + paste! { + [<Term $index>]::NewFieldAcc + } + }; +} + +macro_rules! gen_term_tuple_impls { ($c: tt) => { - seq!(I in 0..=$c { - impl<#(Term~I: TermWithoutField,)*> TermWithoutFieldTuple for (#(Term~I,)*) + seq!(I in 0..$c { + impl<'world, #(Term~I,)*> TermTuple<'world> for (#(Term~I,)*) + where + #( + Term~I: Term<'world> + TermFieldSource< + 'world, + sub!(I - 1, term_field_source_new_field_acc), + NewFieldAcc: Tuple + >, + )* { + type Fields = sub!($c - 1, term_field_source_new_field_acc); + + #[allow(unused)] fn apply_terms_to_builder<const MAX_TERM_CNT: usize>( terms_builder: &mut TermsBuilder<MAX_TERM_CNT> ) @@ -487,60 +534,27 @@ macro_rules! impl_term_sequence { Term~I::apply_to_terms_builder(terms_builder); )* } - } - - impl<#(Term~I: TermWithField,)*> TermWithFieldTuple for (#(Term~I,)*) - { - type Fields<'component> = (#(Term~I::Field<'component>,)*); - fn apply_terms_to_builder<const MAX_TERM_CNT: usize>( - terms_builder: &mut TermsBuilder<MAX_TERM_CNT> - ) + #[allow(unused)] + fn get_fields( + entity_handle: &EntityHandle<'world>, + world: &'world World, + ) -> Self::Fields { + let fields = (); + #( - Term~I::apply_to_terms_builder(terms_builder); + let fields = Term~I::collect_field(entity_handle, world, fields); )* - } - fn get_fields<'component>( - entity_handle: &EntityHandle<'component>, - world: &'component World, - ) -> Self::Fields<'component> - { - (#(Term~I::get_field(entity_handle, world),)*) + fields } } }); }; } -seq!(C in 0..=16 { - impl_term_sequence!(C); +seq!(C in 0..17 { + gen_term_tuple_impls!(C); }); -impl TermWithoutFieldTuple for () -{ - fn apply_terms_to_builder<const MAX_TERM_CNT: usize>( - _terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, - ) - { - } -} - -impl TermWithFieldTuple for () -{ - type Fields<'component> = (); - - fn apply_terms_to_builder<const MAX_TERM_CNT: usize>( - _terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, - ) - { - } - - fn get_fields<'component>( - _entity_handle: &EntityHandle<'_>, - _world: &'component World, - ) -> Self::Fields<'component> - { - } -} |
