diff options
author | HampusM <hampus@hampusmat.com> | 2025-03-18 16:59:53 +0100 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2025-03-19 20:24:12 +0100 |
commit | 76e7e612e7b516bf52b508ae5bb367b1ddc3babc (patch) | |
tree | 1975b4db0eecb74583ab78e58afa50b5326347b2 | |
parent | 44cd47fd67102902b649c98b85c5abb9a0da39f8 (diff) |
refactor(ecs): replace component::RefSequence with query terms
-rw-r--r-- | ecs/src/component.rs | 75 | ||||
-rw-r--r-- | ecs/src/component/storage.rs | 75 | ||||
-rw-r--r-- | ecs/src/lib.rs | 50 | ||||
-rw-r--r-- | ecs/src/query.rs | 295 | ||||
-rw-r--r-- | ecs/src/query/flexible.rs | 46 | ||||
-rw-r--r-- | ecs/tests/query.rs | 9 |
6 files changed, 314 insertions, 236 deletions
diff --git a/ecs/src/component.rs b/ecs/src/component.rs index 9257c41..265eb9e 100644 --- a/ecs/src/component.rs +++ b/ecs/src/component.rs @@ -13,7 +13,7 @@ use crate::system::Input as SystemInput; use crate::type_name::TypeName; use crate::uid::Uid; use crate::util::Array; -use crate::{EntityComponent, World}; +use crate::World; pub mod local; @@ -170,22 +170,6 @@ pub trait Sequence fn removed_event_ids() -> Vec<Uid>; } -/// A sequence of references (immutable or mutable) to components. -pub trait RefSequence -{ - type Handles<'component>; - - type Metadata: Array<Metadata>; - - fn metadata() -> Self::Metadata; - - fn from_components<'component>( - components: &'component [EntityComponent], - component_index_lookup: impl Fn(Uid) -> Option<usize>, - world: &'component World, - ) -> Self::Handles<'component>; -} - /// A mutable or immutable reference to a component. pub trait Ref { @@ -317,44 +301,6 @@ macro_rules! inner { ] } } - - impl<#(CompRef~I: Ref,)*> RefSequence for (#(CompRef~I,)*) - { - type Handles<'component> = (#(CompRef~I::Handle<'component>,)*); - - type Metadata = [Metadata; $c + 1]; - - fn metadata() -> Self::Metadata - { - [#( - Metadata { - id: CompRef~I::Component::id(), - is_optional: CompRef~I::Component::is_optional(), - }, - )*] - } - - fn from_components<'component>( - components: &'component [EntityComponent], - component_index_lookup: impl Fn(Uid) -> Option<usize>, - world: &'component World, - ) -> Self::Handles<'component> - { - (#( - CompRef~I::Handle::from_locked_optional_component( - component_index_lookup(CompRef~I::Component::id()) - .and_then(|component_index| components.get(component_index)) - .map(|component| &component.component), - world, - ).unwrap_or_else(|err| { - panic!( - "Taking component {} lock failed: {err}", - type_name::<CompRef~I::Component>() - ); - }), - )*) - } - } }); }; } @@ -390,25 +336,6 @@ impl Sequence for () } } -impl RefSequence for () -{ - type Handles<'component> = (); - type Metadata = [Metadata; 0]; - - fn metadata() -> Self::Metadata - { - [] - } - - fn from_components<'component>( - _components: &'component [EntityComponent], - _component_index_lookup: impl Fn(Uid) -> Option<usize>, - _world: &'component World, - ) -> Self::Handles<'component> - { - } -} - pub trait Into { type Component; diff --git a/ecs/src/component/storage.rs b/ecs/src/component/storage.rs index 5b7b101..21f9a37 100644 --- a/ecs/src/component/storage.rs +++ b/ecs/src/component/storage.rs @@ -16,7 +16,7 @@ use crate::component::storage::graph::{ ArchetypeEdges, Graph, }; -use crate::component::{Component, Metadata as ComponentMetadata}; +use crate::component::Component; use crate::type_name::TypeName; use crate::uid::{Kind as UidKind, Uid}; use crate::util::{BorrowedOrOwned, Either, StreamingIterator, VecExt}; @@ -36,12 +36,9 @@ pub struct Storage impl Storage { - pub fn search_archetypes( - &self, - component_metadata: &[ComponentMetadata], - ) -> ArchetypeRefIter<'_> + pub fn search_archetypes(&self, component_ids: &[Uid]) -> ArchetypeRefIter<'_> { - let archetype_id = ArchetypeId::from_components_metadata(component_metadata); + let archetype_id = ArchetypeId::new(&component_ids); let Some(add_edge_recursive_iter) = self.graph.dfs_archetype_add_edges(archetype_id) @@ -50,19 +47,10 @@ impl Storage .borrow_mut() .push(ImaginaryArchetype { id: archetype_id, - component_ids: component_metadata - .iter() - .filter_map(|comp_metadata| { - if comp_metadata.is_optional { - return None; - } - - Some(comp_metadata.id) - }) - .collect::<Vec<_>>(), + component_ids: component_ids.to_vec(), }); - let found_archetypes = self.find_all_archetype_with_comps(component_metadata); + let found_archetypes = self.find_all_archetype_with_comps(component_ids); return ArchetypeRefIter { storage: self, @@ -333,16 +321,8 @@ impl Storage } } - fn find_all_archetype_with_comps( - &self, - component_metadata: &[ComponentMetadata], - ) -> Vec<ArchetypeId> + fn find_all_archetype_with_comps(&self, component_ids: &[Uid]) -> Vec<ArchetypeId> { - let comp_metadata_not_opt_cnt = component_metadata - .iter() - .filter(|comp_metadata| !comp_metadata.is_optional) - .count(); - let Some(mut search_iter) = self.graph.dfs_archetype_add_edges(ArchetypeId::new(&[])) else { @@ -362,16 +342,13 @@ impl Storage .get_node_by_id(node_id) .expect("Graph node found through DFS doesn't exist"); - if node.archetype().component_cnt() < comp_metadata_not_opt_cnt { + if node.archetype().component_cnt() < component_ids.len() { continue; } - if !component_metadata + if !component_ids .iter() - .filter(|comp_metadata| !comp_metadata.is_optional) - .all(|comp_metadata| { - node.archetype().has_component_with_id(comp_metadata.id) - }) + .all(|comp_id| node.archetype().has_component_with_id(*comp_id)) { continue; } @@ -431,14 +408,12 @@ impl<'component_storage> Iterator for ArchetypeRefIter<'component_storage> add_edge_archetype_id, add_edge_component_id, } => { - let mut add_edge_archetype_comps = archetype - .component_ids_sorted() - .map(|id| ComponentMetadata { id, is_optional: false }) - .collect::<Vec<_>>(); + let mut add_edge_archetype_comps = + archetype.component_ids_sorted().collect::<Vec<_>>(); add_edge_archetype_comps.insert_at_partition_point_by_key( - ComponentMetadata::new_non_optional(add_edge_component_id), - |comp_metadata| comp_metadata.id, + add_edge_component_id, + |comp_id| *comp_id, ); self.storage.imaginary_archetypes.borrow_mut().push( @@ -446,7 +421,7 @@ impl<'component_storage> Iterator for ArchetypeRefIter<'component_storage> id: add_edge_archetype_id, component_ids: add_edge_archetype_comps .iter() - .map(|comp_metadata| comp_metadata.id) + .map(|comp_id| *comp_id) .collect::<Vec<_>>(), }, ); @@ -457,10 +432,7 @@ impl<'component_storage> Iterator for ArchetypeRefIter<'component_storage> self.dfs_iter.push(( BorrowedOrOwned::Owned(Archetype::new( add_edge_archetype_id, - add_edge_archetype_comps - .iter() - .map(|metadata| metadata.id) - .collect::<Vec<_>>(), + add_edge_archetype_comps.clone(), )), found.into_iter(), )); @@ -485,7 +457,7 @@ impl ArchetypeRefIter<'_> { fn find_edges_of_imaginary_archetype( &self, - imaginary_archetype_comps: &[ComponentMetadata], + imaginary_archetype_comps: &[Uid], ) -> Vec<(Uid, ArchetypeEdges)> { self.storage @@ -500,17 +472,16 @@ impl ArchetypeRefIter<'_> let unique_comp_id = found_archetype .component_ids_sorted() - .find(|id| { - !imaginary_archetype_comps - .iter() - .any(|comp_metadata| comp_metadata.id == *id) + .find(|found_archetype_comp_id| { + !imaginary_archetype_comps.iter().any( + |imaginary_archetype_comp_id| { + *imaginary_archetype_comp_id == *found_archetype_comp_id + }, + ) }) .expect("Oh noooo"); - let mut add_edge_comp_ids = imaginary_archetype_comps - .iter() - .map(|comp_metadata| comp_metadata.id) - .collect::<Vec<_>>(); + let mut add_edge_comp_ids = imaginary_archetype_comps.to_vec(); add_edge_comp_ids .insert_at_partition_point_by_key(unique_comp_id, |id| *id); diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index ad83d1e..cb2059b 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -11,12 +11,7 @@ use hashbrown::HashMap; use crate::actions::Action; use crate::component::storage::Storage as ComponentStorage; -use crate::component::{ - Component, - Metadata as ComponentMetadata, - RefSequence as ComponentRefSequence, - Sequence as ComponentSequence, -}; +use crate::component::{Component, Sequence as ComponentSequence}; use crate::entity::CREATE_STATIC_ENTITIES; use crate::event::component::Kind as ComponentEventKind; use crate::extension::{Collector as ExtensionCollector, Extension}; @@ -24,13 +19,17 @@ use crate::lock::{Lock, WriteGuard}; use crate::phase::{Phase, START as START_PHASE}; use crate::query::flexible::Query as FlexibleQuery; use crate::query::options::{Not, Options as QueryOptions, With}; +use crate::query::{ + ComponentIter, + TermSequence as QueryTermSequence, + Terms as QueryTerms, +}; use crate::relationship::{ChildOf, DependsOn, Relationship}; use crate::sole::Sole; use crate::stats::Stats; use crate::system::{System, SystemComponent}; use crate::type_name::TypeName; use crate::uid::{Kind as UidKind, Uid}; -use crate::util::Sortable; pub mod actions; pub mod component; @@ -174,22 +173,20 @@ impl World extension.collect(extension_collector); } - pub fn query<Comps, OptionsT>(&self) -> Query<Comps, OptionsT> + pub fn query<Terms, OptionsT>(&self) -> Query<Terms, OptionsT> where - Comps: ComponentRefSequence, + Terms: QueryTermSequence, OptionsT: QueryOptions, { Query::new(self) } - pub fn flexible_query<CompMetadata>( + pub fn flexible_query<'terms>( &self, - comp_metadata: CompMetadata, - ) -> FlexibleQuery<CompMetadata> - where - CompMetadata: Sortable<Item = ComponentMetadata> + AsRef<[ComponentMetadata]>, + terms: QueryTerms<'terms>, + ) -> FlexibleQuery<'_, 'terms> { - FlexibleQuery::new(self, comp_metadata) + FlexibleQuery::new(self, terms) } /// Performs a single tick. @@ -482,14 +479,21 @@ impl World fn emit_event_by_id(&self, event_id: Uid) { - let query = self.flexible_query([ - ComponentMetadata::of::<SystemComponent>(), - ComponentMetadata { id: event_id, is_optional: false }, - ]); - - for (system,) in query - .iter::<()>() - .into_component_iter::<(&SystemComponent,)>(self) + //let query = self.flexible_query([ + // ComponentMetadata::of::<SystemComponent>(), + // ComponentMetadata { id: event_id, is_optional: false }, + //]); + + let mut query_required_ids = [SystemComponent::id(), event_id]; + + let query = self.flexible_query( + QueryTerms::builder() + .with_required_ids(&mut query_required_ids) + .build(), + ); + + for (system,) in + ComponentIter::<(&SystemComponent,), _>::new(self, query.iter::<()>()) { unsafe { system.system.run(self); diff --git a/ecs/src/query.rs b/ecs/src/query.rs index ca9345c..2fcd2cc 100644 --- a/ecs/src/query.rs +++ b/ecs/src/query.rs @@ -1,6 +1,10 @@ +use std::any::type_name; +use std::borrow::Cow; use std::marker::PhantomData; -use crate::component::RefSequence as ComponentRefSequence; +use seq_macro::seq; + +use crate::component::{Component, FromLockedOptional, Ref as ComponentRef}; use crate::query::flexible::{ EntityHandle, Iter as FlexibleQueryIter, @@ -9,24 +13,25 @@ use crate::query::flexible::{ use crate::query::options::Options; use crate::system::{Param as SystemParam, System}; use crate::uid::Uid; -use crate::World; +use crate::util::VecExt; +use crate::{EntityComponent, World}; pub mod flexible; pub mod options; #[derive(Debug)] -pub struct Query<'world, Comps, OptionsT = ()> +pub struct Query<'world, Terms, OptionsT = ()> where - Comps: ComponentRefSequence, + Terms: TermSequence, { world: &'world World, - inner: FlexibleQuery<'world, Comps::Metadata>, - _pd: PhantomData<(Comps, OptionsT)>, + inner: FlexibleQuery<'world, 'static>, + _pd: PhantomData<(Terms, OptionsT)>, } -impl<'world, Comps, OptionsT> Query<'world, Comps, OptionsT> +impl<'world, Terms, OptionsT> Query<'world, Terms, OptionsT> where - Comps: ComponentRefSequence, + Terms: TermSequence, OptionsT: Options, { /// Iterates over the entities matching this query, the iterator item being the entity @@ -34,9 +39,9 @@ where #[must_use] pub fn iter<'query>( &'query self, - ) -> ComponentIter<'query, 'world, Comps, FlexibleQueryIter<'query>> + ) -> ComponentIter<'query, 'world, Terms, FlexibleQueryIter<'query>> { - tracing::trace!("Searching for {}", std::any::type_name::<Comps>()); + tracing::trace!("Searching for {}", std::any::type_name::<Terms>()); ComponentIter { world: self.world, @@ -50,9 +55,9 @@ where #[must_use] pub fn iter_with_euids<'query>( &'query self, - ) -> ComponentAndEuidIter<'query, 'world, Comps, FlexibleQueryIter<'query>> + ) -> ComponentAndEuidIter<'query, 'world, Terms, FlexibleQueryIter<'query>> { - tracing::trace!("Searching for {}", std::any::type_name::<Comps>()); + tracing::trace!("Searching for {}", std::any::type_name::<Terms>()); ComponentAndEuidIter { world: self.world, @@ -70,11 +75,11 @@ where pub fn iter_with<'query, OutIter>( &'query self, func: impl FnOnce(FlexibleQueryIter<'query>) -> OutIter, - ) -> ComponentIter<'query, 'world, Comps, OutIter> + ) -> ComponentIter<'query, 'world, Terms, OutIter> where OutIter: Iterator<Item = EntityHandle<'query>>, { - tracing::trace!("Searching for {}", std::any::type_name::<Comps>()); + tracing::trace!("Searching for {}", std::any::type_name::<Terms>()); ComponentIter { world: self.world, @@ -94,20 +99,20 @@ where { Self { world, - inner: world.flexible_query(Comps::metadata()), + inner: world.flexible_query(Terms::build_terms()), _pd: PhantomData, } } } -impl<'query, 'world, Comps, OptionsT> IntoIterator - for &'query Query<'world, Comps, OptionsT> +impl<'query, 'world, Terms, OptionsT> IntoIterator + for &'query Query<'world, Terms, OptionsT> where - Comps: ComponentRefSequence + 'world, + Terms: TermSequence + 'world, OptionsT: Options, { - type IntoIter = ComponentIter<'query, 'world, Comps, FlexibleQueryIter<'query>>; - type Item = Comps::Handles<'query>; + type IntoIter = ComponentIter<'query, 'world, Terms, FlexibleQueryIter<'query>>; + type Item = Terms::Handles<'query>; fn into_iter(self) -> Self::IntoIter { @@ -115,9 +120,9 @@ where } } -impl<'world, Comps, OptionsT> SystemParam<'world> for Query<'world, Comps, OptionsT> +impl<'world, Terms, OptionsT> SystemParam<'world> for Query<'world, Terms, OptionsT> where - Comps: ComponentRefSequence, + Terms: TermSequence, OptionsT: Options, { type Input = (); @@ -138,66 +143,213 @@ where } } -pub struct ComponentIter<'query, 'world, Comps, EntityHandleIter> +#[derive(Debug)] +pub struct Terms<'a> +{ + required_components: Cow<'a, [Uid]>, + //optional_components: Cow<'a, [Uid]>, +} + +impl<'a> Terms<'a> +{ + pub fn builder() -> TermsBuilder<'a> + { + TermsBuilder::default() + } +} + +#[derive(Debug, Default)] +pub struct TermsBuilder<'a> +{ + required_components: Cow<'a, [Uid]>, + //optional_components: Cow<'a, [Uid]>, +} + +impl<'a> TermsBuilder<'a> +{ + pub fn with<ComponentT: Component>(mut self) -> Self + { + if ComponentT::is_optional() { + //self.optional_components + // .to_mut() + // .insert_at_partition_point_by_key(ComponentT::id(), |id| *id); + + return self; + } + + self.required_components + .to_mut() + .insert_at_partition_point_by_key(ComponentT::id(), |id| *id); + + assert!(self.required_components.is_sorted()); + + self + } + + pub fn with_required_ids(mut self, ids: &'a mut [Uid]) -> Self + { + if ids.is_empty() { + return self; + } + + if !ids.is_sorted() { + ids.sort(); + } + + if self.required_components.is_empty() { + self.required_components = Cow::Borrowed(ids); + + return self; + } + + let first_id_pp_index = self.required_components.partition_point(|req_comp_id| { + req_comp_id <= ids.first().expect("Cannot happend since not empty") + }); + + let removed = self + .required_components + .to_mut() + .splice(first_id_pp_index..first_id_pp_index, ids.iter().copied()); + + assert_eq!(removed.count(), 0); + + self + } + + pub fn build(self) -> Terms<'a> + { + assert!(self.required_components.is_sorted()); + //assert!(self.optional_components.is_sorted()); + + Terms { + required_components: self.required_components, + //optional_components: self.optional_components, + } + } +} + +pub trait Term +{ + type Handle<'a>; + + fn apply_to_terms_builder(terms_builder: TermsBuilder) -> TermsBuilder; + + fn create_handle<'world>( + get_component: &impl Fn(Uid) -> Option<&'world EntityComponent>, + world: &'world World, + ) -> Self::Handle<'world>; +} + +impl<ComponentRefT: ComponentRef> Term for ComponentRefT +{ + type Handle<'a> = ComponentRefT::Handle<'a>; + + fn apply_to_terms_builder(terms_builder: TermsBuilder) -> TermsBuilder + { + terms_builder.with::<ComponentRefT::Component>() + } + + fn create_handle<'world>( + get_component: &impl Fn(Uid) -> Option<&'world EntityComponent>, + world: &'world World, + ) -> Self::Handle<'world> + { + Self::Handle::from_locked_optional_component( + get_component(ComponentRefT::Component::id()) + .map(|component| &component.component), + world, + ) + .unwrap_or_else(|err| { + panic!( + "Taking component {} lock failed: {err}", + type_name::<ComponentRefT::Component>() + ); + }) + } +} + +/// A sequence of references (immutable or mutable) to components. +pub trait TermSequence +{ + type Handles<'component>; + + fn build_terms() -> Terms<'static>; + + fn from_components<'component>( + get_component: impl Fn(Uid) -> Option<&'component EntityComponent>, + world: &'component World, + ) -> Self::Handles<'component>; +} + +pub struct ComponentIter<'query, 'world, Terms, EntityHandleIter> where EntityHandleIter: Iterator<Item = EntityHandle<'query>>, { world: &'world World, iter: EntityHandleIter, - comps_pd: PhantomData<Comps>, + comps_pd: PhantomData<Terms>, } -impl<'query, 'world, Comps, EntityHandleIter> - ComponentIter<'query, 'world, Comps, EntityHandleIter> +impl<'query, 'world, Terms, EntityHandleIter> + ComponentIter<'query, 'world, Terms, EntityHandleIter> where - Comps: ComponentRefSequence + 'world, + Terms: TermSequence + 'world, EntityHandleIter: Iterator<Item = EntityHandle<'query>>, 'world: 'query, { - pub(crate) fn new(world: &'world World, iter: EntityHandleIter) -> Self + /// 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, Comps, EntityHandleIter> Iterator - for ComponentIter<'query, 'world, Comps, EntityHandleIter> +impl<'query, 'world, Terms, EntityHandleIter> Iterator + for ComponentIter<'query, 'world, Terms, EntityHandleIter> where - Comps: ComponentRefSequence + 'world, + Terms: TermSequence + 'world, EntityHandleIter: Iterator<Item = EntityHandle<'query>>, 'world: 'query, { - type Item = Comps::Handles<'query>; + type Item = Terms::Handles<'query>; fn next(&mut self) -> Option<Self::Item> { let entity_handle = self.iter.next()?; - Some(Comps::from_components( - entity_handle.components(), - |component_uid| entity_handle.get_component_index(component_uid), + Some(Terms::from_components( + |component_uid| { + entity_handle + .components() + .get(entity_handle.get_component_index(component_uid)?) + }, self.world, )) } } -pub struct ComponentAndEuidIter<'query, 'world, Comps, EntityHandleIter> +pub struct ComponentAndEuidIter<'query, 'world, Terms, EntityHandleIter> where EntityHandleIter: Iterator<Item = EntityHandle<'query>>, { world: &'world World, iter: EntityHandleIter, - comps_pd: PhantomData<Comps>, + comps_pd: PhantomData<Terms>, } -impl<'query, 'world, Comps, EntityHandleIter> Iterator - for ComponentAndEuidIter<'query, 'world, Comps, EntityHandleIter> +impl<'query, 'world, Terms, EntityHandleIter> Iterator + for ComponentAndEuidIter<'query, 'world, Terms, EntityHandleIter> where - Comps: ComponentRefSequence + 'world, + Terms: TermSequence + 'world, EntityHandleIter: Iterator<Item = EntityHandle<'query>>, 'world: 'query, { - type Item = (Uid, Comps::Handles<'query>); + type Item = (Uid, Terms::Handles<'query>); fn next(&mut self) -> Option<Self::Item> { @@ -205,11 +357,66 @@ where Some(( entity_handle.uid(), - Comps::from_components( - entity_handle.components(), - |component_uid| entity_handle.get_component_index(component_uid), + Terms::from_components( + |component_uid| { + entity_handle + .components() + .get(entity_handle.get_component_index(component_uid)?) + }, self.world, ), )) } } + +macro_rules! impl_term_sequence { + ($c: tt) => { + seq!(I in 0..=$c { + impl<#(Term~I: Term,)*> TermSequence for (#(Term~I,)*) + { + type Handles<'component> = (#(Term~I::Handle<'component>,)*); + + fn build_terms() -> Terms<'static> + { + let mut term_builder = Terms::builder(); + + #( + term_builder = + Term~I::apply_to_terms_builder(term_builder); + )* + + term_builder.build() + } + + fn from_components<'component>( + get_component: impl Fn(Uid) -> Option<&'component EntityComponent>, + world: &'component World, + ) -> Self::Handles<'component> + { + (#(Term~I::create_handle(&get_component, world),)*) + } + } + }); + }; +} + +seq!(C in 0..=16 { + impl_term_sequence!(C); +}); + +impl TermSequence for () +{ + type Handles<'component> = (); + + fn build_terms() -> Terms<'static> + { + Terms::builder().build() + } + + fn from_components<'component>( + _get_component: impl Fn(Uid) -> Option<&'component EntityComponent>, + _world: &'component World, + ) -> Self::Handles<'component> + { + } +} diff --git a/ecs/src/query/flexible.rs b/ecs/src/query/flexible.rs index c42ec25..a3e8701 100644 --- a/ecs/src/query/flexible.rs +++ b/ecs/src/query/flexible.rs @@ -3,30 +3,21 @@ use std::iter::{repeat_n, Filter, FlatMap, RepeatN, Zip}; use crate::component::storage::archetype::{Archetype, ArchetypeEntity, EntityIter}; use crate::component::storage::{ArchetypeRefIter, 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::query::Terms; use crate::uid::Uid; -use crate::util::Sortable; use crate::{EntityComponent, World}; /// Low-level entity query structure. #[derive(Debug)] -pub struct Query<'world, CompMetadata> -where - CompMetadata: Sortable<Item = ComponentMetadata> + AsRef<[ComponentMetadata]>, +pub struct Query<'world, 'terms> { component_storage: ReadGuard<'world, ComponentStorage>, - comp_metadata: CompMetadata, + terms: Terms<'terms>, } -impl<'world, CompMetadata> Query<'world, CompMetadata> -where - CompMetadata: Sortable<Item = ComponentMetadata> + AsRef<[ComponentMetadata]>, +impl<'world, 'terms> Query<'world, 'terms> { /// Iterates over the entities matching this query. #[must_use] @@ -35,7 +26,7 @@ where Iter { iter: self .component_storage - .search_archetypes(self.comp_metadata.as_ref()) + .search_archetypes(self.terms.required_components.as_ref()) .flat_map( (|archetype| { repeat_n(archetype, archetype.entity_cnt()) @@ -46,17 +37,15 @@ where } } - pub(crate) fn new(world: &'world World, mut comp_metadata: CompMetadata) -> Self + pub(crate) fn new(world: &'world World, terms: Terms<'terms>) -> 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, + terms, } } } @@ -66,27 +55,6 @@ 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, - { - ComponentIter::new(world, self) - } -} - impl<'query> Iterator for Iter<'query> { type Item = EntityHandle<'query>; diff --git a/ecs/tests/query.rs b/ecs/tests/query.rs index 010ffc9..79dfe85 100644 --- a/ecs/tests/query.rs +++ b/ecs/tests/query.rs @@ -1,4 +1,5 @@ -use ecs::component::{Component, RefSequence as ComponentRefSequence}; +use ecs::component::Component; +use ecs::query::TermSequence as QueryTermSequence; use ecs::uid::Uid; use ecs::{Component, World}; use parking_lot::{Mutex, Once}; @@ -41,13 +42,13 @@ fn setup() }); } -fn assert_query_finds_ents<Comps>(world: &World, mut expected_ent_ids: Vec<Uid>) +fn assert_query_finds_ents<QueryTerms>(world: &World, mut expected_ent_ids: Vec<Uid>) where - Comps: ComponentRefSequence, + QueryTerms: QueryTermSequence, { assert!( world - .query::<Comps, ()>() + .query::<QueryTerms, ()>() .iter_with_euids() .all(|(ent_id, _)| { let Some(index) = expected_ent_ids |