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