summaryrefslogtreecommitdiff
path: root/engine-ecs/src/query.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine-ecs/src/query.rs')
-rw-r--r--engine-ecs/src/query.rs334
1 files changed, 190 insertions, 144 deletions
diff --git a/engine-ecs/src/query.rs b/engine-ecs/src/query.rs
index 8549411..10260f2 100644
--- a/engine-ecs/src/query.rs
+++ b/engine-ecs/src/query.rs
@@ -1,8 +1,8 @@
use std::any::type_name;
use std::marker::PhantomData;
-use seq_macro::seq;
use paste::paste;
+use seq_macro::seq;
use util_macros::sub;
use crate::component::{
@@ -11,13 +11,27 @@ use crate::component::{
HandleMut as ComponentHandleMut,
};
use crate::entity::Handle as EntityHandle;
+use crate::pair::Wildcard;
use crate::query::flexible::{Iter as FlexibleQueryIter, Query as FlexibleQuery};
use crate::system::{Metadata as SystemMetadata, Param as SystemParam};
-use crate::tuple::Tuple;
+use crate::tuple::{Concat, Tuple};
use crate::uid::Uid;
use crate::util::array_vec::ArrayVec;
use crate::util::Array;
-use crate::World;
+use crate::{pair, World};
+
+mod reexports
+{
+ pub use crate::component::storage::{
+ SearchTerms as Terms,
+ TermMetadata,
+ Traversal,
+ TraversalKind,
+ TraversalResult,
+ };
+}
+
+pub use reexports::*;
pub mod flexible;
pub mod term;
@@ -27,23 +41,20 @@ pub const MAX_TERM_CNT: usize = 17;
#[derive(Debug)]
pub struct Query<'world, TermsT>
-where
- TermsT: TermTuple<'world>,
{
inner: FlexibleQuery<'world, MAX_TERM_CNT>,
_pd: PhantomData<TermsT>,
}
impl<'world, TermsT> Query<'world, TermsT>
-where
- TermsT: TermTuple<'world>,
{
/// Iterates over the entities matching this query, the iterator item being the entity
/// components.
#[must_use]
- pub fn iter<'this>(
- &'this self,
- ) -> Iter<'this, 'world, TermsT, FlexibleQueryIter<'this, 'world>>
+ pub fn iter<'this>(&'this self) -> Iter<'this, TermsT>
+ where
+ TermsT: TermTuple<'this>,
+ 'world: 'this,
{
tracing::trace!("Searching for {}", std::any::type_name::<TermsT>());
@@ -57,44 +68,25 @@ where
/// 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<'this>(
- &'this self,
- ) -> ComponentAndEuidIter<'this, 'world, TermsT, FlexibleQueryIter<'this, 'world>>
- {
- tracing::trace!("Searching for {}", std::any::type_name::<TermsT>());
-
- 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<'this, OutIter>(
- &'this self,
- func: impl FnOnce(FlexibleQueryIter<'this, 'world>) -> OutIter,
- ) -> Iter<'this, 'world, TermsT, OutIter>
+ pub fn iter_with_euids<'this>(&'this self) -> ComponentAndEuidIter<'this, TermsT>
where
- OutIter: Iterator<Item = EntityHandle<'world>>,
+ TermsT: TermTuple<'this>,
+ 'world: 'this,
{
tracing::trace!("Searching for {}", std::any::type_name::<TermsT>());
- Iter {
+ ComponentAndEuidIter {
world: self.inner.world(),
- inner: func(self.inner.iter()),
+ inner: 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>
+ pub fn get_entity_uid<'this>(&'this self, entity_index: usize) -> Option<Uid>
+ where
+ TermsT: TermTuple<'this>,
{
Some(self.inner.iter().nth(entity_index)?.uid())
}
@@ -124,10 +116,12 @@ where
}
pub(crate) fn new(world: &'world World) -> Self
+ where
+ TermsT: TermTuple<'world>,
{
let mut terms_builder = Terms::builder();
- TermsT::apply_terms_to_builder(&mut terms_builder);
+ TermsT::apply_terms_to_builder(&mut terms_builder, 0);
Self {
inner: world.flexible_query(terms_builder.build()),
@@ -136,12 +130,12 @@ where
}
}
-impl<'query, 'world, TermsT> IntoIterator
- for &'query Query<'world, TermsT>
+impl<'query, 'world, TermsT> IntoIterator for &'query Query<'world, TermsT>
where
- TermsT: TermTuple<'world>,
+ TermsT: TermTuple<'query>,
+ 'world: 'query,
{
- type IntoIter = Iter<'query, 'world, TermsT, FlexibleQueryIter<'query, 'world>>;
+ type IntoIter = Iter<'query, TermsT>;
type Item = TermsT::Fields;
fn into_iter(self) -> Self::IntoIter
@@ -150,8 +144,7 @@ where
}
}
-impl<'world, TermsT> SystemParam<'world>
- for Query<'world, TermsT>
+impl<'world, TermsT> SystemParam<'world> for Query<'world, TermsT>
where
TermsT: TermTuple<'world>,
{
@@ -163,13 +156,6 @@ where
}
}
-#[derive(Debug)]
-pub struct Terms<const MAX_TERM_CNT: usize>
-{
- present: ArrayVec<Uid, MAX_TERM_CNT>,
- absent: ArrayVec<Uid, MAX_TERM_CNT>,
-}
-
impl<const MAX_TERM_CNT: usize> Terms<MAX_TERM_CNT>
{
pub fn builder() -> TermsBuilder<MAX_TERM_CNT>
@@ -180,30 +166,33 @@ impl<const MAX_TERM_CNT: usize> Terms<MAX_TERM_CNT>
#[derive(Debug, Default)]
#[must_use]
-pub struct TermsBuilder<const MAX_TERM_CNT: usize>
+pub struct TermsBuilder<const TERM_CAP: usize>
{
- present: ArrayVec<Uid, MAX_TERM_CNT>,
- absent: ArrayVec<Uid, MAX_TERM_CNT>,
+ present: ArrayVec<Uid, TERM_CAP>,
+ absent: ArrayVec<Uid, TERM_CAP>,
+ traverse: ArrayVec<Traversal<TERM_CAP>, TERM_CAP>,
}
#[allow(clippy::return_self_not_must_use)]
-pub trait TermsBuilderInterface
+pub trait TermsBuilderInterface<const TERM_CAP: usize>
{
fn present(self, ids: impl Array<Uid>) -> Self;
fn absent(self, ids: impl Array<Uid>) -> Self;
+
+ fn traverse(self, traversals: impl Array<Traversal<TERM_CAP>> + Clone) -> Self;
}
macro_rules! impl_terms_builder {
($($impl_content: tt)*) => {
- impl<const MAX_TERM_CNT: usize>
- TermsBuilderInterface for TermsBuilder<MAX_TERM_CNT>
+ impl<const TERM_CAP: usize>
+ TermsBuilderInterface<TERM_CAP> for TermsBuilder<TERM_CAP>
{
$($impl_content)*
}
- impl<const MAX_TERM_CNT: usize>
- TermsBuilderInterface for &mut TermsBuilder<MAX_TERM_CNT>
+ impl<const TERM_CAP: usize>
+ TermsBuilderInterface<TERM_CAP> for &mut TermsBuilder<TERM_CAP>
{
$($impl_content)*
}
@@ -274,6 +263,17 @@ impl_terms_builder! {
self
}
+
+ #[allow(unused_mut)]
+ fn traverse(mut self, traversals: impl Array<Traversal<TERM_CAP>> + Clone) -> Self
+ {
+ self.traverse.extend(traversals.clone());
+
+ self.present(
+ traversals
+ .map(|traversal| pair!({ traversal.relation }, Wildcard).id())
+ )
+ }
}
impl<const MAX_TERM_CNT: usize> TermsBuilder<MAX_TERM_CNT>
@@ -287,45 +287,49 @@ impl<const MAX_TERM_CNT: usize> TermsBuilder<MAX_TERM_CNT>
Terms {
present: self.present,
absent: self.absent,
+ traverse: self.traverse,
}
}
}
-pub trait Term<'world>
+pub trait Term<'query>
{
- type AddField<Fields: Tuple>;
+ type Fields: Tuple;
fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ term_metadata: TermMetadata,
);
- fn add_field<Fields: Tuple>(
- entity_handle: &EntityHandle<'world>,
- world: &'world World,
- fields: Fields,
- ) -> Self::AddField<Fields>;
+ fn fields(
+ world: &'query World,
+ search_result: &SearchResult<'query, '_>,
+ term_metadata: TermMetadata,
+ ) -> Self::Fields;
}
-impl<'world, ComponentT: Component> Term<'world> for &ComponentT
+impl<'query, ComponentT: Component> Term<'query> for &ComponentT
{
- type AddField<Fields: Tuple> = Fields::WithElementAtEnd<ComponentHandle<'world, ComponentT>>;
+ type Fields = (ComponentHandle<'query, ComponentT>,);
fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ _term_metadata: TermMetadata,
)
{
terms_builder.present([ComponentT::id()]);
}
- fn add_field<Fields: Tuple>(
- entity_handle: &EntityHandle<'world>,
- _world: &'world World,
- fields: Fields,
- ) -> Self::AddField<Fields>
+ fn fields(
+ _world: &'query World,
+ search_result: &SearchResult<'query, '_>,
+ _term_metadata: TermMetadata,
+ ) -> Self::Fields
{
assert!(!ComponentT::id().is_pair());
- let Some(component) = entity_handle
+ let Some(component) = search_result
+ .entity_handle
.get_matching_components(ComponentT::id())
.next()
else {
@@ -335,44 +339,47 @@ impl<'world, ComponentT: Component> Term<'world> for &ComponentT
"is most likely a bug in the entity querying"
),
type_name::<ComponentT>(),
- entity_handle.uid()
+ search_result.entity_handle.uid()
);
};
- let component = match ComponentHandle::<ComponentT>::from_entity_component_ref(&component) {
- Ok(component) => component,
- Err(err) => {
- panic!(
- "Creating handle to component {} failed: {err}",
- type_name::<ComponentT>()
- );
- }
- };
+ let component =
+ match ComponentHandle::<ComponentT>::from_entity_component_ref(&component) {
+ Ok(component) => component,
+ Err(err) => {
+ panic!(
+ "Creating handle to component {} failed: {err}",
+ type_name::<ComponentT>()
+ );
+ }
+ };
- fields.with_elem(component)
+ (component,)
}
}
-impl<'world, ComponentT: Component> Term<'world> for &mut ComponentT
+impl<'query, ComponentT: Component> Term<'query> for &mut ComponentT
{
- type AddField<Fields: Tuple> = Fields::WithElementAtEnd<ComponentHandleMut<'world, ComponentT>>;
+ type Fields = (ComponentHandleMut<'query, ComponentT>,);
fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ _term_metadata: TermMetadata,
)
{
terms_builder.present([ComponentT::id()]);
}
- fn add_field<Fields: Tuple>(
- entity_handle: &EntityHandle<'world>,
- world: &'world World,
- fields: Fields,
- ) -> Self::AddField<Fields>
+ fn fields(
+ world: &'query World,
+ search_result: &SearchResult<'query, '_>,
+ _term_metadata: TermMetadata,
+ ) -> Self::Fields
{
assert!(!ComponentT::id().is_pair());
- let Some(component) = entity_handle
+ let Some(component) = search_result
+ .entity_handle
.get_matching_components(ComponentT::id())
.next()
else {
@@ -382,11 +389,13 @@ impl<'world, ComponentT: Component> Term<'world> for &mut ComponentT
"is most likely a bug in the entity querying"
),
type_name::<ComponentT>(),
- entity_handle.uid()
+ search_result.entity_handle.uid()
);
};
- let component = match ComponentHandleMut::<ComponentT>::from_entity_component_ref(&component, world) {
+ let component = match ComponentHandleMut::<ComponentT>::from_entity_component_ref(
+ &component, world,
+ ) {
Ok(component) => component,
Err(err) => {
panic!(
@@ -396,57 +405,67 @@ impl<'world, ComponentT: Component> Term<'world> for &mut ComponentT
}
};
- fields.with_elem(component)
+ (component,)
}
}
-impl<'world, TermT, FieldAcc> TermFieldSource<'world, FieldAcc> for TermT
-where
- TermT: Term<'world>,
- TermT::AddField<FieldAcc>: Tuple,
- FieldAcc: Tuple
+impl<'query, TermT, FieldAcc> TermFieldSource<'query, FieldAcc> for TermT
+where
+ TermT: Term<'query, Fields: Concat<FieldAcc>>,
+ FieldAcc: Tuple,
{
- type NewFieldAcc = TermT::AddField<FieldAcc>;
+ type NewFieldAcc = <TermT::Fields as Concat<FieldAcc>>::Output;
fn collect_field(
- entity_handle: &EntityHandle<'world>,
- world: &'world World,
+ world: &'query World,
+ search_result: &SearchResult<'query, '_>,
+ term_metadata: TermMetadata,
fields: FieldAcc,
) -> Self::NewFieldAcc
{
- Self::add_field(entity_handle, world, fields)
+ <TermT::Fields as Concat<FieldAcc>>::concat(
+ Self::fields(world, search_result, term_metadata),
+ fields,
+ )
}
}
-pub trait TermTuple<'world>
+pub trait TermTuple<'query>
{
- type Fields;
+ type Fields: Tuple;
fn apply_terms_to_builder<const MAX_TERM_CNT: usize>(
terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ term_level: u32,
);
fn get_fields(
- entity_handle: &EntityHandle<'world>,
- world: &'world World,
+ world: &'query World,
+ search_result: &SearchResult<'query, '_>,
+ term_level: u32,
) -> Self::Fields;
}
-pub struct Iter<'query, 'world, TermsT, EntityHandleIter>
+#[derive(Debug)]
+#[non_exhaustive]
+pub struct SearchResult<'query, 'temp>
+{
+ pub entity_handle: EntityHandle<'query>,
+ pub traversal_results: &'temp [TraversalResult],
+}
+
+pub struct Iter<'query, TermsT>
where
- TermsT: TermTuple<'world>,
- EntityHandleIter: Iterator<Item = EntityHandle<'world>>,
+ TermsT: TermTuple<'query>,
{
- world: &'world World,
- inner: EntityHandleIter,
- comps_pd: PhantomData<(TermsT, &'query ())>,
+ world: &'query World,
+ inner: FlexibleQueryIter<'query, MAX_TERM_CNT>,
+ comps_pd: PhantomData<TermsT>,
}
-impl<'query, 'world, TermsT, EntityHandleIter> Iterator
- for Iter<'query, 'world, TermsT, EntityHandleIter>
+impl<'query, TermsT> Iterator for Iter<'query, TermsT>
where
- TermsT: TermTuple<'world>,
- EntityHandleIter: Iterator<Item = EntityHandle<'world>>,
+ TermsT: TermTuple<'query>,
{
type Item = TermsT::Fields;
@@ -454,46 +473,58 @@ where
{
let entity_handle = self.inner.next()?;
- Some(TermsT::get_fields(&entity_handle, self.world))
+ Some(TermsT::get_fields(
+ self.world,
+ &SearchResult {
+ entity_handle,
+ traversal_results: self.inner.traversal_results().unwrap(),
+ },
+ 0,
+ ))
}
}
-pub struct ComponentAndEuidIter<'query, 'world, TermsT, EntityHandleIter>
+pub struct ComponentAndEuidIter<'query, TermsT>
where
- TermsT: TermTuple<'world>,
- EntityHandleIter: Iterator<Item = EntityHandle<'world>>,
+ TermsT: TermTuple<'query>,
{
- world: &'world World,
- iter: EntityHandleIter,
- comps_pd: PhantomData<(TermsT, &'query ())>,
+ world: &'query World,
+ inner: FlexibleQueryIter<'query, MAX_TERM_CNT>,
+ comps_pd: PhantomData<TermsT>,
}
-impl<'query, 'world, TermsT, EntityHandleIter> Iterator
- for ComponentAndEuidIter<'query, 'world, TermsT, EntityHandleIter>
+impl<'query, TermsT> Iterator for ComponentAndEuidIter<'query, TermsT>
where
- TermsT: TermTuple<'world>,
- EntityHandleIter: Iterator<Item = EntityHandle<'world>>,
+ TermsT: TermTuple<'query>,
{
type Item = (Uid, TermsT::Fields);
fn next(&mut self) -> Option<Self::Item>
{
- let entity_handle = self.iter.next()?;
+ let entity_handle = self.inner.next()?;
Some((
entity_handle.uid(),
- TermsT::get_fields(&entity_handle, self.world),
+ TermsT::get_fields(
+ self.world,
+ &SearchResult {
+ entity_handle,
+ traversal_results: self.inner.traversal_results().unwrap(),
+ },
+ 0,
+ ),
))
}
}
-pub trait TermFieldSource<'world, FieldAcc>
+pub trait TermFieldSource<'query, FieldAcc>
{
type NewFieldAcc;
fn collect_field(
- entity_handle: &EntityHandle<'world>,
- world: &'world World,
+ world: &'query World,
+ search_result: &SearchResult<'query, '_>,
+ term_metadata: TermMetadata,
fields: FieldAcc,
) -> Self::NewFieldAcc;
}
@@ -513,11 +544,11 @@ macro_rules! term_field_source_new_field_acc {
macro_rules! gen_term_tuple_impls {
($c: tt) => {
seq!(I in 0..$c {
- impl<'world, #(Term~I,)*> TermTuple<'world> for (#(Term~I,)*)
+ impl<'query, #(Term~I,)*> TermTuple<'query> for (#(Term~I,)*)
where
#(
- Term~I: Term<'world> + TermFieldSource<
- 'world,
+ Term~I: Term<'query> + TermFieldSource<
+ 'query,
sub!(I - 1, term_field_source_new_field_acc),
NewFieldAcc: Tuple
>,
@@ -527,24 +558,40 @@ macro_rules! gen_term_tuple_impls {
#[allow(unused)]
fn apply_terms_to_builder<const MAX_TERM_CNT: usize>(
- terms_builder: &mut TermsBuilder<MAX_TERM_CNT>
+ terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ term_level: u32,
)
{
#(
- Term~I::apply_to_terms_builder(terms_builder);
+ Term~I::apply_to_terms_builder(
+ terms_builder,
+ TermMetadata {
+ level: term_level,
+ index: I
+ },
+ );
)*
}
#[allow(unused)]
fn get_fields(
- entity_handle: &EntityHandle<'world>,
- world: &'world World,
+ world: &'query World,
+ search_result: &SearchResult<'query, '_>,
+ term_level: u32,
) -> Self::Fields
{
let fields = ();
#(
- let fields = Term~I::collect_field(entity_handle, world, fields);
+ let fields = Term~I::collect_field(
+ world,
+ search_result,
+ TermMetadata {
+ level: term_level,
+ index: I
+ },
+ fields
+ );
)*
fields
@@ -557,4 +604,3 @@ macro_rules! gen_term_tuple_impls {
seq!(C in 0..17 {
gen_term_tuple_impls!(C);
});
-