diff options
Diffstat (limited to 'ecs/src/query.rs')
-rw-r--r-- | ecs/src/query.rs | 167 |
1 files changed, 124 insertions, 43 deletions
diff --git a/ecs/src/query.rs b/ecs/src/query.rs index b29db3d..ccb7add 100644 --- a/ecs/src/query.rs +++ b/ecs/src/query.rs @@ -3,11 +3,15 @@ use std::marker::PhantomData; use seq_macro::seq; -use crate::component::{Component, FromLockedOptional, Ref as ComponentRef}; +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::{Param as SystemParam, System}; -use crate::uid::Uid; +use crate::uid::{Kind as UidKind, Uid, With as WithUid}; use crate::util::array_vec::ArrayVec; use crate::util::Array; use crate::World; @@ -111,7 +115,7 @@ where impl<'query, 'world, FieldTerms, FieldlessTerms> IntoIterator for &'query Query<'world, FieldTerms, FieldlessTerms> where - FieldTerms: TermWithFieldTuple + 'world, + FieldTerms: TermWithFieldTuple, FieldlessTerms: TermWithoutFieldTuple, { type IntoIter = Iter<'query, 'world, FieldTerms, FlexibleQueryIter<'query>>; @@ -163,19 +167,23 @@ impl<const MAX_TERM_CNT: usize> Terms<MAX_TERM_CNT> } #[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<ComponentT: Component>(self) -> Self; + fn with<WithUidT: WithUid>(self) -> Self; - fn without<ComponentT: Component>(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 { @@ -196,36 +204,25 @@ macro_rules! impl_terms_builder { impl_terms_builder! { #[allow(unused_mut)] - fn with<ComponentT: Component>(mut self) -> Self + fn with<WithUidT: WithUid>(mut self) -> Self { - if ComponentT::is_optional() { - return self; - } - let insert_index = self.required_components - .partition_point(|id| *id <= ComponentT::id()); + .partition_point(|id| *id <= WithUidT::uid()); self.required_components - .insert(insert_index, ComponentT::id()); + .insert(insert_index, WithUidT::uid()); self } #[allow(unused_mut)] - fn without<ComponentT: Component>(mut self) -> Self + fn without<WithUidT: WithUid>(mut self) -> Self { - if ComponentT::is_optional() { - panic!( - "{}::without cannot take optional component", - type_name::<Self>() - ); - } - let insert_index = self.excluded_components - .partition_point(|id| *id <= ComponentT::id()); + .partition_point(|id| *id <= WithUidT::uid()); self.excluded_components - .insert(insert_index, ComponentT::id()); + .insert(insert_index, WithUidT::uid()); self } @@ -237,7 +234,7 @@ impl_terms_builder! { ids.as_mut().sort(); } - if self.required_components.len() == 0 { + if self.required_components.is_empty() { self.required_components.extend(ids); return self; } @@ -261,14 +258,47 @@ impl_terms_builder! { 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> { - assert!(self.required_components.is_sorted()); - assert!(self.excluded_components.is_sorted()); + debug_assert!(self.required_components.is_sorted()); + debug_assert!(self.excluded_components.is_sorted()); Terms { required_components: self.required_components, @@ -298,32 +328,83 @@ pub trait TermWithField ) -> Self::Field<'world>; } -impl<ComponentRefT: ComponentRef> TermWithField for ComponentRefT +impl<ComponentT: Component> TermWithField for &ComponentT { - type Field<'a> = ComponentRefT::Handle<'a>; + 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::<ComponentRefT::Component>(); + terms_builder.with::<ComponentT>(); } fn get_field<'world>( entity_handle: &EntityHandle<'world>, - world: &'world World, + _world: &'world World, ) -> Self::Field<'world> { - Self::Field::from_locked_optional_component( - entity_handle - .get_component(ComponentRefT::Component::id()) - .map(|component| component.component()), - world, - ) - .unwrap_or_else(|err| { + 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!( - "Taking component {} lock failed: {err}", - type_name::<ComponentRefT::Component>() + 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>() ); }) } @@ -352,7 +433,7 @@ pub trait TermWithFieldTuple pub struct Iter<'query, 'world, FieldTerms, EntityHandleIter> where - FieldTerms: TermWithFieldTuple + 'world, + FieldTerms: TermWithFieldTuple, EntityHandleIter: Iterator<Item = EntityHandle<'query>>, { world: &'world World, @@ -363,7 +444,7 @@ where impl<'query, 'world, FieldTerms, EntityHandleIter> Iter<'query, 'world, FieldTerms, EntityHandleIter> where - FieldTerms: TermWithFieldTuple + 'world, + FieldTerms: TermWithFieldTuple, EntityHandleIter: Iterator<Item = EntityHandle<'query>>, 'world: 'query, { @@ -382,7 +463,7 @@ where impl<'query, 'world, FieldTerms, EntityHandleIter> Iterator for Iter<'query, 'world, FieldTerms, EntityHandleIter> where - FieldTerms: TermWithFieldTuple + 'world, + FieldTerms: TermWithFieldTuple, EntityHandleIter: Iterator<Item = EntityHandle<'query>>, 'world: 'query, { @@ -398,7 +479,7 @@ where pub struct ComponentAndEuidIter<'query, 'world, FieldTerms, EntityHandleIter> where - FieldTerms: TermWithFieldTuple + 'world, + FieldTerms: TermWithFieldTuple, EntityHandleIter: Iterator<Item = EntityHandle<'query>>, { world: &'world World, @@ -409,7 +490,7 @@ where impl<'query, 'world, FieldTerms, EntityHandleIter> Iterator for ComponentAndEuidIter<'query, 'world, FieldTerms, EntityHandleIter> where - FieldTerms: TermWithFieldTuple + 'world, + FieldTerms: TermWithFieldTuple, EntityHandleIter: Iterator<Item = EntityHandle<'query>>, 'world: 'query, { |