use std::any::{TypeId, 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::{ SearchResult, Term as QueryTerm, TermMetadata as QueryTermMetadata, TermsBuilder as QueryTermsBuilder, TermsBuilderInterface, }; use crate::reflection::Type as TypeReflection; use crate::uid::{PairParams as UidPairParams, Uid, With as WithUid}; use crate::util::impl_multiple; use crate::{Component, EntityComponentRef, World}; /// Pair builder. #[derive(Debug)] pub struct Builder { relation: Relation, target: Target, relation_metadata: Option, target_metadata: Option, } impl Builder { pub fn relation(self) -> Builder { Builder { relation: NewRelation::id(), target: self.target, relation_metadata: Some(MemberMetadata { ty: NewRelation::type_reflection(), ty_id: TypeId::of::(), name: type_name::(), }), target_metadata: self.target_metadata, } } pub fn relation_id(self, id: Uid) -> Builder { Builder { relation: id, target: self.target, relation_metadata: None, target_metadata: self.target_metadata, } } pub fn target(self) -> Builder { Builder { relation: self.relation, target: NewTarget::id(), relation_metadata: self.relation_metadata, target_metadata: Some(MemberMetadata { ty: NewTarget::type_reflection(), ty_id: TypeId::of::(), name: type_name::(), }), } } pub fn target_id(self, id: Uid) -> Builder { Builder { relation: self.relation, target: id, relation_metadata: self.relation_metadata, target_metadata: None, } } } impl_multiple!( Builder, (impl _<>, impl _<><(), Target>) cb=(type_params=(ty_param_1, ty_param_2)) => { pub fn target_as_data( self, data: NewTarget, ) -> Builder<$ty_param_1, NewTarget> { Builder { relation: self.relation, target: data, relation_metadata: self.relation_metadata, target_metadata: Some(MemberMetadata { ty: NewTarget::type_reflection(), ty_id: TypeId::of::(), name: type_name::(), }), } } } ); impl_multiple!( Builder, (impl _<>, impl _<>) cb=(type_params=(ty_param_1, ty_param_2)) => { pub fn relation_as_data( self, data: NewRelation, ) -> Builder { Builder { relation: data, target: self.target, relation_metadata: Some(MemberMetadata { ty: NewRelation::type_reflection(), ty_id: TypeId::of::(), name: type_name::(), }), target_metadata: self.target_metadata, } } } ); impl_multiple!( Builder, ( impl _<>, impl _<>, impl _<>, impl _<> ) 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, relation_metadata: self.relation_metadata, target_metadata: self.target_metadata, } } } ); impl Default for Builder<(), ()> { fn default() -> Self { Self { relation: (), target: (), relation_metadata: None, target_metadata: None, } } } #[derive(Debug)] pub struct Pair { relation: Relation, target: Target, relation_metadata: Option, target_metadata: Option, } impl Pair<(), ()> { #[must_use] pub fn builder() -> Builder<(), ()> { Builder::default() } } impl Pair { #[must_use] pub fn id(&self) -> Uid { Uid::new_pair(&UidPairParams { relation: self.relation, target: self.target, }) } } impl IntoComponentParts for Pair { fn into_parts(self) -> ComponentParts { let id = self.id(); ComponentParts::builder() .name("Pair") .pair_relation_metadata(self.relation_metadata) .pair_target_metadata(self.target_metadata) .build(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") .pair_relation_metadata(self.relation_metadata) .pair_target_metadata(self.target_metadata) .build(id, self.target) } } impl IntoComponentParts for Pair where Relation: Component, { fn into_parts(self) -> ComponentParts { let id = Uid::new_pair(&UidPairParams { relation: Relation::id(), target: self.target, }); ComponentParts::builder() .name("Pair") .pair_relation_metadata(self.relation_metadata) .pair_target_metadata(self.target_metadata) .build(id, self.relation) } } impl<'query, Relation, Target> QueryTerm<'query> for Pair where Relation: Component, Target: Component, { type Fields = (ComponentHandle<'query, Target>,); fn apply_to_terms_builder( terms_builder: &mut QueryTermsBuilder, _term_metadata: QueryTermMetadata, ) { terms_builder.present([Pair::::uid()]); } fn fields( _world: &'query World, search_result: &SearchResult<'query, '_>, _term_metadata: QueryTermMetadata, ) -> Self::Fields { let target_component = search_result .entity_handle .get_matching_components(Pair::::uid()) .next() .expect("Not possible"); let target_component = match ComponentHandle::::from_entity_component_ref(&target_component) { Ok(target_component) => target_component, Err(err) => { panic!( "Creating handle to target component {} failed: {err}", type_name::() ); } }; (target_component,) } } impl<'query, Relation, Target> QueryTerm<'query> for Pair where Relation: Component, Target: Component, { type Fields = (ComponentHandleMut<'query, Target>,); fn apply_to_terms_builder( terms_builder: &mut QueryTermsBuilder, _term_metadata: QueryTermMetadata, ) { terms_builder.present([Pair::::uid()]); } fn fields( world: &'query World, search_result: &SearchResult<'query, '_>, _term_metadata: QueryTermMetadata, ) -> Self::Fields { let target_component = search_result .entity_handle .get_matching_components(Pair::::uid()) .next() .expect("Not possible"); let target_component = match ComponentHandleMut::::from_entity_component_ref( &target_component, world, ) { Ok(target_component) => target_component, Err(err) => { panic!( "Creating mut handle to target component {} failed: {err}", type_name::() ); } }; (target_component,) } } // TODO: implement QueryTerm for Pair<&Relation, Target> (or equivalent) // TODO: implement QueryTerm for Pair<&mut Relation, Target> (or equivalent) impl<'query, Relation> QueryTerm<'query> for Pair where Relation: Component, { type Fields = (WithWildcard<'query, Relation, Wildcard>,); fn apply_to_terms_builder( terms_builder: &mut QueryTermsBuilder, _term_metadata: QueryTermMetadata, ) { terms_builder.present([Self::uid()]); } fn fields( world: &'query World, search_result: &SearchResult<'query, '_>, _term_metadata: QueryTermMetadata, ) -> Self::Fields { let first_matching_comp = search_result .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::id(), target: Target::id(), }) } } impl WithUid for Pair where Relation: Component, { fn uid() -> Uid { Uid::new_pair(&UidPairParams { relation: Relation::id(), target: Wildcard::uid(), }) } } impl<'query, Relation> QueryTerm<'query> for &[Pair] where Relation: Component, { type Fields = (MultipleWithWildcard<'query, Relation, Wildcard>,); fn apply_to_terms_builder( _terms_builder: &mut QueryTermsBuilder, _term_metadata: QueryTermMetadata, ) { } fn fields( world: &'query World, search_result: &SearchResult<'query, '_>, _term_metadata: QueryTermMetadata, ) -> Self::Fields { (MultipleWithWildcard { entity_handle: search_result.entity_handle.clone(), world, _pd: PhantomData, },) } } /// Reference to a pair with a wildcard relation/target. #[derive(Debug)] pub struct WithWildcard<'query, Relation, Target> { world: &'query World, component_ref: EntityComponentRef<'query>, _pd: PhantomData<(Relation, Target)>, } impl<'query, Relation, Target> WithWildcard<'query, 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: &'query World, component_ref: EntityComponentRef<'query>) -> Self where Relation: ComponentOrWildcard, Target: ComponentOrWildcard, { let component_id = component_ref.id(); assert!(component_id.is_pair()); assert!( Relation::uid() == Wildcard::uid() || component_id.relation() == Relation::uid() ); assert!( Target::uid() == Wildcard::uid() || component_id.target() == 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_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 pair data as 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 pair data as component {} failed: {err}", type_name::() ); } }, Some, ) } } impl<'query, Relation> WithWildcard<'query, 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> { let archetype = self .world .data .component_storage .get_entity_archetype(self.component_ref.id().target())?; let Some(archetype_entity) = archetype.get_entity_by_id(self.component_ref.id().target()) else { unreachable!(); }; 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::::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::() ); } }, 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::::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::() ); } }, Some, ) } } /// 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<'query, Relation, Target> MultipleWithWildcard<'query, Relation, Target> { /// 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: &'query World, entity_handle: EntityHandle<'query>) -> Self where Relation: ComponentOrWildcard, Target: ComponentOrWildcard, { assert!(Relation::uid() == Wildcard::uid() || Target::uid() == Wildcard::uid()); assert!( !(Relation::uid() == Wildcard::uid() && Target::uid() == Wildcard::uid()) ); 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> { Some(WithWildcard { world: self.world, component_ref: self .entity_handle .get_matching_components( Pair::builder() .relation::() .target_id(target_id) .build() .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() } } pub trait ComponentOrWildcard: sealed::Sealed { fn uid() -> Uid; } impl ComponentOrWildcard for ComponentT { fn uid() -> Uid { ComponentT::id() } } impl sealed::Sealed for ComponentT {} impl ComponentOrWildcard for Wildcard { fn uid() -> Uid { Wildcard::uid() } } impl sealed::Sealed for Wildcard {} #[derive(Debug, Clone)] #[non_exhaustive] pub struct MemberMetadata { pub ty: Option<&'static TypeReflection>, pub ty_id: TypeId, pub name: &'static str, } #[macro_export] macro_rules! pair { (Wildcard, $target: tt) => { { let pair: $crate::pair::Pair<(), ()> = std::compile_error!( "Use shorthand * instead of Wildcard as relation" ); pair } }; ($relation: tt, Wildcard) => { { let pair: $crate::pair::Pair<(), ()> = std::compile_error!( "Use shorthand * instead of Wildcard as target" ); pair } }; (={ $relation: tt }, ={ $target: tt }) => { { let pair: $crate::pair::Pair<(), ()> = std::compile_error!( "Cannot use both relation and target as pair data" ); pair } }; ($relation: tt, $target: tt) => { { #[allow(dead_code)] fn get_type_uid() -> $crate::uid::Uid { T::uid() } let builder = $crate::pair::Pair::builder(); $crate::pair!(@set_member_in_builder, builder, relation, $relation); $crate::pair!(@set_member_in_builder, builder, target, $target); builder.build() } }; (@set_member_in_builder, $builder: ident, $member: ident, *) => { $crate::pair::__private::paste! { let $builder = $builder.[<$member _id>]($crate::uid::Uid::wildcard()); } }; (@set_member_in_builder, $builder: ident, $member: ident, $src: ty) => { let $builder = $builder.$member::<$src>(); }; (@set_member_in_builder, $builder: ident, $member: ident, { $src: expr }) => { $crate::pair::__private::paste! { let $builder = $builder.[<$member _id>]($src); } }; (@set_member_in_builder, $builder: ident, $member: ident, ={ $src: expr }) => { $crate::pair::__private::paste! { let $builder = $builder.[<$member _as_data>]($src); } }; } #[doc(hidden)] pub mod __private { pub use paste::paste; } mod sealed { pub trait Sealed {} }