From 624e6dd450944e67d84ad7afda54ae2abd277aba Mon Sep 17 00:00:00 2001 From: HampusM Date: Thu, 23 Jul 2026 17:38:51 +0200 Subject: refactor(engine-ecs): remove distinction between query terms with & without a field --- engine-ecs/src/query.rs | 302 +++++++++++++++++++++++++----------------------- 1 file changed, 158 insertions(+), 144 deletions(-) (limited to 'engine-ecs/src/query.rs') 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, } -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::()); + tracing::trace!("Searching for {}", std::any::type_name::()); 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::()); + tracing::trace!("Searching for {}", std::any::type_name::()); 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>, + OutIter: Iterator>, { - tracing::trace!("Searching for {}", std::any::type_name::()); + tracing::trace!("Searching for {}", std::any::type_name::()); 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 TermsBuilder } } -pub trait TermWithoutField +pub trait Term<'world> { - fn apply_to_terms_builder( - terms_builder: &mut TermsBuilder, - ); -} - -pub trait TermWithField -{ - type Field<'a>; + type AddField; fn apply_to_terms_builder( terms_builder: &mut TermsBuilder, ); - fn get_field<'world>( + fn add_field( entity_handle: &EntityHandle<'world>, world: &'world World, - ) -> Self::Field<'world>; + fields: Fields, + ) -> Self::AddField; } -impl TermWithField for &ComponentT +impl<'world, ComponentT: Component> Term<'world> for &ComponentT { - type Field<'a> = ComponentHandle<'a, ComponentT>; + type AddField = Fields::WithElementAtEnd>; fn apply_to_terms_builder( terms_builder: &mut TermsBuilder, @@ -325,10 +317,11 @@ impl TermWithField for &ComponentT terms_builder.present([ComponentT::id()]); } - fn get_field<'world>( + fn add_field( entity_handle: &EntityHandle<'world>, _world: &'world World, - ) -> Self::Field<'world> + fields: Fields, + ) -> Self::AddField { assert!(!ComponentT::id().is_pair()); @@ -346,18 +339,23 @@ impl TermWithField for &ComponentT ); }; - Self::Field::from_entity_component_ref(&component).unwrap_or_else(|err| { - panic!( - "Creating handle to component {} failed: {err}", - type_name::() - ); - }) + let component = match ComponentHandle::::from_entity_component_ref(&component) { + Ok(component) => component, + Err(err) => { + panic!( + "Creating handle to component {} failed: {err}", + type_name::() + ); + } + }; + + fields.with_elem(component) } } -impl TermWithField for &mut ComponentT +impl<'world, ComponentT: Component> Term<'world> for &mut ComponentT { - type Field<'a> = ComponentHandleMut<'a, ComponentT>; + type AddField = Fields::WithElementAtEnd>; fn apply_to_terms_builder( terms_builder: &mut TermsBuilder, @@ -366,10 +364,11 @@ impl TermWithField for &mut ComponentT terms_builder.present([ComponentT::id()]); } - fn get_field<'world>( + fn add_field( entity_handle: &EntityHandle<'world>, world: &'world World, - ) -> Self::Field<'world> + fields: Fields, + ) -> Self::AddField { assert!(!ComponentT::id().is_pair()); @@ -387,81 +386,95 @@ impl 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::() - ); - }) + let component = match ComponentHandleMut::::from_entity_component_ref(&component, world) { + Ok(component) => component, + Err(err) => { + panic!( + "Creating mut handle to component {} failed: {err}", + type_name::() + ); + } + }; + + fields.with_elem(component) } } -pub trait TermWithoutFieldTuple +impl<'world, TermT, FieldAcc> TermFieldSource<'world, FieldAcc> for TermT +where + TermT: Term<'world>, + TermT::AddField: Tuple, + FieldAcc: Tuple { - fn apply_terms_to_builder( - terms_builder: &mut TermsBuilder, - ); + type NewFieldAcc = TermT::AddField; + + 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( terms_builder: &mut TermsBuilder, ); - 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>, + TermsT: TermTuple<'world>, + EntityHandleIter: Iterator>, { world: &'world World, inner: EntityHandleIter, - comps_pd: PhantomData, + 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>, - 'world: 'query, + TermsT: TermTuple<'world>, + EntityHandleIter: Iterator>, { - type Item = FieldTerms::Fields<'query>; + type Item = TermsT::Fields; fn next(&mut self) -> Option { 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>, + TermsT: TermTuple<'world>, + EntityHandleIter: Iterator>, { world: &'world World, iter: EntityHandleIter, - comps_pd: PhantomData, + 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>, - 'world: 'query, + TermsT: TermTuple<'world>, + EntityHandleIter: Iterator>, { - type Item = (Uid, FieldTerms::Fields<'query>); + type Item = (Uid, TermsT::Fields); fn next(&mut self) -> Option { @@ -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! { + []::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( terms_builder: &mut TermsBuilder ) @@ -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( - terms_builder: &mut TermsBuilder - ) + #[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( - _terms_builder: &mut TermsBuilder, - ) - { - } -} - -impl TermWithFieldTuple for () -{ - type Fields<'component> = (); - - fn apply_terms_to_builder( - _terms_builder: &mut TermsBuilder, - ) - { - } - - fn get_fields<'component>( - _entity_handle: &EntityHandle<'_>, - _world: &'component World, - ) -> Self::Fields<'component> - { - } -} -- cgit v1.2.3-18-g5258