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.rs167
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,
{