From 8022e8998290b067b8aa0cb9cba8ba410826bdab Mon Sep 17 00:00:00 2001 From: HampusM Date: Thu, 21 May 2026 17:55:20 +0200 Subject: chore: rename ecs* crates to engine-ecs* --- engine-ecs/src/pair.rs | 687 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 687 insertions(+) create mode 100644 engine-ecs/src/pair.rs (limited to 'engine-ecs/src/pair.rs') diff --git a/engine-ecs/src/pair.rs b/engine-ecs/src/pair.rs new file mode 100644 index 0000000..0d353e3 --- /dev/null +++ b/engine-ecs/src/pair.rs @@ -0,0 +1,687 @@ +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::{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 Builder +{ + relation: Relation, + target: Target, +} + +impl Builder +{ + pub fn relation(self) -> Builder + { + Builder { + relation: NewRelation::id(), + target: self.target, + } + } + + pub fn relation_id(self, id: Uid) -> Builder + { + Builder { relation: id, target: self.target } + } + + pub fn target(self) -> Builder + { + Builder { + relation: self.relation, + target: NewTarget::id(), + } + } + + pub fn target_id(self, id: Uid) -> Builder + { + Builder { relation: self.relation, target: id } + } +} + +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, + } + } + } +); + +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, + } + } + } +); + +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 + } + } + } +); + +impl Default for Builder<(), ()> +{ + fn default() -> Self + { + Self { relation: (), target: () } + } +} + +#[derive(Debug)] +pub struct Pair +{ + relation: Relation, + target: Target, +} + +impl Pair<(), ()> +{ + #[must_use] + pub fn builder() -> Builder<(), ()> + { + Builder { relation: (), target: () } + } +} + +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 + { + 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 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") + .build(id, self.relation) + } +} + +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([Pair::::uid()]); + } + + fn get_field<'world>( + entity_handle: &EntityHandle<'world>, + _world: &'world World, + ) -> Self::Field<'world> + { + let target_component = entity_handle + .get_matching_components(Pair::::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([Pair::::uid()]); + } + + fn get_field<'world>( + entity_handle: &EntityHandle<'world>, + world: &'world World, + ) -> Self::Field<'world> + { + let target_component = entity_handle + .get_matching_components(Pair::::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::() + ); + }, + ) + } +} + +// TODO: implement QueryTermWithField for Pair<&Relation, Target> (or equivalent) +// TODO: implement QueryTermWithField for Pair<&mut Relation, Target> (or equivalent) + +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::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 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<'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_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<'world, Relation> WithWildcard<'world, 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_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 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<'world, Relation, Target> MultipleWithWildcard<'world, 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: &'world World, entity_handle: EntityHandle<'world>) -> 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 {} + +mod sealed +{ + pub trait Sealed {} +} -- cgit v1.2.3-18-g5258