summaryrefslogtreecommitdiff
path: root/ecs/src/pair.rs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2025-08-20 14:17:14 +0200
committerHampusM <hampus@hampusmat.com>2025-08-20 14:17:14 +0200
commit5c9113431ea22c53cc59324c93ec3dc6efdfe926 (patch)
tree3218de3310339878a25b26ac957e0b2d54e7be49 /ecs/src/pair.rs
parentfb9263ff3fd6211d5ca19e182094e25835886503 (diff)
feat(ecs): add support for pairs with target component as data
Diffstat (limited to 'ecs/src/pair.rs')
-rw-r--r--ecs/src/pair.rs198
1 files changed, 157 insertions, 41 deletions
diff --git a/ecs/src/pair.rs b/ecs/src/pair.rs
index 4ff4995..77b6da7 100644
--- a/ecs/src/pair.rs
+++ b/ecs/src/pair.rs
@@ -1,6 +1,12 @@
+use std::any::type_name;
use std::convert::Infallible;
-use crate::component::{IntoParts as IntoComponentParts, Parts as ComponentParts};
+use crate::component::{
+ Handle as ComponentHandle,
+ HandleMut as ComponentHandleMut,
+ IntoParts as IntoComponentParts,
+ Parts as ComponentParts,
+};
use crate::entity::{
Handle as EntityHandle,
MatchingComponentIter as EntityMatchingComponentIter,
@@ -10,22 +16,22 @@ use crate::query::{
TermsBuilder as QueryTermsBuilder,
TermsBuilderInterface,
};
-use crate::uid::{PairParams as UidPairParams, Uid, Wildcard, With as WithUid};
+use crate::uid::{PairParams as UidPairParams, Uid, With as WithUid};
use crate::{Component, World};
#[derive(Debug)]
-pub struct Pair<RelationElem: Element, TargetElem: Element>
+pub struct Pair<Relation, Target>
{
- relation: RelationElem,
- target: TargetElem,
+ relation: Relation,
+ target: Target,
}
impl Pair<Uid, Uid>
{
#[must_use]
- pub fn new<Relation: WithUid>(target: Uid) -> Self
+ pub fn new<Relation: Component>(target: Uid) -> Self
{
- Self { relation: Relation::uid(), target }
+ Self { relation: Relation::id(), target }
}
#[must_use]
@@ -38,6 +44,20 @@ impl Pair<Uid, Uid>
}
}
+impl<Target> Pair<Uid, Target>
+where
+ Target: Component,
+{
+ /// Returns a new pair that contains the target component as data.
+ pub fn new_with_comp_target<Relation: Component>(target_component: Target) -> Self
+ {
+ Self {
+ relation: Relation::uid(),
+ target: target_component,
+ }
+ }
+}
+
impl IntoComponentParts for Pair<Uid, Uid>
{
fn into_parts(self) -> ComponentParts
@@ -46,12 +66,94 @@ impl IntoComponentParts for Pair<Uid, Uid>
}
}
-impl<Relation, Target> QueryTermWithField for Pair<Relation, Target>
+impl<Target> IntoComponentParts for Pair<Uid, Target>
+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<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([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::<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([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::<Target>()
+ );
+ })
+ }
+}
+
+impl<Relation> QueryTermWithField for Pair<Relation, Wildcard>
where
- Relation: WithUid,
- Target: WithUid,
+ Relation: Component,
{
- type Field<'a> = Handle<'a>;
+ type Field<'a> = EntityTargetHandle<'a>;
fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
terms_builder: &mut QueryTermsBuilder<MAX_TERM_CNT>,
@@ -70,17 +172,17 @@ where
.next()
.expect("Not possible");
- Handle {
+ EntityTargetHandle {
world,
pair_uid: first_matching_comp.id(),
}
}
}
-impl<Relation, Target> WithUid for Pair<Relation, Target>
+impl<Relation, Target> WithUid for Pair<Relation, &Target>
where
- Relation: WithUid,
- Target: WithUid,
+ Relation: Component,
+ Target: Component,
{
fn uid() -> Uid
{
@@ -91,9 +193,36 @@ where
}
}
+impl<Relation, Target> WithUid for Pair<Relation, &mut Target>
+where
+ Relation: Component,
+ Target: Component,
+{
+ fn uid() -> Uid
+ {
+ Uid::new_pair(&UidPairParams {
+ relation: Relation::uid(),
+ target: Target::uid(),
+ })
+ }
+}
+
+impl<Relation> WithUid for Pair<Relation, Wildcard>
+where
+ Relation: Component,
+{
+ fn uid() -> Uid
+ {
+ Uid::new_pair(&UidPairParams {
+ relation: Relation::uid(),
+ target: Wildcard::uid(),
+ })
+ }
+}
+
impl<Relation> QueryTermWithField for &'static [Pair<Relation, Wildcard>]
where
- Relation: WithUid,
+ Relation: Component,
{
type Field<'a> = HandleIter<'a>;
@@ -117,13 +246,13 @@ where
}
}
-pub struct Handle<'world>
+pub struct EntityTargetHandle<'world>
{
world: &'world World,
pair_uid: Uid,
}
-impl Handle<'_>
+impl EntityTargetHandle<'_>
{
#[must_use]
pub fn get_target_entity(&self) -> Option<EntityHandle<'_>>
@@ -152,38 +281,19 @@ pub struct HandleIter<'a>
impl<'a> Iterator for HandleIter<'a>
{
- type Item = Handle<'a>;
+ type Item = EntityTargetHandle<'a>;
fn next(&mut self) -> Option<Self::Item>
{
let matching_comp = self.inner.next()?;
- Some(Handle {
+ Some(EntityTargetHandle {
world: self.world,
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<WithUidT: WithUid> Element for WithUidT
-{
- type Value = Infallible;
-}
-
-impl<WithUidT: WithUid> sealed::Sealed for WithUidT {}
-
/// Relation denoting a dependency to another entity
#[derive(Debug, Default, Clone, Copy, Component)]
pub struct DependsOn;
@@ -192,7 +302,13 @@ pub struct DependsOn;
#[derive(Debug, Default, Clone, Copy, Component)]
pub struct ChildOf;
-mod sealed
+#[derive(Debug)]
+pub struct Wildcard(Infallible);
+
+impl Wildcard
{
- pub trait Sealed {}
+ pub fn uid() -> Uid
+ {
+ Uid::wildcard()
+ }
}