diff options
Diffstat (limited to 'ecs/src/query')
-rw-r--r-- | ecs/src/query/flexible.rs | 137 | ||||
-rw-r--r-- | ecs/src/query/options.rs | 59 | ||||
-rw-r--r-- | ecs/src/query/term.rs | 115 |
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>() + ); + }), + ) + } +} |