diff options
Diffstat (limited to 'ecs/src/query.rs')
-rw-r--r-- | ecs/src/query.rs | 295 |
1 files changed, 251 insertions, 44 deletions
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> + { + } +} |