From 94e5e592baea2935af7c94ad44805a09d0e30740 Mon Sep 17 00:00:00 2001 From: HampusM Date: Wed, 9 Apr 2025 20:50:14 +0200 Subject: feat(ecs): replace Relationship component with pair UID support --- ecs/src/pair.rs | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 ecs/src/pair.rs (limited to 'ecs/src/pair.rs') diff --git a/ecs/src/pair.rs b/ecs/src/pair.rs new file mode 100644 index 0000000..27e535e --- /dev/null +++ b/ecs/src/pair.rs @@ -0,0 +1,201 @@ +use std::convert::Infallible; + +use crate::component::storage::Storage as ComponentStorage; +use crate::component::{IntoParts as IntoComponentParts, Parts as ComponentParts}; +use crate::entity::{ + Handle as EntityHandle, + MatchingComponentIter as EntityMatchingComponentIter, +}; +use crate::lock::ReadGuard; +use crate::query::{ + TermWithField as QueryTermWithField, + TermsBuilder as QueryTermsBuilder, + TermsBuilderInterface, +}; +use crate::uid::{PairParams as UidPairParams, Uid, Wildcard, With as WithUid}; +use crate::{Component, World}; + +#[derive(Debug)] +pub struct Pair +{ + relation: RelationElem, + target: TargetElem, +} + +impl Pair +{ + pub fn new(target: Uid) -> Self + { + Self { relation: Relation::uid(), target } + } + + 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 QueryTermWithField for Pair +where + Relation: WithUid, + Target: WithUid, +{ + type Field<'a> = Handle<'a>; + + 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"); + + Handle { + world, + component_storage_lock: world.data.component_storage.read_nonblock().unwrap(), + pair_uid: first_matching_comp.id(), + } + } +} + +impl WithUid for Pair +where + Relation: WithUid, + Target: WithUid, +{ + fn uid() -> Uid + { + Uid::new_pair(UidPairParams { + relation: Relation::uid(), + target: Target::uid(), + }) + } +} + +impl QueryTermWithField for &'static [Pair] +where + Relation: WithUid, +{ + type Field<'a> = HandleIter<'a>; + + 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> + { + HandleIter { + inner: entity_handle + .get_matching_components(Pair::::uid()), + world, + } + } +} + +pub struct Handle<'world> +{ + world: &'world World, + component_storage_lock: ReadGuard<'world, ComponentStorage>, + pair_uid: Uid, +} + +impl Handle<'_> +{ + pub fn get_target_entity(&self) -> Option> + { + let archetype = self + .component_storage_lock + .get_entity_archetype(self.pair_uid.target_entity())?; + + let archetype_entity = archetype + .get_entity_by_id(self.pair_uid.target_entity()) + .expect("Not possible"); + + Some(EntityHandle::new(self.world, archetype, archetype_entity)) + } +} + +pub struct HandleIter<'a> +{ + inner: EntityMatchingComponentIter<'a>, + world: &'a World, +} + +impl<'a> Iterator for HandleIter<'a> +{ + type Item = Handle<'a>; + + fn next(&mut self) -> Option + { + let matching_comp = self.inner.next()?; + + Some(Handle { + world: self.world, + component_storage_lock: self + .world + .data + .component_storage + .read_nonblock() + .unwrap(), + pair_uid: matching_comp.id(), + }) + } +} + +pub trait Element: sealed::Sealed +{ + type Value; +} + +impl Element for Uid +{ + type Value = Uid; +} + +impl sealed::Sealed for Uid {} + +impl Element for WithUidT +{ + type Value = Infallible; +} + +impl sealed::Sealed for WithUidT {} + +/// 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; + +mod sealed +{ + pub trait Sealed {} +} -- cgit v1.2.3-18-g5258