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.rs298
1 files changed, 204 insertions, 94 deletions
diff --git a/ecs/src/query.rs b/ecs/src/query.rs
index 1889e00..ccb7add 100644
--- a/ecs/src/query.rs
+++ b/ecs/src/query.rs
@@ -1,18 +1,19 @@
use std::any::type_name;
-use std::borrow::Cow;
use std::marker::PhantomData;
use seq_macro::seq;
-use crate::component::{Component, FromLockedOptional, Ref as ComponentRef};
-use crate::query::flexible::{
- EntityHandle,
- Iter as FlexibleQueryIter,
- Query as FlexibleQuery,
+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::util::VecExt;
+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;
@@ -25,7 +26,8 @@ where
FieldlessTerms: TermWithoutFieldTuple,
{
world: &'world World,
- inner: FlexibleQuery<'world, 'static>,
+ // A term tuple type can have a maximum of 17 elements
+ inner: FlexibleQuery<'world, 17>,
_pd: PhantomData<(FieldTerms, FieldlessTerms)>,
}
@@ -39,11 +41,11 @@ where
#[must_use]
pub fn iter<'query>(
&'query self,
- ) -> ComponentIter<'query, 'world, FieldTerms, FlexibleQueryIter<'query>>
+ ) -> Iter<'query, 'world, FieldTerms, FlexibleQueryIter<'query>>
{
tracing::trace!("Searching for {}", std::any::type_name::<FieldTerms>());
- ComponentIter {
+ Iter {
world: self.world,
iter: self.inner.iter(),
comps_pd: PhantomData,
@@ -51,7 +53,7 @@ where
}
/// Iterates over the entities matching this query, the iterator item being the entity
- /// [`Uid`] and the entity components.
+ /// [`Uid`] and the matching entity components.
#[must_use]
pub fn iter_with_euids<'query>(
&'query self,
@@ -70,18 +72,18 @@ where
/// `func`.
///
/// This function exists so that a custom [`EntityHandle`] iterator can be given to
- /// [`ComponentIter`] without giving the user access to a reference to the [`World`].
+ /// [`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,
- ) -> ComponentIter<'query, 'world, FieldTerms, OutIter>
+ ) -> Iter<'query, 'world, FieldTerms, OutIter>
where
OutIter: Iterator<Item = EntityHandle<'query>>,
{
tracing::trace!("Searching for {}", std::any::type_name::<FieldTerms>());
- ComponentIter {
+ Iter {
world: self.world,
iter: func(self.inner.iter()),
comps_pd: PhantomData,
@@ -113,10 +115,10 @@ where
impl<'query, 'world, FieldTerms, FieldlessTerms> IntoIterator
for &'query Query<'world, FieldTerms, FieldlessTerms>
where
- FieldTerms: TermWithFieldTuple + 'world,
+ FieldTerms: TermWithFieldTuple,
FieldlessTerms: TermWithoutFieldTuple,
{
- type IntoIter = ComponentIter<'query, 'world, FieldTerms, FlexibleQueryIter<'query>>;
+ type IntoIter = Iter<'query, 'world, FieldTerms, FlexibleQueryIter<'query>>;
type Item = FieldTerms::Fields<'query>;
fn into_iter(self) -> Self::IntoIter
@@ -150,43 +152,51 @@ where
}
#[derive(Debug)]
-pub struct Terms<'a>
+pub struct Terms<const MAX_TERM_CNT: usize>
{
- required_components: Cow<'a, [Uid]>,
- excluded_components: Cow<'a, [Uid]>,
+ required_components: ArrayVec<Uid, MAX_TERM_CNT>,
+ excluded_components: ArrayVec<Uid, MAX_TERM_CNT>,
}
-impl<'a> Terms<'a>
+impl<const MAX_TERM_CNT: usize> Terms<MAX_TERM_CNT>
{
- pub fn builder() -> TermsBuilder<'a>
+ pub fn builder() -> TermsBuilder<MAX_TERM_CNT>
{
TermsBuilder::default()
}
}
#[derive(Debug, Default)]
-pub struct TermsBuilder<'a>
+#[must_use]
+pub struct TermsBuilder<const MAX_TERM_CNT: usize>
{
- required_components: Cow<'a, [Uid]>,
- excluded_components: Cow<'a, [Uid]>,
+ required_components: ArrayVec<Uid, MAX_TERM_CNT>,
+ excluded_components: ArrayVec<Uid, MAX_TERM_CNT>,
}
-pub trait TermsBuilderInterface<'a>
+#[allow(clippy::return_self_not_must_use)]
+pub trait TermsBuilderInterface
{
- fn with<ComponentT: Component>(self) -> Self;
+ fn with<WithUidT: WithUid>(self) -> Self;
+
+ fn without<WithUidT: WithUid>(self) -> Self;
- fn without<ComponentT: Component>(self) -> Self;
+ fn with_required(self, ids: impl Array<Uid>) -> Self;
- fn with_required_ids(self, ids: &'a mut [Uid]) -> Self;
+ fn without_ids(self, ids: impl Array<Uid>) -> Self;
}
macro_rules! impl_terms_builder {
($($impl_content: tt)*) => {
- impl<'a> TermsBuilderInterface<'a> for TermsBuilder<'a> {
+ impl<const MAX_TERM_CNT: usize>
+ TermsBuilderInterface for TermsBuilder<MAX_TERM_CNT>
+ {
$($impl_content)*
}
- impl<'a> TermsBuilderInterface<'a> for &mut TermsBuilder<'a> {
+ impl<const MAX_TERM_CNT: usize>
+ TermsBuilderInterface for &mut TermsBuilder<MAX_TERM_CNT>
+ {
$($impl_content)*
}
};
@@ -194,74 +204,101 @@ 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 <= WithUidT::uid());
self.required_components
- .to_mut()
- .insert_at_partition_point_by_key(ComponentT::id(), |id| *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 <= WithUidT::uid());
self.excluded_components
- .to_mut()
- .insert_at_partition_point_by_key(ComponentT::id(), |id| *id);
+ .insert(insert_index, WithUidT::uid());
self
}
#[allow(unused_mut)]
- fn with_required_ids(mut self, ids: &'a mut [Uid]) -> Self
+ fn with_required(mut self, mut ids: impl Array<Uid>) -> Self
{
- if ids.is_empty() {
+ if !ids.as_ref().is_sorted() {
+ ids.as_mut().sort();
+ }
+
+ if self.required_components.is_empty() {
+ self.required_components.extend(ids);
return self;
}
- if !ids.is_sorted() {
- ids.sort();
+ 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);
+
}
- if self.required_components.is_empty() {
- self.required_components = Cow::Borrowed(ids);
+ 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 first_id_pp_index = self.required_components.partition_point(|req_comp_id| {
- req_comp_id <= ids.first().expect("Cannot happend since not empty")
- });
+ let mut id_iter = ids.into_iter();
- let removed = self
- .required_components
- .to_mut()
- .splice(first_id_pp_index..first_id_pp_index, ids.iter().copied());
+ while let Some(id) = id_iter.next() {
+ let insert_index = self.excluded_components
+ .partition_point(|other_id| *other_id <= id);
- assert_eq!(removed.count(), 0);
+ 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<'a> TermsBuilder<'a>
+impl<const MAX_TERM_CNT: usize> TermsBuilder<MAX_TERM_CNT>
{
- pub fn build(self) -> Terms<'a>
+ #[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,
@@ -272,14 +309,18 @@ impl<'a> TermsBuilder<'a>
pub trait TermWithoutField
{
- fn apply_to_terms_builder(terms_builder: &mut TermsBuilder<'_>);
+ 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(terms_builder: &mut TermsBuilder<'_>);
+ 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>,
@@ -287,30 +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(terms_builder: &mut TermsBuilder<'_>)
+ 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!(
- "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>()
+ );
+ })
+ }
+}
+
+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).unwrap_or_else(|err| {
+ panic!(
+ "Creating handle to component {} failed: {err}",
+ type_name::<ComponentT>()
);
})
}
@@ -318,14 +412,18 @@ impl<ComponentRefT: ComponentRef> TermWithField for ComponentRefT
pub trait TermWithoutFieldTuple
{
- fn apply_terms_to_builder(terms_builder: &mut TermsBuilder<'_>);
+ 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(terms_builder: &mut TermsBuilder<'_>);
+ 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>,
@@ -333,9 +431,9 @@ pub trait TermWithFieldTuple
) -> Self::Fields<'component>;
}
-pub struct ComponentIter<'query, 'world, FieldTerms, EntityHandleIter>
+pub struct Iter<'query, 'world, FieldTerms, EntityHandleIter>
where
- FieldTerms: TermWithFieldTuple + 'world,
+ FieldTerms: TermWithFieldTuple,
EntityHandleIter: Iterator<Item = EntityHandle<'query>>,
{
world: &'world World,
@@ -344,9 +442,9 @@ where
}
impl<'query, 'world, FieldTerms, EntityHandleIter>
- ComponentIter<'query, 'world, FieldTerms, EntityHandleIter>
+ Iter<'query, 'world, FieldTerms, EntityHandleIter>
where
- FieldTerms: TermWithFieldTuple + 'world,
+ FieldTerms: TermWithFieldTuple,
EntityHandleIter: Iterator<Item = EntityHandle<'query>>,
'world: 'query,
{
@@ -363,9 +461,9 @@ where
}
impl<'query, 'world, FieldTerms, EntityHandleIter> Iterator
- for ComponentIter<'query, 'world, FieldTerms, EntityHandleIter>
+ for Iter<'query, 'world, FieldTerms, EntityHandleIter>
where
- FieldTerms: TermWithFieldTuple + 'world,
+ FieldTerms: TermWithFieldTuple,
EntityHandleIter: Iterator<Item = EntityHandle<'query>>,
'world: 'query,
{
@@ -381,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,
@@ -392,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,
{
@@ -414,7 +512,9 @@ macro_rules! impl_term_sequence {
seq!(I in 0..=$c {
impl<#(Term~I: TermWithoutField,)*> TermWithoutFieldTuple for (#(Term~I,)*)
{
- fn apply_terms_to_builder(terms_builder: &mut TermsBuilder<'_>)
+ 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);
@@ -426,7 +526,9 @@ macro_rules! impl_term_sequence {
{
type Fields<'component> = (#(Term~I::Field<'component>,)*);
- fn apply_terms_to_builder(terms_builder: &mut TermsBuilder<'_>)
+ 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);
@@ -451,14 +553,22 @@ seq!(C in 0..=16 {
impl TermWithoutFieldTuple for ()
{
- fn apply_terms_to_builder(_terms_builder: &mut TermsBuilder<'_>) {}
+ 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(_terms_builder: &mut TermsBuilder<'_>) {}
+ fn apply_terms_to_builder<const MAX_TERM_CNT: usize>(
+ _terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ )
+ {
+ }
fn get_fields<'component>(
_entity_handle: &EntityHandle<'_>,