diff options
Diffstat (limited to 'ecs/src/pair.rs')
| -rw-r--r-- | ecs/src/pair.rs | 595 |
1 files changed, 542 insertions, 53 deletions
diff --git a/ecs/src/pair.rs b/ecs/src/pair.rs index 4ff4995..b4bfa57 100644 --- a/ecs/src/pair.rs +++ b/ecs/src/pair.rs @@ -1,6 +1,14 @@ +use std::any::type_name; use std::convert::Infallible; +use std::marker::PhantomData; -use crate::component::{IntoParts as IntoComponentParts, Parts as ComponentParts}; +use crate::component::{ + Handle as ComponentHandle, + HandleError as ComponentHandleError, + HandleMut as ComponentHandleMut, + IntoParts as IntoComponentParts, + Parts as ComponentParts, +}; use crate::entity::{ Handle as EntityHandle, MatchingComponentIter as EntityMatchingComponentIter, @@ -10,24 +18,127 @@ use crate::query::{ TermsBuilder as QueryTermsBuilder, TermsBuilderInterface, }; -use crate::uid::{PairParams as UidPairParams, Uid, Wildcard, With as WithUid}; -use crate::{Component, World}; +use crate::uid::{Kind as UidKind, PairParams as UidPairParams, Uid, With as WithUid}; +use crate::util::impl_multiple; +use crate::{Component, EntityComponentRef, World}; +/// Pair builder. #[derive(Debug)] -pub struct Pair<RelationElem: Element, TargetElem: Element> +pub struct Builder<Relation, Target> { - relation: RelationElem, - target: TargetElem, + relation: Relation, + target: Target, } -impl Pair<Uid, Uid> +impl<Relation, Target> Builder<Relation, Target> +{ + pub fn relation<NewRelation: Component>(self) -> Builder<Uid, Target> + { + Builder { + relation: NewRelation::id(), + target: self.target, + } + } + + pub fn relation_id(self, id: Uid) -> Builder<Uid, Target> + { + Builder { relation: id, target: self.target } + } + + pub fn target<NewTarget: Component>(self) -> Builder<Relation, Uid> + { + Builder { + relation: self.relation, + target: NewTarget::id(), + } + } + + pub fn target_id(self, id: Uid) -> Builder<Relation, Uid> + { + Builder { relation: self.relation, target: id } + } +} + +impl_multiple!( + Builder, + (impl<Target> _<><Uid, Target>, impl<Target> _<><(), Target>) + cb=(type_params=(ty_param_1, ty_param_2)) => { + pub fn target_as_data<NewTarget: Component>( + self, + data: NewTarget, + ) -> Builder<$ty_param_1, NewTarget> + { + Builder { + relation: self.relation, + target: data, + } + } + } +); + +impl_multiple!( + Builder, + (impl<Relation> _<><Relation, Uid>, impl<Relation> _<><Relation, ()>) + cb=(type_params=(ty_param_1, ty_param_2)) => { + pub fn relation_as_data<NewRelation: Component>( + self, + data: NewRelation, + ) -> Builder<NewRelation, $ty_param_2> + { + Builder { + relation: data, + target: self.target, + } + } + } +); + +impl_multiple!( + Builder, + ( + impl _<><Uid, Uid>, + impl<Relation: Component> _<><Relation, Uid>, + impl<Target: Component> _<><Uid, Target>, + impl<Relation: Component, Target: Component> _<><Relation, Target> + ) + cb=(type_params=(ty_param_1, ty_param_2)) => { + #[must_use] + pub fn build(self) -> Pair<$ty_param_1, $ty_param_2> + { + Pair { + relation: self.relation, + target: self.target + } + } + } +); + +impl Default for Builder<(), ()> +{ + fn default() -> Self + { + Self { relation: (), target: () } + } +} + +#[derive(Debug)] +pub struct Pair<Relation, Target> +{ + relation: Relation, + target: Target, +} + +impl Pair<(), ()> { #[must_use] - pub fn new<Relation: WithUid>(target: Uid) -> Self + pub fn builder() -> Builder<(), ()> { - Self { relation: Relation::uid(), target } + Builder { relation: (), target: () } } +} +impl Pair<Uid, Uid> +{ #[must_use] pub fn id(&self) -> Uid { @@ -46,12 +157,116 @@ impl IntoComponentParts for Pair<Uid, Uid> } } -impl<Relation, Target> QueryTermWithField for Pair<Relation, Target> +impl<Target> IntoComponentParts for Pair<Uid, Target> where - Relation: WithUid, - Target: WithUid, + Target: Component, { - type Field<'a> = Handle<'a>; + fn into_parts(self) -> ComponentParts + { + let id = Uid::new_pair(&UidPairParams { + relation: self.relation, + target: Target::id(), + }); + + ComponentParts::builder() + .name("Pair") + .build(id, self.target) + } +} + +impl<Relation> IntoComponentParts for Pair<Relation, Uid> +where + Relation: Component, +{ + fn into_parts(self) -> ComponentParts + { + let id = Uid::new_pair(&UidPairParams { + relation: Relation::id(), + target: self.target, + }); + + ComponentParts::builder() + .name("Pair") + .build(id, self.relation) + } +} + +impl<Relation, Target> QueryTermWithField for Pair<Relation, &Target> +where + Relation: Component, + Target: Component, +{ + type Field<'a> = ComponentHandle<'a, Target>; + + fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( + terms_builder: &mut QueryTermsBuilder<MAX_TERM_CNT>, + ) + { + terms_builder.with_required([Pair::<Relation, Target>::uid()]); + } + + fn get_field<'world>( + entity_handle: &EntityHandle<'world>, + _world: &'world World, + ) -> Self::Field<'world> + { + let target_component = entity_handle + .get_matching_components(Pair::<Relation, Target>::uid()) + .next() + .expect("Not possible"); + + Self::Field::from_entity_component_ref(&target_component).unwrap_or_else(|err| { + panic!( + "Creating handle to target component {} failed: {err}", + type_name::<Target>() + ); + }) + } +} + +impl<Relation, Target> QueryTermWithField for Pair<Relation, &mut Target> +where + Relation: Component, + Target: Component, +{ + type Field<'a> = ComponentHandleMut<'a, Target>; + + fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( + terms_builder: &mut QueryTermsBuilder<MAX_TERM_CNT>, + ) + { + terms_builder.with_required([Pair::<Relation, Target>::uid()]); + } + + fn get_field<'world>( + entity_handle: &EntityHandle<'world>, + world: &'world World, + ) -> Self::Field<'world> + { + let target_component = entity_handle + .get_matching_components(Pair::<Relation, Target>::uid()) + .next() + .expect("Not possible"); + + Self::Field::from_entity_component_ref(&target_component, world).unwrap_or_else( + |err| { + panic!( + "Creating handle to target component {} failed: {err}", + type_name::<Target>() + ); + }, + ) + } +} + +// TODO: implement QueryTermWithField for Pair<&Relation, Target> (or equivalent) +// TODO: implement QueryTermWithField for Pair<&mut Relation, Target> (or equivalent) + +impl<Relation> QueryTermWithField for Pair<Relation, Wildcard> +where + Relation: Component, +{ + type Field<'a> = WithWildcard<'a, Relation, Wildcard>; fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( terms_builder: &mut QueryTermsBuilder<MAX_TERM_CNT>, @@ -70,38 +285,51 @@ where .next() .expect("Not possible"); - Handle { + WithWildcard { world, - pair_uid: first_matching_comp.id(), + component_ref: first_matching_comp, + _pd: PhantomData, } } } impl<Relation, Target> WithUid for Pair<Relation, Target> where - Relation: WithUid, - Target: WithUid, + Relation: Component, + Target: Component, { fn uid() -> Uid { Uid::new_pair(&UidPairParams { - relation: Relation::uid(), - target: Target::uid(), + relation: Relation::id(), + target: Target::id(), }) } } -impl<Relation> QueryTermWithField for &'static [Pair<Relation, Wildcard>] +impl<Relation> WithUid for Pair<Relation, Wildcard> where - Relation: WithUid, + Relation: Component, { - type Field<'a> = HandleIter<'a>; + fn uid() -> Uid + { + Uid::new_pair(&UidPairParams { + relation: Relation::id(), + target: Wildcard::uid(), + }) + } +} + +impl<Relation> QueryTermWithField for &'_ [Pair<Relation, Wildcard>] +where + Relation: Component, +{ + type Field<'a> = MultipleWithWildcard<'a, Relation, Wildcard>; fn apply_to_terms_builder<const MAX_TERM_CNT: usize>( - terms_builder: &mut QueryTermsBuilder<MAX_TERM_CNT>, + _terms_builder: &mut QueryTermsBuilder<MAX_TERM_CNT>, ) { - terms_builder.with_required([Pair::<Relation, Wildcard>::uid()]); } fn get_field<'world>( @@ -109,80 +337,304 @@ where world: &'world World, ) -> Self::Field<'world> { - HandleIter { - inner: entity_handle - .get_matching_components(Pair::<Relation, Wildcard>::uid()), + MultipleWithWildcard { + entity_handle: entity_handle.clone(), world, + _pd: PhantomData, } } } -pub struct Handle<'world> +/// Reference to a pair with a wildcard relation/target. +#[derive(Debug)] +pub struct WithWildcard<'world, Relation, Target> { world: &'world World, - pair_uid: Uid, + component_ref: EntityComponentRef<'world>, + _pd: PhantomData<(Relation, Target)>, } -impl Handle<'_> +impl<'world, Relation, Target> WithWildcard<'world, Relation, Target> { + /// Returns a new `WithWildcard`. + /// + /// # Panics + /// This function will panic if: + /// - The given component's ID is not a pair ID. + /// - `Relation::uid()` is not wildcard and does not equal to the relation of the + /// given component's ID + /// - `Target::uid()` is not wildcard and does not equal to the target of the given + /// component's ID + /// - Both `Relation::uid()` and `Target::uid()` are wildcards + /// - Neither `Relation::uid()` or `Target::uid()` are wildcards + pub fn new(world: &'world World, component_ref: EntityComponentRef<'world>) -> Self + where + Relation: ComponentOrWildcard, + Target: ComponentOrWildcard, + { + let component_id = component_ref.id(); + + assert!(component_id.kind() == UidKind::Pair); + + assert!( + Relation::uid() == Wildcard::uid() + || component_id.relation_component() == Relation::uid() + ); + + assert!( + Target::uid() == Wildcard::uid() + || component_id.target_component() == Target::uid() + ); + + assert!(Relation::uid() == Wildcard::uid() || Target::uid() == Wildcard::uid()); + + assert!( + !(Relation::uid() == Wildcard::uid() && Target::uid() == Wildcard::uid()) + ); + + WithWildcard { + world, + component_ref, + _pd: PhantomData, + } + } + + /// Returns the [`Uid`] of the pair. + #[must_use] + pub fn id(&self) -> Uid + { + self.component_ref.id() + } + + /// Attempts to get the component data of this pair, returning `None` if the `Data` + /// type is incorrect. + /// + /// # Panics + /// Will panic if the component data is mutably borrowed elsewhere. #[must_use] - pub fn get_target_entity(&self) -> Option<EntityHandle<'_>> + pub fn get_data<Data>(&self) -> Option<ComponentHandle<'_, Data>> + where + Data: 'static, + { + ComponentHandle::<Data>::from_entity_component_ref(&self.component_ref) + .map_or_else( + |err| match err { + ComponentHandleError::IncorrectType => None, + err @ ComponentHandleError::AcquireLockFailed(_) => { + panic!( + "Creating handle to pair data as component {} failed: {err}", + type_name::<Data>() + ); + } + }, + Some, + ) + } + + /// Attempts to get the component data of this pair, returning `None` if the `Data` + /// type is incorrect. + /// + /// # Panics + /// Will panic if the component data is borrowed elsewhere. + #[must_use] + pub fn get_data_mut<Data>(&self) -> Option<ComponentHandleMut<'_, Data>> + where + Data: 'static, + { + ComponentHandleMut::<Data>::from_entity_component_ref( + &self.component_ref, + self.world, + ) + .map_or_else( + |err| match err { + ComponentHandleError::IncorrectType => None, + err @ ComponentHandleError::AcquireLockFailed(_) => { + panic!( + "Creating handle to pair data as component {} failed: {err}", + type_name::<Data>() + ); + } + }, + Some, + ) + } +} + +impl<Relation> WithWildcard<'_, Relation, Wildcard> +where + Relation: Component, +{ + /// Attempts to retrieve the target as a entity, returning `None` if not found. + #[must_use] + pub fn get_target_ent(&self) -> Option<EntityHandle<'_>> { let archetype = self .world .data .component_storage - .get_entity_archetype(self.pair_uid.target_entity())?; + .get_entity_archetype(self.component_ref.id().target_entity())?; let Some(archetype_entity) = - archetype.get_entity_by_id(self.pair_uid.target_entity()) + archetype.get_entity_by_id(self.component_ref.id().target_entity()) else { unreachable!(); }; - Some(EntityHandle::new(archetype, archetype_entity)) + Some(EntityHandle::new(archetype, archetype_entity, self.world)) + } + + /// Attempts to get the component data of this pair, returning `None` if the + /// `Relation` type is incorrect. + /// + /// # Panics + /// Will panic if the component data is mutably borrowed elsewhere. + #[must_use] + pub fn get_data_as_relation(&self) -> Option<ComponentHandle<'_, Relation>> + { + ComponentHandle::<Relation>::from_entity_component_ref(&self.component_ref) + .map_or_else( + |err| match err { + ComponentHandleError::IncorrectType => None, + err @ ComponentHandleError::AcquireLockFailed(_) => { + panic!( + "Creating handle to pair data as component {} failed: {err}", + type_name::<Relation>() + ); + } + }, + Some, + ) + } + + /// Attempts to get the component data of this pair, returning `None` if the + /// `Relation` type is incorrect. + /// + /// # Panics + /// Will panic if the component data is borrowed elsewhere. + #[must_use] + pub fn get_data_as_relation_mut(&self) -> Option<ComponentHandleMut<'_, Relation>> + { + ComponentHandleMut::<Relation>::from_entity_component_ref( + &self.component_ref, + self.world, + ) + .map_or_else( + |err| match err { + ComponentHandleError::IncorrectType => None, + err @ ComponentHandleError::AcquireLockFailed(_) => { + panic!( + "Creating handle to pair data as component {} failed: {err}", + type_name::<Relation>() + ); + } + }, + Some, + ) } } -pub struct HandleIter<'a> +/// Used to access matching pairs in a entity containing zero or more matching pairs. +#[derive(Debug)] +pub struct MultipleWithWildcard<'a, Relation, Target> { - inner: EntityMatchingComponentIter<'a>, + entity_handle: EntityHandle<'a>, world: &'a World, + _pd: PhantomData<(Relation, Target)>, } -impl<'a> Iterator for HandleIter<'a> +impl<'world, Relation, Target> MultipleWithWildcard<'world, Relation, Target> { - type Item = Handle<'a>; - - fn next(&mut self) -> Option<Self::Item> + /// Returns a new `MultipleWithWildcard`. + /// + /// # Panics + /// This function will panic if: + /// - Both `Relation::uid()` and `Target::uid()` are wildcards + /// - Neither `Relation::uid()` or `Target::uid()` are wildcards + pub fn new(world: &'world World, entity_handle: EntityHandle<'world>) -> Self + where + Relation: ComponentOrWildcard, + Target: ComponentOrWildcard, { - let matching_comp = self.inner.next()?; + assert!(Relation::uid() == Wildcard::uid() || Target::uid() == Wildcard::uid()); + + assert!( + !(Relation::uid() == Wildcard::uid() && Target::uid() == Wildcard::uid()) + ); - Some(Handle { + MultipleWithWildcard { + entity_handle, + world, + _pd: PhantomData, + } + } +} + +impl<'a, Relation: Component> MultipleWithWildcard<'a, Relation, Wildcard> +{ + #[must_use] + pub fn get_with_target_id( + &self, + target_id: Uid, + ) -> Option<WithWildcard<'a, Relation, Wildcard>> + { + Some(WithWildcard { world: self.world, - pair_uid: matching_comp.id(), + component_ref: self + .entity_handle + .get_matching_components( + Pair::builder() + .relation::<Relation>() + .target_id(target_id) + .build() + .id(), + ) + .next()?, + _pd: PhantomData, }) } } -pub trait Element: sealed::Sealed +impl<'a, Relation: Component> IntoIterator + for MultipleWithWildcard<'a, Relation, Wildcard> { - type Value; + type IntoIter = WithWildcardIter<'a, Relation, Wildcard>; + type Item = <Self::IntoIter as Iterator>::Item; + + fn into_iter(self) -> Self::IntoIter + { + WithWildcardIter { + inner: self + .entity_handle + .get_matching_components(Pair::<Relation, Wildcard>::uid()), + world: self.world, + _pd: PhantomData, + } + } } -impl Element for Uid +/// Iterator of matching pairs in a entity. +pub struct WithWildcardIter<'a, Relation, Target> { - type Value = Uid; + inner: EntityMatchingComponentIter<'a>, + world: &'a World, + _pd: PhantomData<(Relation, Target)>, } -impl sealed::Sealed for Uid {} - -impl<WithUidT: WithUid> Element for WithUidT +impl<'a, Relation, Target> Iterator for WithWildcardIter<'a, Relation, Target> { - type Value = Infallible; -} + type Item = WithWildcard<'a, Relation, Target>; -impl<WithUidT: WithUid> sealed::Sealed for WithUidT {} + fn next(&mut self) -> Option<Self::Item> + { + let matching_comp = self.inner.next()?; + + Some(WithWildcard { + world: self.world, + component_ref: matching_comp, + _pd: PhantomData, + }) + } +} /// Relation denoting a dependency to another entity #[derive(Debug, Default, Clone, Copy, Component)] @@ -192,6 +644,43 @@ pub struct DependsOn; #[derive(Debug, Default, Clone, Copy, Component)] pub struct ChildOf; +#[derive(Debug)] +pub struct Wildcard(Infallible); + +impl Wildcard +{ + #[must_use] + pub fn uid() -> Uid + { + Uid::wildcard() + } +} + +pub trait ComponentOrWildcard: sealed::Sealed +{ + fn uid() -> Uid; +} + +impl<ComponentT: Component> ComponentOrWildcard for ComponentT +{ + fn uid() -> Uid + { + ComponentT::id() + } +} + +impl<ComponentT: Component> sealed::Sealed for ComponentT {} + +impl ComponentOrWildcard for Wildcard +{ + fn uid() -> Uid + { + Wildcard::uid() + } +} + +impl sealed::Sealed for Wildcard {} + mod sealed { pub trait Sealed {} |
