diff options
Diffstat (limited to 'ecs/src/query.rs')
| -rw-r--r-- | ecs/src/query.rs | 569 |
1 files changed, 0 insertions, 569 deletions
diff --git a/ecs/src/query.rs b/ecs/src/query.rs deleted file mode 100644 index 5f13579..0000000 --- a/ecs/src/query.rs +++ /dev/null @@ -1,569 +0,0 @@ -use std::any::type_name; -use std::marker::PhantomData; - -use seq_macro::seq; - -use crate::component::{ - Component, - Handle as ComponentHandle, - HandleMut as ComponentHandleMut, -}; -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::uid::{Kind as UidKind, Uid, With as WithUid}; -use crate::util::array_vec::ArrayVec; -use crate::util::Array; -use crate::World; - -pub mod flexible; -pub mod term; - -// A term tuple type can have a maximum of 17 elements -pub const MAX_TERM_CNT: usize = 17; - -#[derive(Debug)] -pub struct Query<'world, FieldTerms, FieldlessTerms = ()> -where - FieldTerms: TermWithFieldTuple, - FieldlessTerms: TermWithoutFieldTuple, -{ - inner: FlexibleQuery<'world, MAX_TERM_CNT>, - _pd: PhantomData<(FieldTerms, FieldlessTerms)>, -} - -impl<'world, FieldTerms, FieldlessTerms> Query<'world, FieldTerms, FieldlessTerms> -where - FieldTerms: TermWithFieldTuple, - FieldlessTerms: TermWithoutFieldTuple, -{ - /// 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>> - { - tracing::trace!("Searching for {}", std::any::type_name::<FieldTerms>()); - - Iter { - world: self.inner.world(), - inner: self.inner.iter(), - comps_pd: PhantomData, - } - } - - /// 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>> - { - tracing::trace!("Searching for {}", std::any::type_name::<FieldTerms>()); - - 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<'query, OutIter>( - &'query self, - func: impl FnOnce(FlexibleQueryIter<'query>) -> OutIter, - ) -> Iter<'query, 'world, FieldTerms, OutIter> - where - OutIter: Iterator<Item = EntityHandle<'query>>, - { - tracing::trace!("Searching for {}", std::any::type_name::<FieldTerms>()); - - Iter { - world: self.inner.world(), - inner: func(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> - { - Some(self.inner.iter().nth(entity_index)?.uid()) - } - - /// Returns a new `Query` created from a [`FlexibleQuery`]. - /// - /// # Important notes - /// The terms in `FieldTerms` and `FieldlessTerms` must be compatible with the terms - /// in the given [`FlexibleQuery`], otherwise any method call or iterating might - /// panic. - #[must_use] - pub fn from_flexible_query( - flexible_query: FlexibleQuery<'world, MAX_TERM_CNT>, - ) -> Self - { - // TODO: Check compatability of terms - - Self { - inner: flexible_query, - _pd: PhantomData, - } - } - - pub(crate) fn new(world: &'world World) -> Self - { - let mut terms_builder = Terms::builder(); - - FieldTerms::apply_terms_to_builder(&mut terms_builder); - FieldlessTerms::apply_terms_to_builder(&mut terms_builder); - - Self { - inner: world.flexible_query(terms_builder.build()), - _pd: PhantomData, - } - } -} - -impl<'query, 'world, FieldTerms, FieldlessTerms> IntoIterator - for &'query Query<'world, FieldTerms, FieldlessTerms> -where - FieldTerms: TermWithFieldTuple, - FieldlessTerms: TermWithoutFieldTuple, -{ - type IntoIter = Iter<'query, 'world, FieldTerms, FlexibleQueryIter<'query>>; - type Item = FieldTerms::Fields<'query>; - - fn into_iter(self) -> Self::IntoIter - { - self.iter() - } -} - -impl<'world, FieldTerms, FieldlessTerms> SystemParam<'world> - for Query<'world, FieldTerms, FieldlessTerms> -where - FieldTerms: TermWithFieldTuple, - FieldlessTerms: TermWithoutFieldTuple, -{ - type Input = (); - - fn new(world: &'world World, _system_metadata: &SystemMetadata) -> Self - { - Self::new(world) - } -} - -#[derive(Debug)] -pub struct Terms<const MAX_TERM_CNT: usize> -{ - required_components: ArrayVec<Uid, MAX_TERM_CNT>, - excluded_components: ArrayVec<Uid, MAX_TERM_CNT>, -} - -impl<const MAX_TERM_CNT: usize> Terms<MAX_TERM_CNT> -{ - pub fn builder() -> TermsBuilder<MAX_TERM_CNT> - { - TermsBuilder::default() - } -} - -#[derive(Debug, Default)] -#[must_use] -pub struct TermsBuilder<const MAX_TERM_CNT: usize> -{ - required_components: ArrayVec<Uid, MAX_TERM_CNT>, - excluded_components: ArrayVec<Uid, MAX_TERM_CNT>, -} - -#[allow(clippy::return_self_not_must_use)] -pub trait TermsBuilderInterface -{ - fn with<WithUidT: WithUid>(self) -> Self; - - fn without<WithUidT: WithUid>(self) -> Self; - - fn with_required(self, ids: impl Array<Uid>) -> Self; - - fn without_ids(self, ids: impl Array<Uid>) -> Self; -} - -macro_rules! impl_terms_builder { - ($($impl_content: tt)*) => { - impl<const MAX_TERM_CNT: usize> - TermsBuilderInterface for TermsBuilder<MAX_TERM_CNT> - { - $($impl_content)* - } - - impl<const MAX_TERM_CNT: usize> - TermsBuilderInterface for &mut TermsBuilder<MAX_TERM_CNT> - { - $($impl_content)* - } - }; -} - -impl_terms_builder! { - #[allow(unused_mut)] - fn with<WithUidT: WithUid>(mut self) -> Self - { - let insert_index = self.required_components - .partition_point(|id| *id <= WithUidT::uid()); - - self.required_components - .insert(insert_index, WithUidT::uid()); - - self - } - - #[allow(unused_mut)] - fn without<WithUidT: WithUid>(mut self) -> Self - { - let insert_index = self.excluded_components - .partition_point(|id| *id <= WithUidT::uid()); - - self.excluded_components - .insert(insert_index, WithUidT::uid()); - - self - } - - #[allow(unused_mut)] - fn with_required(mut self, mut ids: impl Array<Uid>) -> Self - { - if !ids.as_ref().is_sorted() { - ids.as_mut().sort(); - } - - if self.required_components.is_empty() { - self.required_components.extend(ids); - return self; - } - - let mut id_iter = ids.into_iter(); - - while let Some(id) = id_iter.next() { - let insert_index = self.required_components - .partition_point(|other_id| *other_id <= id); - - if insert_index == self.required_components.len() { - self.required_components.extend([id].into_iter().chain(id_iter)); - - return self; - } - - self.required_components - .insert(insert_index, id); - - } - - self - } - - #[allow(unused_mut)] - fn without_ids(mut self, mut ids: impl Array<Uid>) -> Self - { - if !ids.as_ref().is_sorted() { - ids.as_mut().sort(); - } - - if self.excluded_components.is_empty() { - self.excluded_components.extend(ids); - return self; - } - - let mut id_iter = ids.into_iter(); - - while let Some(id) = id_iter.next() { - let insert_index = self.excluded_components - .partition_point(|other_id| *other_id <= id); - - if insert_index == self.excluded_components.len() { - self.excluded_components.extend([id].into_iter().chain(id_iter)); - - return self; - } - - self.excluded_components - .insert(insert_index, id); - - } - - self - } -} - -impl<const MAX_TERM_CNT: usize> TermsBuilder<MAX_TERM_CNT> -{ - #[must_use] - pub fn build(self) -> Terms<MAX_TERM_CNT> - { - debug_assert!(self.required_components.is_sorted()); - debug_assert!(self.excluded_components.is_sorted()); - - Terms { - required_components: self.required_components, - excluded_components: self.excluded_components, - } - } -} - -pub trait TermWithoutField -{ - fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( - terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, - ); -} - -pub trait TermWithField -{ - type Field<'a>; - - fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( - terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, - ); - - fn get_field<'world>( - entity_handle: &EntityHandle<'world>, - world: &'world World, - ) -> Self::Field<'world>; -} - -impl<ComponentT: Component> TermWithField for &ComponentT -{ - type Field<'a> = ComponentHandle<'a, ComponentT>; - - fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( - terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, - ) - { - terms_builder.with::<ComponentT>(); - } - - fn get_field<'world>( - entity_handle: &EntityHandle<'world>, - _world: &'world World, - ) -> Self::Field<'world> - { - assert_eq!(ComponentT::id().kind(), UidKind::Component); - - let Some(component) = entity_handle - .get_matching_components(ComponentT::id()) - .next() - else { - panic!( - concat!( - "Component {} was not found in entity {}. There ", - "is most likely a bug in the entity querying" - ), - type_name::<ComponentT>(), - entity_handle.uid() - ); - }; - - Self::Field::from_entity_component_ref(&component).unwrap_or_else(|err| { - panic!( - "Creating handle to component {} failed: {err}", - type_name::<ComponentT>() - ); - }) - } -} - -impl<ComponentT: Component> TermWithField for &mut ComponentT -{ - type Field<'a> = ComponentHandleMut<'a, ComponentT>; - - fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( - terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, - ) - { - terms_builder.with::<ComponentT>(); - } - - fn get_field<'world>( - entity_handle: &EntityHandle<'world>, - world: &'world World, - ) -> Self::Field<'world> - { - assert_eq!(ComponentT::id().kind(), UidKind::Component); - - let Some(component) = entity_handle - .get_matching_components(ComponentT::id()) - .next() - else { - panic!( - concat!( - "Component {} was not found in entity {}. There ", - "is most likely a bug in the entity querying" - ), - type_name::<ComponentT>(), - entity_handle.uid() - ); - }; - - Self::Field::from_entity_component_ref(&component, world).unwrap_or_else(|err| { - panic!( - "Creating handle to component {} failed: {err}", - type_name::<ComponentT>() - ); - }) - } -} - -pub trait TermWithoutFieldTuple -{ - fn apply_terms_to_builder<const MAX_TERM_CNT: usize>( - terms_builder: &mut TermsBuilder<MAX_TERM_CNT>, - ); -} - -pub trait TermWithFieldTuple -{ - 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<'component>, - world: &'component World, - ) -> Self::Fields<'component>; -} - -pub struct Iter<'query, 'world, FieldTerms, EntityHandleIter> -where - FieldTerms: TermWithFieldTuple, - EntityHandleIter: Iterator<Item = EntityHandle<'query>>, -{ - world: &'world World, - inner: EntityHandleIter, - comps_pd: PhantomData<FieldTerms>, -} - -impl<'query, 'world, FieldTerms, EntityHandleIter> Iterator - for Iter<'query, 'world, FieldTerms, EntityHandleIter> -where - FieldTerms: TermWithFieldTuple, - EntityHandleIter: Iterator<Item = EntityHandle<'query>>, - 'world: 'query, -{ - type Item = FieldTerms::Fields<'query>; - - fn next(&mut self) -> Option<Self::Item> - { - let entity_handle = self.inner.next()?; - - Some(FieldTerms::get_fields(&entity_handle, self.world)) - } -} - -pub struct ComponentAndEuidIter<'query, 'world, FieldTerms, EntityHandleIter> -where - FieldTerms: TermWithFieldTuple, - EntityHandleIter: Iterator<Item = EntityHandle<'query>>, -{ - world: &'world World, - iter: EntityHandleIter, - comps_pd: PhantomData<FieldTerms>, -} - -impl<'query, 'world, FieldTerms, EntityHandleIter> Iterator - for ComponentAndEuidIter<'query, 'world, FieldTerms, EntityHandleIter> -where - FieldTerms: TermWithFieldTuple, - EntityHandleIter: Iterator<Item = EntityHandle<'query>>, - 'world: 'query, -{ - type Item = (Uid, FieldTerms::Fields<'query>); - - fn next(&mut self) -> Option<Self::Item> - { - let entity_handle = self.iter.next()?; - - Some(( - entity_handle.uid(), - FieldTerms::get_fields(&entity_handle, self.world), - )) - } -} - -macro_rules! impl_term_sequence { - ($c: tt) => { - seq!(I in 0..=$c { - impl<#(Term~I: TermWithoutField,)*> TermWithoutFieldTuple for (#(Term~I,)*) - { - fn apply_terms_to_builder<const MAX_TERM_CNT: usize>( - terms_builder: &mut TermsBuilder<MAX_TERM_CNT> - ) - { - #( - 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> - ) - { - #( - Term~I::apply_to_terms_builder(terms_builder); - )* - } - - fn get_fields<'component>( - entity_handle: &EntityHandle<'component>, - world: &'component World, - ) -> Self::Fields<'component> - { - (#(Term~I::get_field(entity_handle, world),)*) - } - } - }); - }; -} - -seq!(C in 0..=16 { - impl_term_sequence!(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> - { - } -} |
