From 8d76fe6be211dfc8fc57d4e2f7e312e757ca899c Mon Sep 17 00:00:00 2001 From: HampusM Date: Wed, 24 Sep 2025 14:41:50 +0200 Subject: refactor(ecs): improve pair with wildcard API --- ecs/src/pair.rs | 151 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 101 insertions(+), 50 deletions(-) (limited to 'ecs/src/pair.rs') diff --git a/ecs/src/pair.rs b/ecs/src/pair.rs index caf55db..85be9f6 100644 --- a/ecs/src/pair.rs +++ b/ecs/src/pair.rs @@ -1,5 +1,6 @@ use std::any::type_name; use std::convert::Infallible; +use std::marker::PhantomData; use crate::component::{ Handle as ComponentHandle, @@ -156,7 +157,7 @@ impl QueryTermWithField for Pair where Relation: Component, { - type Field<'a> = WildcardTargetHandle<'a>; + type Field<'a> = WithWildcard<'a, Relation, Wildcard>; fn apply_to_terms_builder( terms_builder: &mut QueryTermsBuilder, @@ -175,9 +176,10 @@ where .next() .expect("Not possible"); - WildcardTargetHandle { + WithWildcard { world, component_ref: first_matching_comp, + _pd: PhantomData, } } } @@ -227,10 +229,10 @@ impl QueryTermWithField for &'_ [Pair] where Relation: Component, { - type Field<'a> = WildcardTargetIter<'a>; + type Field<'a> = MultipleWithWildcard<'a, Relation, Wildcard>; fn apply_to_terms_builder( - terms_builder: &mut QueryTermsBuilder, + _terms_builder: &mut QueryTermsBuilder, ) { } @@ -240,62 +242,43 @@ where world: &'world World, ) -> Self::Field<'world> { - WildcardTargetIter { - inner: entity_handle - .get_matching_components(Pair::::uid()), + MultipleWithWildcard { + entity_handle: entity_handle.clone(), world, + _pd: PhantomData, } } } -pub struct WildcardTargetHandle<'world> +/// Reference to a pair with a wildcard relation/target. +#[derive(Debug)] +pub struct WithWildcard<'world, Relation, Target> { world: &'world World, component_ref: EntityComponentRef<'world>, + _pd: PhantomData<(Relation, Target)>, } -impl WildcardTargetHandle<'_> +impl WithWildcard<'_, Relation, Target> { - /// Attempts to retrieve the target as a entity, returning `None` if not found. - #[must_use] - pub fn get_entity(&self) -> Option> - { - let archetype = self - .world - .data - .component_storage - .get_entity_archetype(self.component_ref.id().target_entity())?; - - let Some(archetype_entity) = - archetype.get_entity_by_id(self.component_ref.id().target_entity()) - else { - unreachable!(); - }; - - Some(EntityHandle::new(archetype, archetype_entity, self.world)) - } - - /// Attempts to retrieve the target as a component, returning `None` if the component + /// Attempts to get the component data of this pair, returning `None` if the `Data` /// type is incorrect. /// /// # Panics - /// Will panic if: - /// - The component is mutably borrowed elsewhere + /// Will panic if the component data is mutably borrowed elsewhere. #[must_use] - pub fn get_component( - &self, - ) -> Option> + pub fn get_data(&self) -> Option> where - ComponentData: 'static, + Data: 'static, { - ComponentHandle::::from_entity_component_ref(&self.component_ref) + ComponentHandle::::from_entity_component_ref(&self.component_ref) .map_or_else( |err| match err { ComponentHandleError::IncorrectType => None, err @ ComponentHandleError::AcquireLockFailed(_) => { panic!( "Creating handle to component {} failed: {err}", - type_name::() + type_name::() ); } }, @@ -303,20 +286,17 @@ impl WildcardTargetHandle<'_> ) } - /// Attempts to retrieve the target as a component, returning `None` if the component + /// Attempts to get the component data of this pair, returning `None` if the `Data` /// type is incorrect. /// /// # Panics - /// Will panic if: - /// - The component is borrowed elsewhere + /// Will panic if the component data is borrowed elsewhere. #[must_use] - pub fn get_component_mut( - &self, - ) -> Option> + pub fn get_data_mut(&self) -> Option> where - ComponentData: 'static, + Data: 'static, { - ComponentHandleMut::::from_entity_component_ref( + ComponentHandleMut::::from_entity_component_ref( &self.component_ref, self.world, ) @@ -326,7 +306,7 @@ impl WildcardTargetHandle<'_> err @ ComponentHandleError::AcquireLockFailed(_) => { panic!( "Creating handle to component {} failed: {err}", - type_name::() + type_name::() ); } }, @@ -335,23 +315,94 @@ impl WildcardTargetHandle<'_> } } -pub struct WildcardTargetIter<'a> +impl WithWildcard<'_, Relation, Wildcard> +{ + /// Attempts to retrieve the target as a entity, returning `None` if not found. + #[must_use] + pub fn get_target_ent(&self) -> Option> + { + let archetype = self + .world + .data + .component_storage + .get_entity_archetype(self.component_ref.id().target_entity())?; + + let Some(archetype_entity) = + archetype.get_entity_by_id(self.component_ref.id().target_entity()) + else { + unreachable!(); + }; + + Some(EntityHandle::new(archetype, archetype_entity, self.world)) + } +} + +/// Used to access matching pairs in a entity containing zero or more matching pairs. +#[derive(Debug)] +pub struct MultipleWithWildcard<'a, Relation, Target> +{ + entity_handle: EntityHandle<'a>, + world: &'a World, + _pd: PhantomData<(Relation, Target)>, +} + +impl<'a, Relation: Component> MultipleWithWildcard<'a, Relation, Wildcard> +{ + #[must_use] + pub fn get_with_target_id( + &self, + target_id: Uid, + ) -> Option> + { + Some(WithWildcard { + world: self.world, + component_ref: self + .entity_handle + .get_matching_components(Pair::new::(target_id).id()) + .next()?, + _pd: PhantomData, + }) + } +} + +impl<'a, Relation: Component> IntoIterator + for MultipleWithWildcard<'a, Relation, Wildcard> +{ + type IntoIter = WithWildcardIter<'a, Relation, Wildcard>; + type Item = ::Item; + + fn into_iter(self) -> Self::IntoIter + { + WithWildcardIter { + inner: self + .entity_handle + .get_matching_components(Pair::::uid()), + world: self.world, + _pd: PhantomData, + } + } +} + +/// Iterator of matching pairs in a entity. +pub struct WithWildcardIter<'a, Relation, Target> { inner: EntityMatchingComponentIter<'a>, world: &'a World, + _pd: PhantomData<(Relation, Target)>, } -impl<'a> Iterator for WildcardTargetIter<'a> +impl<'a, Relation, Target> Iterator for WithWildcardIter<'a, Relation, Target> { - type Item = WildcardTargetHandle<'a>; + type Item = WithWildcard<'a, Relation, Target>; fn next(&mut self) -> Option { let matching_comp = self.inner.next()?; - Some(WildcardTargetHandle { + Some(WithWildcard { world: self.world, component_ref: matching_comp, + _pd: PhantomData, }) } } -- cgit v1.2.3-18-g5258