use std::any::type_name; use std::convert::Infallible; use std::marker::PhantomData; 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, }; use crate::query::{ TermWithField as QueryTermWithField, TermsBuilder as QueryTermsBuilder, TermsBuilderInterface, }; use crate::uid::{PairParams as UidPairParams, Uid, With as WithUid}; use crate::{Component, EntityComponentRef, World}; #[derive(Debug)] pub struct Pair { relation: Relation, target: Target, } impl Pair { #[must_use] pub fn new(target: Uid) -> Self { Self { relation: Relation::id(), target } } #[must_use] pub fn id(&self) -> Uid { Uid::new_pair(&UidPairParams { relation: self.relation, target: self.target, }) } } impl Pair where Target: Component, { /// Returns a new pair that contains the target component as data. pub fn new_with_comp_target(target_component: Target) -> Self { Self { relation: Relation::uid(), target: target_component, } } } impl IntoComponentParts for Pair { fn into_parts(self) -> ComponentParts { ComponentParts::builder().name("Pair").build(self.id(), ()) } } impl IntoComponentParts for Pair where Target: Component, { 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 QueryTermWithField for Pair where Relation: Component, Target: Component, { type Field<'a> = ComponentHandle<'a, Target>; fn apply_to_terms_builder( terms_builder: &mut QueryTermsBuilder, ) { terms_builder.with_required([Self::uid()]); } fn get_field<'world>( entity_handle: &EntityHandle<'world>, _world: &'world World, ) -> Self::Field<'world> { let target_component = entity_handle .get_matching_components(Self::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::() ); }) } } impl QueryTermWithField for Pair where Relation: Component, Target: Component, { type Field<'a> = ComponentHandleMut<'a, Target>; fn apply_to_terms_builder( terms_builder: &mut QueryTermsBuilder, ) { terms_builder.with_required([Self::uid()]); } fn get_field<'world>( entity_handle: &EntityHandle<'world>, world: &'world World, ) -> Self::Field<'world> { let target_component = entity_handle .get_matching_components(Self::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::() ); }, ) } } impl QueryTermWithField for Pair where Relation: Component, { type Field<'a> = WithWildcard<'a, Relation, Wildcard>; fn apply_to_terms_builder( terms_builder: &mut QueryTermsBuilder, ) { terms_builder.with_required([Self::uid()]); } fn get_field<'world>( entity_handle: &EntityHandle<'world>, world: &'world World, ) -> Self::Field<'world> { let first_matching_comp = entity_handle .get_matching_components(Self::uid()) .next() .expect("Not possible"); WithWildcard { world, component_ref: first_matching_comp, _pd: PhantomData, } } } impl WithUid for Pair where Relation: Component, Target: Component, { fn uid() -> Uid { Uid::new_pair(&UidPairParams { relation: Relation::uid(), target: Target::uid(), }) } } impl WithUid for Pair where Relation: Component, Target: Component, { fn uid() -> Uid { Uid::new_pair(&UidPairParams { relation: Relation::uid(), target: Target::uid(), }) } } impl WithUid for Pair where Relation: Component, { fn uid() -> Uid { Uid::new_pair(&UidPairParams { relation: Relation::uid(), target: Wildcard::uid(), }) } } impl QueryTermWithField for &'_ [Pair] where Relation: Component, { type Field<'a> = MultipleWithWildcard<'a, Relation, Wildcard>; fn apply_to_terms_builder( _terms_builder: &mut QueryTermsBuilder, ) { } fn get_field<'world>( entity_handle: &EntityHandle<'world>, world: &'world World, ) -> Self::Field<'world> { MultipleWithWildcard { entity_handle: entity_handle.clone(), world, _pd: PhantomData, } } } /// 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 WithWildcard<'_, Relation, Target> { /// 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_data(&self) -> Option> where Data: 'static, { 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::() ); } }, 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(&self) -> Option> where Data: 'static, { ComponentHandleMut::::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 component {} failed: {err}", type_name::() ); } }, Some, ) } } 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, Relation, Target> Iterator for WithWildcardIter<'a, Relation, Target> { type Item = WithWildcard<'a, Relation, Target>; fn next(&mut self) -> Option { 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)] pub struct DependsOn; /// Relation denoting being the child of another entity. #[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() } }