summaryrefslogtreecommitdiff
path: root/ecs
diff options
context:
space:
mode:
Diffstat (limited to 'ecs')
-rw-r--r--ecs/examples/component_relationship.rs56
-rw-r--r--ecs/examples/relationship.rs3
-rw-r--r--ecs/src/lib.rs4
-rw-r--r--ecs/src/pair.rs198
-rw-r--r--ecs/src/uid.rs13
5 files changed, 217 insertions, 57 deletions
diff --git a/ecs/examples/component_relationship.rs b/ecs/examples/component_relationship.rs
new file mode 100644
index 0000000..4453e3a
--- /dev/null
+++ b/ecs/examples/component_relationship.rs
@@ -0,0 +1,56 @@
+use ecs::pair::Pair;
+use ecs::phase::START as START_PHASE;
+use ecs::{Component, Query, World};
+
+#[derive(Component)]
+struct Person
+{
+ name: String,
+}
+
+fn print_dog_likers(query: Query<(&Person, Pair<Likes, &Dogs>)>)
+{
+ for (person, liked_dogs) in &query {
+ println!(
+ "{} likes {} dogs!",
+ person.name,
+ if liked_dogs.large { "large" } else { "small" },
+ );
+ }
+}
+
+#[derive(Component)]
+struct Likes;
+
+#[derive(Component)]
+struct Cats;
+
+#[derive(Component)]
+struct Dogs
+{
+ large: bool,
+}
+
+fn main()
+{
+ let mut world = World::new();
+
+ world.register_system(*START_PHASE, print_dog_likers);
+
+ world.create_entity((
+ Person { name: "Irving".to_string() },
+ Pair::new_with_comp_target::<Likes>(Dogs { large: true }),
+ ));
+
+ world.create_entity((
+ Person { name: "Mark".to_string() },
+ Pair::new_with_comp_target::<Likes>(Cats),
+ ));
+
+ world.create_entity((
+ Person { name: "Helena".to_string() },
+ Pair::new_with_comp_target::<Likes>(Dogs { large: false }),
+ ));
+
+ world.step();
+}
diff --git a/ecs/examples/relationship.rs b/ecs/examples/relationship.rs
index b607398..f99d090 100644
--- a/ecs/examples/relationship.rs
+++ b/ecs/examples/relationship.rs
@@ -1,6 +1,5 @@
-use ecs::pair::Pair;
+use ecs::pair::{Pair, Wildcard};
use ecs::phase::START as START_PHASE;
-use ecs::uid::Wildcard;
use ecs::{Component, Query, World};
#[derive(Component)]
diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs
index 979b517..fa31460 100644
--- a/ecs/src/lib.rs
+++ b/ecs/src/lib.rs
@@ -25,7 +25,7 @@ use crate::event::component::{
};
use crate::extension::{Collector as ExtensionCollector, Extension};
use crate::lock::Lock;
-use crate::pair::{ChildOf, DependsOn, Pair};
+use crate::pair::{ChildOf, DependsOn, Pair, Wildcard};
use crate::phase::{Phase, START as START_PHASE};
use crate::query::flexible::Query as FlexibleQuery;
use crate::query::term::Without;
@@ -39,7 +39,7 @@ use crate::query::{
use crate::sole::Sole;
use crate::stats::Stats;
use crate::system::{System, SystemComponent};
-use crate::uid::{Kind as UidKind, Uid, Wildcard};
+use crate::uid::{Kind as UidKind, Uid};
pub mod actions;
pub mod component;
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()
+ }
}
diff --git a/ecs/src/uid.rs b/ecs/src/uid.rs
index feed62c..a361882 100644
--- a/ecs/src/uid.rs
+++ b/ecs/src/uid.rs
@@ -218,7 +218,7 @@ pub struct PairParams
pub target: Uid,
}
-pub trait With: 'static
+pub trait With
{
fn uid() -> Uid;
}
@@ -230,14 +230,3 @@ impl<ComponentT: Component> With for ComponentT
Self::id()
}
}
-
-#[derive(Debug)]
-pub enum Wildcard {}
-
-impl With for Wildcard
-{
- fn uid() -> Uid
- {
- Uid::wildcard()
- }
-}