summaryrefslogtreecommitdiff
path: root/ecs/src/pair.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ecs/src/pair.rs')
-rw-r--r--ecs/src/pair.rs201
1 files changed, 201 insertions, 0 deletions
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<RelationElem: Element, TargetElem: Element>
+{
+ relation: RelationElem,
+ target: TargetElem,
+}
+
+impl Pair<Uid, Uid>
+{
+ pub fn new<Relation: WithUid>(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<Uid, Uid>
+{
+ fn into_parts(self) -> ComponentParts
+ {
+ ComponentParts::builder().name("Pair").build(self.id(), ())
+ }
+}
+
+impl<Relation, Target> QueryTermWithField for Pair<Relation, Target>
+where
+ Relation: WithUid,
+ Target: WithUid,
+{
+ type Field<'a> = Handle<'a>;
+
+ 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 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<Relation, Target> WithUid for Pair<Relation, Target>
+where
+ Relation: WithUid,
+ Target: WithUid,
+{
+ fn uid() -> Uid
+ {
+ Uid::new_pair(UidPairParams {
+ relation: Relation::uid(),
+ target: Target::uid(),
+ })
+ }
+}
+
+impl<Relation> QueryTermWithField for &'static [Pair<Relation, Wildcard>]
+where
+ Relation: WithUid,
+{
+ type Field<'a> = HandleIter<'a>;
+
+ fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
+ terms_builder: &mut QueryTermsBuilder<MAX_TERM_CNT>,
+ )
+ {
+ terms_builder.with_required([Pair::<Relation, Wildcard>::uid()]);
+ }
+
+ fn get_field<'world>(
+ entity_handle: &EntityHandle<'world>,
+ world: &'world World,
+ ) -> Self::Field<'world>
+ {
+ HandleIter {
+ inner: entity_handle
+ .get_matching_components(Pair::<Relation, Wildcard>::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<EntityHandle<'_>>
+ {
+ 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<Self::Item>
+ {
+ 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<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;
+
+/// Relation denoting being the child of another entity.
+#[derive(Debug, Default, Clone, Copy, Component)]
+pub struct ChildOf;
+
+mod sealed
+{
+ pub trait Sealed {}
+}