diff options
Diffstat (limited to 'engine-ecs/src/query.rs')
| -rw-r--r-- | engine-ecs/src/query.rs | 334 |
1 files changed, 190 insertions, 144 deletions
diff --git a/engine-ecs/src/query.rs b/engine-ecs/src/query.rs index 8549411..10260f2 100644 --- a/engine-ecs/src/query.rs +++ b/engine-ecs/src/query.rs @@ -1,8 +1,8 @@ use std::any::type_name; use std::marker::PhantomData; -use seq_macro::seq; use paste::paste; +use seq_macro::seq; use util_macros::sub; use crate::component::{ @@ -11,13 +11,27 @@ use crate::component::{ HandleMut as ComponentHandleMut, }; use crate::entity::Handle as EntityHandle; +use crate::pair::Wildcard; 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::tuple::{Concat, Tuple}; use crate::uid::Uid; use crate::util::array_vec::ArrayVec; use crate::util::Array; -use crate::World; +use crate::{pair, World}; + +mod reexports +{ + pub use crate::component::storage::{ + SearchTerms as Terms, + TermMetadata, + Traversal, + TraversalKind, + TraversalResult, + }; +} + +pub use reexports::*; pub mod flexible; pub mod term; @@ -27,23 +41,20 @@ pub const MAX_TERM_CNT: usize = 17; #[derive(Debug)] pub struct Query<'world, TermsT> -where - TermsT: TermTuple<'world>, { inner: FlexibleQuery<'world, MAX_TERM_CNT>, _pd: PhantomData<TermsT>, } impl<'world, TermsT> Query<'world, TermsT> -where - TermsT: TermTuple<'world>, { /// Iterates over the entities matching this query, the iterator item being the entity /// components. #[must_use] - pub fn iter<'this>( - &'this self, - ) -> Iter<'this, 'world, TermsT, FlexibleQueryIter<'this, 'world>> + pub fn iter<'this>(&'this self) -> Iter<'this, TermsT> + where + TermsT: TermTuple<'this>, + 'world: 'this, { tracing::trace!("Searching for {}", std::any::type_name::<TermsT>()); @@ -57,44 +68,25 @@ 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<'this>( - &'this self, - ) -> ComponentAndEuidIter<'this, 'world, TermsT, FlexibleQueryIter<'this, 'world>> - { - tracing::trace!("Searching for {}", std::any::type_name::<TermsT>()); - - ComponentAndEuidIter { - world: self.inner.world(), - iter: self.inner.iter(), - comps_pd: PhantomData, - } - } - - /// Iterates over the entities matching this query using the iterator returned by - /// `func`. - /// - /// 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<'this, OutIter>( - &'this self, - func: impl FnOnce(FlexibleQueryIter<'this, 'world>) -> OutIter, - ) -> Iter<'this, 'world, TermsT, OutIter> + pub fn iter_with_euids<'this>(&'this self) -> ComponentAndEuidIter<'this, TermsT> where - OutIter: Iterator<Item = EntityHandle<'world>>, + TermsT: TermTuple<'this>, + 'world: 'this, { tracing::trace!("Searching for {}", std::any::type_name::<TermsT>()); - Iter { + ComponentAndEuidIter { world: self.inner.world(), - inner: func(self.inner.iter()), + inner: self.inner.iter(), comps_pd: PhantomData, } } /// Returns the UID of the entity at the given query iteration index. #[must_use] - pub fn get_entity_uid(&self, entity_index: usize) -> Option<Uid> + pub fn get_entity_uid<'this>(&'this self, entity_index: usize) -> Option<Uid> + where + TermsT: TermTuple<'this>, { Some(self.inner.iter().nth(entity_index)?.uid()) } @@ -124,10 +116,12 @@ where } pub(crate) fn new(world: &'world World) -> Self + where + TermsT: TermTuple<'world>, { let mut terms_builder = Terms::builder(); - TermsT::apply_terms_to_builder(&mut terms_builder); + TermsT::apply_terms_to_builder(&mut terms_builder, 0); Self { inner: world.flexible_query(terms_builder.build()), @@ -136,12 +130,12 @@ where } } -impl<'query, 'world, TermsT> IntoIterator - for &'query Query<'world, TermsT> +impl<'query, 'world, TermsT> IntoIterator for &'query Query<'world, TermsT> where - TermsT: TermTuple<'world>, + TermsT: TermTuple<'query>, + 'world: 'query, { - type IntoIter = Iter<'query, 'world, TermsT, FlexibleQueryIter<'query, 'world>>; + type IntoIter = Iter<'query, TermsT>; type Item = TermsT::Fields; fn into_iter(self) -> Self::IntoIter @@ -150,8 +144,7 @@ where } } -impl<'world, TermsT> SystemParam<'world> - for Query<'world, TermsT> +impl<'world, TermsT> SystemParam<'world> for Query<'world, TermsT> where TermsT: TermTuple<'world>, { @@ -163,13 +156,6 @@ where } } -#[derive(Debug)] -pub struct Terms<const MAX_TERM_CNT: usize> -{ - present: ArrayVec<Uid, MAX_TERM_CNT>, - absent: ArrayVec<Uid, MAX_TERM_CNT>, -} - impl<const MAX_TERM_CNT: usize> Terms<MAX_TERM_CNT> { pub fn builder() -> TermsBuilder<MAX_TERM_CNT> @@ -180,30 +166,33 @@ impl<const MAX_TERM_CNT: usize> Terms<MAX_TERM_CNT> #[derive(Debug, Default)] #[must_use] -pub struct TermsBuilder<const MAX_TERM_CNT: usize> +pub struct TermsBuilder<const TERM_CAP: usize> { - present: ArrayVec<Uid, MAX_TERM_CNT>, - absent: ArrayVec<Uid, MAX_TERM_CNT>, + present: ArrayVec<Uid, TERM_CAP>, + absent: ArrayVec<Uid, TERM_CAP>, + traverse: ArrayVec<Traversal<TERM_CAP>, TERM_CAP>, } #[allow(clippy::return_self_not_must_use)] -pub trait TermsBuilderInterface +pub trait TermsBuilderInterface<const TERM_CAP: usize> { fn present(self, ids: impl Array<Uid>) -> Self; fn absent(self, ids: impl Array<Uid>) -> Self; + + fn traverse(self, traversals: impl Array<Traversal<TERM_CAP>> + Clone) -> Self; } macro_rules! impl_terms_builder { ($($impl_content: tt)*) => { - impl<const MAX_TERM_CNT: usize> - TermsBuilderInterface for TermsBuilder<MAX_TERM_CNT> + impl<const TERM_CAP: usize> + TermsBuilderInterface<TERM_CAP> for TermsBuilder<TERM_CAP> { $($impl_content)* } - impl<const MAX_TERM_CNT: usize> - TermsBuilderInterface for &mut TermsBuilder<MAX_TERM_CNT> + impl<const TERM_CAP: usize> + TermsBuilderInterface<TERM_CAP> for &mut TermsBuilder<TERM_CAP> { $($impl_content)* } @@ -274,6 +263,17 @@ impl_terms_builder! { self } + + #[allow(unused_mut)] + fn traverse(mut self, traversals: impl Array<Traversal<TERM_CAP>> + Clone) -> Self + { + self.traverse.extend(traversals.clone()); + + self.present( + traversals + .map(|traversal| pair!({ traversal.relation }, Wildcard).id()) + ) + } } impl<const MAX_TERM_CNT: usize> TermsBuilder<MAX_TERM_CNT> @@ -287,45 +287,49 @@ impl<const MAX_TERM_CNT: usize> TermsBuilder<MAX_TERM_CNT> Terms { present: self.present, absent: self.absent, + traverse: self.traverse, } } } -pub trait Term<'world> +pub trait Term<'query> { - type AddField<Fields: Tuple>; + type Fields: Tuple; fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, + term_metadata: TermMetadata, ); - fn add_field<Fields: Tuple>( - entity_handle: &EntityHandle<'world>, - world: &'world World, - fields: Fields, - ) -> Self::AddField<Fields>; + fn fields( + world: &'query World, + search_result: &SearchResult<'query, '_>, + term_metadata: TermMetadata, + ) -> Self::Fields; } -impl<'world, ComponentT: Component> Term<'world> for &ComponentT +impl<'query, ComponentT: Component> Term<'query> for &ComponentT { - type AddField<Fields: Tuple> = Fields::WithElementAtEnd<ComponentHandle<'world, ComponentT>>; + type Fields = (ComponentHandle<'query, ComponentT>,); fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, + _term_metadata: TermMetadata, ) { terms_builder.present([ComponentT::id()]); } - fn add_field<Fields: Tuple>( - entity_handle: &EntityHandle<'world>, - _world: &'world World, - fields: Fields, - ) -> Self::AddField<Fields> + fn fields( + _world: &'query World, + search_result: &SearchResult<'query, '_>, + _term_metadata: TermMetadata, + ) -> Self::Fields { assert!(!ComponentT::id().is_pair()); - let Some(component) = entity_handle + let Some(component) = search_result + .entity_handle .get_matching_components(ComponentT::id()) .next() else { @@ -335,44 +339,47 @@ impl<'world, ComponentT: Component> Term<'world> for &ComponentT "is most likely a bug in the entity querying" ), type_name::<ComponentT>(), - entity_handle.uid() + search_result.entity_handle.uid() ); }; - 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>() - ); - } - }; + 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) + (component,) } } -impl<'world, ComponentT: Component> Term<'world> for &mut ComponentT +impl<'query, ComponentT: Component> Term<'query> for &mut ComponentT { - type AddField<Fields: Tuple> = Fields::WithElementAtEnd<ComponentHandleMut<'world, ComponentT>>; + type Fields = (ComponentHandleMut<'query, ComponentT>,); fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, + _term_metadata: TermMetadata, ) { terms_builder.present([ComponentT::id()]); } - fn add_field<Fields: Tuple>( - entity_handle: &EntityHandle<'world>, - world: &'world World, - fields: Fields, - ) -> Self::AddField<Fields> + fn fields( + world: &'query World, + search_result: &SearchResult<'query, '_>, + _term_metadata: TermMetadata, + ) -> Self::Fields { assert!(!ComponentT::id().is_pair()); - let Some(component) = entity_handle + let Some(component) = search_result + .entity_handle .get_matching_components(ComponentT::id()) .next() else { @@ -382,11 +389,13 @@ impl<'world, ComponentT: Component> Term<'world> for &mut ComponentT "is most likely a bug in the entity querying" ), type_name::<ComponentT>(), - entity_handle.uid() + search_result.entity_handle.uid() ); }; - let component = match ComponentHandleMut::<ComponentT>::from_entity_component_ref(&component, world) { + let component = match ComponentHandleMut::<ComponentT>::from_entity_component_ref( + &component, world, + ) { Ok(component) => component, Err(err) => { panic!( @@ -396,57 +405,67 @@ impl<'world, ComponentT: Component> Term<'world> for &mut ComponentT } }; - fields.with_elem(component) + (component,) } } -impl<'world, TermT, FieldAcc> TermFieldSource<'world, FieldAcc> for TermT -where - TermT: Term<'world>, - TermT::AddField<FieldAcc>: Tuple, - FieldAcc: Tuple +impl<'query, TermT, FieldAcc> TermFieldSource<'query, FieldAcc> for TermT +where + TermT: Term<'query, Fields: Concat<FieldAcc>>, + FieldAcc: Tuple, { - type NewFieldAcc = TermT::AddField<FieldAcc>; + type NewFieldAcc = <TermT::Fields as Concat<FieldAcc>>::Output; fn collect_field( - entity_handle: &EntityHandle<'world>, - world: &'world World, + world: &'query World, + search_result: &SearchResult<'query, '_>, + term_metadata: TermMetadata, fields: FieldAcc, ) -> Self::NewFieldAcc { - Self::add_field(entity_handle, world, fields) + <TermT::Fields as Concat<FieldAcc>>::concat( + Self::fields(world, search_result, term_metadata), + fields, + ) } } -pub trait TermTuple<'world> +pub trait TermTuple<'query> { - type Fields; + type Fields: Tuple; fn apply_terms_to_builder<const MAX_TERM_CNT: usize>( terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, + term_level: u32, ); fn get_fields( - entity_handle: &EntityHandle<'world>, - world: &'world World, + world: &'query World, + search_result: &SearchResult<'query, '_>, + term_level: u32, ) -> Self::Fields; } -pub struct Iter<'query, 'world, TermsT, EntityHandleIter> +#[derive(Debug)] +#[non_exhaustive] +pub struct SearchResult<'query, 'temp> +{ + pub entity_handle: EntityHandle<'query>, + pub traversal_results: &'temp [TraversalResult], +} + +pub struct Iter<'query, TermsT> where - TermsT: TermTuple<'world>, - EntityHandleIter: Iterator<Item = EntityHandle<'world>>, + TermsT: TermTuple<'query>, { - world: &'world World, - inner: EntityHandleIter, - comps_pd: PhantomData<(TermsT, &'query ())>, + world: &'query World, + inner: FlexibleQueryIter<'query, MAX_TERM_CNT>, + comps_pd: PhantomData<TermsT>, } -impl<'query, 'world, TermsT, EntityHandleIter> Iterator - for Iter<'query, 'world, TermsT, EntityHandleIter> +impl<'query, TermsT> Iterator for Iter<'query, TermsT> where - TermsT: TermTuple<'world>, - EntityHandleIter: Iterator<Item = EntityHandle<'world>>, + TermsT: TermTuple<'query>, { type Item = TermsT::Fields; @@ -454,46 +473,58 @@ where { let entity_handle = self.inner.next()?; - Some(TermsT::get_fields(&entity_handle, self.world)) + Some(TermsT::get_fields( + self.world, + &SearchResult { + entity_handle, + traversal_results: self.inner.traversal_results().unwrap(), + }, + 0, + )) } } -pub struct ComponentAndEuidIter<'query, 'world, TermsT, EntityHandleIter> +pub struct ComponentAndEuidIter<'query, TermsT> where - TermsT: TermTuple<'world>, - EntityHandleIter: Iterator<Item = EntityHandle<'world>>, + TermsT: TermTuple<'query>, { - world: &'world World, - iter: EntityHandleIter, - comps_pd: PhantomData<(TermsT, &'query ())>, + world: &'query World, + inner: FlexibleQueryIter<'query, MAX_TERM_CNT>, + comps_pd: PhantomData<TermsT>, } -impl<'query, 'world, TermsT, EntityHandleIter> Iterator - for ComponentAndEuidIter<'query, 'world, TermsT, EntityHandleIter> +impl<'query, TermsT> Iterator for ComponentAndEuidIter<'query, TermsT> where - TermsT: TermTuple<'world>, - EntityHandleIter: Iterator<Item = EntityHandle<'world>>, + TermsT: TermTuple<'query>, { type Item = (Uid, TermsT::Fields); fn next(&mut self) -> Option<Self::Item> { - let entity_handle = self.iter.next()?; + let entity_handle = self.inner.next()?; Some(( entity_handle.uid(), - TermsT::get_fields(&entity_handle, self.world), + TermsT::get_fields( + self.world, + &SearchResult { + entity_handle, + traversal_results: self.inner.traversal_results().unwrap(), + }, + 0, + ), )) } } -pub trait TermFieldSource<'world, FieldAcc> +pub trait TermFieldSource<'query, FieldAcc> { type NewFieldAcc; fn collect_field( - entity_handle: &EntityHandle<'world>, - world: &'world World, + world: &'query World, + search_result: &SearchResult<'query, '_>, + term_metadata: TermMetadata, fields: FieldAcc, ) -> Self::NewFieldAcc; } @@ -513,11 +544,11 @@ macro_rules! term_field_source_new_field_acc { macro_rules! gen_term_tuple_impls { ($c: tt) => { seq!(I in 0..$c { - impl<'world, #(Term~I,)*> TermTuple<'world> for (#(Term~I,)*) + impl<'query, #(Term~I,)*> TermTuple<'query> for (#(Term~I,)*) where #( - Term~I: Term<'world> + TermFieldSource< - 'world, + Term~I: Term<'query> + TermFieldSource< + 'query, sub!(I - 1, term_field_source_new_field_acc), NewFieldAcc: Tuple >, @@ -527,24 +558,40 @@ macro_rules! gen_term_tuple_impls { #[allow(unused)] fn apply_terms_to_builder<const MAX_TERM_CNT: usize>( - terms_builder: &mut TermsBuilder<MAX_TERM_CNT> + terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, + term_level: u32, ) { #( - Term~I::apply_to_terms_builder(terms_builder); + Term~I::apply_to_terms_builder( + terms_builder, + TermMetadata { + level: term_level, + index: I + }, + ); )* } #[allow(unused)] fn get_fields( - entity_handle: &EntityHandle<'world>, - world: &'world World, + world: &'query World, + search_result: &SearchResult<'query, '_>, + term_level: u32, ) -> Self::Fields { let fields = (); #( - let fields = Term~I::collect_field(entity_handle, world, fields); + let fields = Term~I::collect_field( + world, + search_result, + TermMetadata { + level: term_level, + index: I + }, + fields + ); )* fields @@ -557,4 +604,3 @@ macro_rules! gen_term_tuple_impls { seq!(C in 0..17 { gen_term_tuple_impls!(C); }); - |
