summaryrefslogtreecommitdiff
path: root/engine-ecs/src/query.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine-ecs/src/query.rs')
-rw-r--r--engine-ecs/src/query.rs302
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>
- {
- }
-}