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.rs237
1 files changed, 154 insertions, 83 deletions
diff --git a/ecs/src/query.rs b/ecs/src/query.rs
index b29db3d..5f13579 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::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;
@@ -15,15 +19,16 @@ 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,
{
- world: &'world World,
- // A term tuple type can have a maximum of 17 elements
- inner: FlexibleQuery<'world, 17>,
+ inner: FlexibleQuery<'world, MAX_TERM_CNT>,
_pd: PhantomData<(FieldTerms, FieldlessTerms)>,
}
@@ -42,8 +47,8 @@ where
tracing::trace!("Searching for {}", std::any::type_name::<FieldTerms>());
Iter {
- world: self.world,
- iter: self.inner.iter(),
+ world: self.inner.world(),
+ inner: self.inner.iter(),
comps_pd: PhantomData,
}
}
@@ -58,7 +63,7 @@ where
tracing::trace!("Searching for {}", std::any::type_name::<FieldTerms>());
ComponentAndEuidIter {
- world: self.world,
+ world: self.inner.world(),
iter: self.inner.iter(),
comps_pd: PhantomData,
}
@@ -80,8 +85,8 @@ where
tracing::trace!("Searching for {}", std::any::type_name::<FieldTerms>());
Iter {
- world: self.world,
- iter: func(self.inner.iter()),
+ world: self.inner.world(),
+ inner: func(self.inner.iter()),
comps_pd: PhantomData,
}
}
@@ -93,6 +98,25 @@ where
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();
@@ -101,7 +125,6 @@ where
FieldlessTerms::apply_terms_to_builder(&mut terms_builder);
Self {
- world,
inner: world.flexible_query(terms_builder.build()),
_pd: PhantomData,
}
@@ -111,7 +134,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>>;
@@ -131,17 +154,7 @@ where
{
type Input = ();
- fn initialize<SystemImpl>(
- _system: &mut impl System<'world, SystemImpl>,
- _input: Self::Input,
- )
- {
- }
-
- fn new<SystemImpl>(
- _system: &'world impl System<'world, SystemImpl>,
- world: &'world World,
- ) -> Self
+ fn new(world: &'world World, _system_metadata: &SystemMetadata) -> Self
{
Self::new(world)
}
@@ -163,19 +176,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 +213,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 +243,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 +267,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,15 +337,56 @@ 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,
+ ) -> 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>(
@@ -314,16 +394,26 @@ impl<ComponentRefT: ComponentRef> TermWithField for ComponentRefT
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, world).unwrap_or_else(|err| {
panic!(
- "Taking component {} lock failed: {err}",
- type_name::<ComponentRefT::Component>()
+ "Creating handle to component {} failed: {err}",
+ type_name::<ComponentT>()
);
})
}
@@ -352,37 +442,18 @@ pub trait TermWithFieldTuple
pub struct Iter<'query, 'world, FieldTerms, EntityHandleIter>
where
- FieldTerms: TermWithFieldTuple + 'world,
+ FieldTerms: TermWithFieldTuple,
EntityHandleIter: Iterator<Item = EntityHandle<'query>>,
{
world: &'world World,
- iter: EntityHandleIter,
+ inner: EntityHandleIter,
comps_pd: PhantomData<FieldTerms>,
}
-impl<'query, 'world, FieldTerms, EntityHandleIter>
- Iter<'query, 'world, FieldTerms, EntityHandleIter>
-where
- FieldTerms: TermWithFieldTuple + 'world,
- EntityHandleIter: Iterator<Item = EntityHandle<'query>>,
- 'world: 'query,
-{
- /// Creates a new iterator from the given entity handle iterator.
- ///
- /// # Important
- /// All of the yielded entities of the entity handle iterator should match the
- /// terms `Terms`. The [`Self::next`] function will panic if it encounters a
- /// entity that does not match the terms `Terms`.
- pub fn new(world: &'world World, iter: EntityHandleIter) -> Self
- {
- Self { world, iter, comps_pd: PhantomData }
- }
-}
-
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,
{
@@ -390,7 +461,7 @@ where
fn next(&mut self) -> Option<Self::Item>
{
- let entity_handle = self.iter.next()?;
+ let entity_handle = self.inner.next()?;
Some(FieldTerms::get_fields(&entity_handle, self.world))
}
@@ -398,7 +469,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 +480,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,
{