summaryrefslogtreecommitdiff
path: root/ecs/src/query
diff options
context:
space:
mode:
Diffstat (limited to 'ecs/src/query')
-rw-r--r--ecs/src/query/flexible.rs137
-rw-r--r--ecs/src/query/options.rs59
-rw-r--r--ecs/src/query/term.rs115
3 files changed, 153 insertions, 158 deletions
diff --git a/ecs/src/query/flexible.rs b/ecs/src/query/flexible.rs
index 5c23e68..add30b0 100644
--- a/ecs/src/query/flexible.rs
+++ b/ecs/src/query/flexible.rs
@@ -1,145 +1,84 @@
//! Low-level querying.
-use std::iter::{repeat_n, Filter, Flatten, Map, RepeatN, Zip};
+use std::iter::{repeat_n, FlatMap, RepeatN, Zip};
-use crate::component::storage::{
- Archetype,
- ArchetypeEntity,
- ArchetypeRefIter,
- EntityIter,
- Storage as ComponentStorage,
-};
-use crate::component::{
- Metadata as ComponentMetadata,
- RefSequence as ComponentRefSequence,
-};
-use crate::lock::ReadGuard;
-use crate::query::options::Options;
-use crate::query::ComponentIter;
-use crate::uid::Uid;
-use crate::util::Sortable;
-use crate::{EntityComponent, World};
+use crate::component::storage::archetype::{Archetype, EntityIter};
+use crate::component::storage::{ArchetypeRefIter, ArchetypeSearchTerms};
+use crate::entity::Handle as EntityHandle;
+use crate::query::Terms;
+use crate::World;
/// Low-level entity query structure.
#[derive(Debug)]
-pub struct Query<'world, CompMetadata>
-where
- CompMetadata: Sortable<Item = ComponentMetadata> + AsRef<[ComponentMetadata]>,
+pub struct Query<'world, const MAX_TERM_CNT: usize>
{
- component_storage: ReadGuard<'world, ComponentStorage>,
- comp_metadata: CompMetadata,
+ world: &'world World,
+ terms: Terms<MAX_TERM_CNT>,
}
-impl<'world, CompMetadata> Query<'world, CompMetadata>
-where
- CompMetadata: Sortable<Item = ComponentMetadata> + AsRef<[ComponentMetadata]>,
+impl<'world, const MAX_TERM_CNT: usize> Query<'world, MAX_TERM_CNT>
{
/// Iterates over the entities matching this query.
#[must_use]
- pub fn iter<'query, OptionsT: Options>(&'query self) -> Iter<'query>
+ pub fn iter(&self) -> Iter<'_>
{
Iter {
iter: self
+ .world
+ .data
.component_storage
- .iter_archetypes_with_comps(&self.comp_metadata)
- .map(
+ .search_archetypes(ArchetypeSearchTerms {
+ required_components: &self.terms.required_components,
+ excluded_components: &self.terms.excluded_components,
+ })
+ .flat_map(
(|archetype| {
repeat_n(archetype, archetype.entity_cnt())
.zip(archetype.entities())
}) as ComponentIterMapFn,
- )
- .flatten()
- .filter(|(_, entity)| OptionsT::entity_filter(entity.components())),
+ ),
}
}
- pub(crate) fn new(world: &'world World, mut comp_metadata: CompMetadata) -> Self
- {
- comp_metadata.sort_by_key_b(|metadata| metadata.id);
-
- Self {
- component_storage: world
- .data
- .component_storage
- .read_nonblock()
- .expect("Failed to acquire read-only component storage lock"),
- comp_metadata,
- }
- }
-}
-
-pub struct Iter<'query>
-{
- iter: QueryEntityIter<'query>,
-}
-
-impl<'query> Iter<'query>
-{
- /// Converts this iterator into a [`ComponentIter`].
- ///
- /// Note: The matching entities of this iterator should have all of the non-[`Option`]
- /// components in `Comps`, otherwise iterating the [`ComponentIter`] will cause a
- /// panic.
- #[must_use]
- #[inline]
- pub fn into_component_iter<'world, Comps>(
- self,
- world: &'world World,
- ) -> ComponentIter<'query, 'world, Comps, Self>
- where
- Comps: ComponentRefSequence + 'world,
- 'world: 'query,
+ pub(crate) fn new(world: &'world World, terms: Terms<MAX_TERM_CNT>) -> Self
{
- ComponentIter::new(world, self)
+ Self { world, terms }
}
}
-impl<'query> Iterator for Iter<'query>
+impl<'query, const MAX_TERM_CNT: usize> IntoIterator for &'query Query<'_, MAX_TERM_CNT>
{
+ type IntoIter = Iter<'query>;
type Item = EntityHandle<'query>;
- fn next(&mut self) -> Option<Self::Item>
+ fn into_iter(self) -> Self::IntoIter
{
- let (archetype, entity) = self.iter.next()?;
-
- Some(EntityHandle { archetype, entity })
+ self.iter()
}
}
-pub struct EntityHandle<'query>
+pub struct Iter<'query>
{
- archetype: &'query Archetype,
- entity: &'query ArchetypeEntity,
+ iter: QueryEntityIter<'query>,
}
-impl<'query> EntityHandle<'query>
+impl<'query> Iterator for Iter<'query>
{
- /// Returns the [`Uid`] of this entity.
- #[inline]
- pub fn uid(&self) -> Uid
- {
- self.entity.uid()
- }
+ type Item = EntityHandle<'query>;
- #[inline]
- pub fn components(&self) -> &'query [EntityComponent]
+ fn next(&mut self) -> Option<Self::Item>
{
- self.entity.components()
- }
+ let (archetype, entity) = self.iter.next()?;
- #[inline]
- pub fn get_component_index(&self, component_uid: Uid) -> Option<usize>
- {
- self.archetype.get_index_for_component(component_uid)
+ Some(EntityHandle::new(archetype, entity))
}
}
-type ComponentIterMapFn =
- for<'a> fn(&'a Archetype) -> Zip<RepeatN<&'a Archetype>, EntityIter<'a>>;
+type ComponentIterMapFnOutput<'a> = Zip<RepeatN<&'a Archetype>, EntityIter<'a>>;
-type ComponentIterFilterFn =
- for<'a, 'b> fn(&'a (&'b Archetype, &'b ArchetypeEntity)) -> bool;
+type ComponentIterMapFn = for<'a> fn(&'a Archetype) -> ComponentIterMapFnOutput<'a>;
-type QueryEntityIter<'query> = Filter<
- Flatten<Map<ArchetypeRefIter<'query>, ComponentIterMapFn>>,
- ComponentIterFilterFn,
+type QueryEntityIter<'query> = FlatMap<
+ ArchetypeRefIter<'query, 'query>,
+ ComponentIterMapFnOutput<'query>,
+ ComponentIterMapFn,
>;
diff --git a/ecs/src/query/options.rs b/ecs/src/query/options.rs
deleted file mode 100644
index 772d091..0000000
--- a/ecs/src/query/options.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-use std::marker::PhantomData;
-
-use hashbrown::HashSet;
-
-use crate::component::Component;
-use crate::EntityComponent;
-
-/// Query options.
-pub trait Options
-{
- fn entity_filter<'component>(components: &'component [EntityComponent]) -> bool;
-}
-
-impl Options for ()
-{
- fn entity_filter<'component>(_components: &'component [EntityComponent]) -> bool
- {
- true
- }
-}
-
-pub struct With<ComponentT>
-where
- ComponentT: Component,
-{
- _pd: PhantomData<ComponentT>,
-}
-
-impl<ComponentT> Options for With<ComponentT>
-where
- ComponentT: Component,
-{
- fn entity_filter<'component>(components: &'component [EntityComponent]) -> bool
- {
- let ids_set = components
- .into_iter()
- .map(|component| component.id)
- .collect::<HashSet<_>>();
-
- ids_set.contains(&ComponentT::id())
- }
-}
-
-pub struct Not<OptionsT>
-where
- OptionsT: Options,
-{
- _pd: PhantomData<OptionsT>,
-}
-
-impl<OptionsT> Options for Not<OptionsT>
-where
- OptionsT: Options,
-{
- fn entity_filter<'component>(components: &'component [EntityComponent]) -> bool
- {
- !OptionsT::entity_filter(components)
- }
-}
diff --git a/ecs/src/query/term.rs b/ecs/src/query/term.rs
new file mode 100644
index 0000000..9c772da
--- /dev/null
+++ b/ecs/src/query/term.rs
@@ -0,0 +1,115 @@
+use std::any::type_name;
+use std::marker::PhantomData;
+
+use crate::component::{
+ Component,
+ Handle as ComponentHandle,
+ HandleMut as ComponentHandleMut,
+};
+use crate::query::{
+ TermWithField,
+ TermWithoutField,
+ TermsBuilder,
+ TermsBuilderInterface,
+};
+use crate::uid::With as WithUid;
+
+pub struct With<WithUidT>
+where
+ WithUidT: WithUid,
+{
+ _pd: PhantomData<WithUidT>,
+}
+
+impl<WithUidT> TermWithoutField for With<WithUidT>
+where
+ WithUidT: WithUid,
+{
+ fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
+ terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ )
+ {
+ terms_builder.with::<WithUidT>();
+ }
+}
+
+pub struct Without<WithUidT>
+where
+ WithUidT: WithUid,
+{
+ _pd: PhantomData<WithUidT>,
+}
+
+impl<WithUidT> TermWithoutField for Without<WithUidT>
+where
+ WithUidT: WithUid,
+{
+ fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
+ terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ )
+ {
+ terms_builder.without::<WithUidT>();
+ }
+}
+
+impl<ComponentT: Component> TermWithField for Option<&ComponentT>
+{
+ type Field<'a> = Option<ComponentHandle<'a, ComponentT>>;
+
+ fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
+ _terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ )
+ {
+ }
+
+ fn get_field<'world>(
+ entity_handle: &crate::entity::Handle<'world>,
+ _world: &'world crate::World,
+ ) -> Self::Field<'world>
+ {
+ Some(
+ ComponentHandle::<'world, ComponentT>::from_entity_component_ref(
+ entity_handle
+ .get_matching_components(ComponentT::id())
+ .next()?,
+ )
+ .unwrap_or_else(|err| {
+ panic!(
+ "Creating handle to component {} failed: {err}",
+ type_name::<ComponentT>()
+ );
+ }),
+ )
+ }
+}
+
+impl<ComponentT: Component> TermWithField for Option<&mut ComponentT>
+{
+ type Field<'a> = Option<ComponentHandleMut<'a, ComponentT>>;
+
+ fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
+ _terms_builder: &mut TermsBuilder<MAX_TERM_CNT>,
+ )
+ {
+ }
+
+ fn get_field<'world>(
+ entity_handle: &crate::entity::Handle<'world>,
+ _world: &'world crate::World,
+ ) -> Self::Field<'world>
+ {
+ Some(
+ ComponentHandleMut::<'world, ComponentT>::from_entity_component_ref(
+ entity_handle
+ .get_matching_components(ComponentT::id())
+ .next()?,
+ )
+ .unwrap_or_else(|err| {
+ panic!(
+ "Creating handle to component {} failed: {err}",
+ type_name::<ComponentT>()
+ );
+ }),
+ )
+ }
+}