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.rs595
1 files changed, 542 insertions, 53 deletions
diff --git a/ecs/src/pair.rs b/ecs/src/pair.rs
index 4ff4995..b4bfa57 100644
--- a/ecs/src/pair.rs
+++ b/ecs/src/pair.rs
@@ -1,6 +1,14 @@
+use std::any::type_name;
use std::convert::Infallible;
+use std::marker::PhantomData;
-use crate::component::{IntoParts as IntoComponentParts, Parts as ComponentParts};
+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,
@@ -10,24 +18,127 @@ use crate::query::{
TermsBuilder as QueryTermsBuilder,
TermsBuilderInterface,
};
-use crate::uid::{PairParams as UidPairParams, Uid, Wildcard, With as WithUid};
-use crate::{Component, World};
+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 Pair<RelationElem: Element, TargetElem: Element>
+pub struct Builder<Relation, Target>
{
- relation: RelationElem,
- target: TargetElem,
+ relation: Relation,
+ target: Target,
}
-impl Pair<Uid, Uid>
+impl<Relation, Target> Builder<Relation, Target>
+{
+ pub fn relation<NewRelation: Component>(self) -> Builder<Uid, Target>
+ {
+ Builder {
+ relation: NewRelation::id(),
+ target: self.target,
+ }
+ }
+
+ pub fn relation_id(self, id: Uid) -> Builder<Uid, Target>
+ {
+ Builder { relation: id, target: self.target }
+ }
+
+ pub fn target<NewTarget: Component>(self) -> Builder<Relation, Uid>
+ {
+ Builder {
+ relation: self.relation,
+ target: NewTarget::id(),
+ }
+ }
+
+ pub fn target_id(self, id: Uid) -> Builder<Relation, Uid>
+ {
+ Builder { relation: self.relation, target: id }
+ }
+}
+
+impl_multiple!(
+ Builder,
+ (impl<Target> _<><Uid, Target>, impl<Target> _<><(), Target>)
+ cb=(type_params=(ty_param_1, ty_param_2)) => {
+ pub fn target_as_data<NewTarget: Component>(
+ self,
+ data: NewTarget,
+ ) -> Builder<$ty_param_1, NewTarget>
+ {
+ Builder {
+ relation: self.relation,
+ target: data,
+ }
+ }
+ }
+);
+
+impl_multiple!(
+ Builder,
+ (impl<Relation> _<><Relation, Uid>, impl<Relation> _<><Relation, ()>)
+ cb=(type_params=(ty_param_1, ty_param_2)) => {
+ pub fn relation_as_data<NewRelation: Component>(
+ self,
+ data: NewRelation,
+ ) -> Builder<NewRelation, $ty_param_2>
+ {
+ Builder {
+ relation: data,
+ target: self.target,
+ }
+ }
+ }
+);
+
+impl_multiple!(
+ Builder,
+ (
+ impl _<><Uid, Uid>,
+ impl<Relation: Component> _<><Relation, Uid>,
+ impl<Target: Component> _<><Uid, Target>,
+ impl<Relation: Component, Target: Component> _<><Relation, Target>
+ )
+ 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, Target>
+{
+ relation: Relation,
+ target: Target,
+}
+
+impl Pair<(), ()>
{
#[must_use]
- pub fn new<Relation: WithUid>(target: Uid) -> Self
+ pub fn builder() -> Builder<(), ()>
{
- Self { relation: Relation::uid(), target }
+ Builder { relation: (), target: () }
}
+}
+impl Pair<Uid, Uid>
+{
#[must_use]
pub fn id(&self) -> Uid
{
@@ -46,12 +157,116 @@ impl IntoComponentParts for Pair<Uid, Uid>
}
}
-impl<Relation, Target> QueryTermWithField for Pair<Relation, Target>
+impl<Target> IntoComponentParts for Pair<Uid, Target>
where
- Relation: WithUid,
- Target: WithUid,
+ Target: Component,
{
- type Field<'a> = Handle<'a>;
+ 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> IntoComponentParts for Pair<Relation, Uid>
+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<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([Pair::<Relation, Target>::uid()]);
+ }
+
+ fn get_field<'world>(
+ entity_handle: &EntityHandle<'world>,
+ _world: &'world World,
+ ) -> Self::Field<'world>
+ {
+ let target_component = entity_handle
+ .get_matching_components(Pair::<Relation, Target>::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([Pair::<Relation, Target>::uid()]);
+ }
+
+ fn get_field<'world>(
+ entity_handle: &EntityHandle<'world>,
+ world: &'world World,
+ ) -> Self::Field<'world>
+ {
+ let target_component = entity_handle
+ .get_matching_components(Pair::<Relation, Target>::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::<Target>()
+ );
+ },
+ )
+ }
+}
+
+// TODO: implement QueryTermWithField for Pair<&Relation, Target> (or equivalent)
+// TODO: implement QueryTermWithField for Pair<&mut Relation, Target> (or equivalent)
+
+impl<Relation> QueryTermWithField for Pair<Relation, Wildcard>
+where
+ Relation: Component,
+{
+ type Field<'a> = WithWildcard<'a, Relation, Wildcard>;
fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
terms_builder: &mut QueryTermsBuilder<MAX_TERM_CNT>,
@@ -70,38 +285,51 @@ where
.next()
.expect("Not possible");
- Handle {
+ WithWildcard {
world,
- pair_uid: first_matching_comp.id(),
+ component_ref: first_matching_comp,
+ _pd: PhantomData,
}
}
}
impl<Relation, Target> WithUid for Pair<Relation, Target>
where
- Relation: WithUid,
- Target: WithUid,
+ Relation: Component,
+ Target: Component,
{
fn uid() -> Uid
{
Uid::new_pair(&UidPairParams {
- relation: Relation::uid(),
- target: Target::uid(),
+ relation: Relation::id(),
+ target: Target::id(),
})
}
}
-impl<Relation> QueryTermWithField for &'static [Pair<Relation, Wildcard>]
+impl<Relation> WithUid for Pair<Relation, Wildcard>
where
- Relation: WithUid,
+ Relation: Component,
{
- type Field<'a> = HandleIter<'a>;
+ fn uid() -> Uid
+ {
+ Uid::new_pair(&UidPairParams {
+ relation: Relation::id(),
+ target: Wildcard::uid(),
+ })
+ }
+}
+
+impl<Relation> QueryTermWithField for &'_ [Pair<Relation, Wildcard>]
+where
+ Relation: Component,
+{
+ type Field<'a> = MultipleWithWildcard<'a, Relation, Wildcard>;
fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
- terms_builder: &mut QueryTermsBuilder<MAX_TERM_CNT>,
+ _terms_builder: &mut QueryTermsBuilder<MAX_TERM_CNT>,
)
{
- terms_builder.with_required([Pair::<Relation, Wildcard>::uid()]);
}
fn get_field<'world>(
@@ -109,80 +337,304 @@ where
world: &'world World,
) -> Self::Field<'world>
{
- HandleIter {
- inner: entity_handle
- .get_matching_components(Pair::<Relation, Wildcard>::uid()),
+ MultipleWithWildcard {
+ entity_handle: entity_handle.clone(),
world,
+ _pd: PhantomData,
}
}
}
-pub struct Handle<'world>
+/// Reference to a pair with a wildcard relation/target.
+#[derive(Debug)]
+pub struct WithWildcard<'world, Relation, Target>
{
world: &'world World,
- pair_uid: Uid,
+ component_ref: EntityComponentRef<'world>,
+ _pd: PhantomData<(Relation, Target)>,
}
-impl Handle<'_>
+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_target_entity(&self) -> Option<EntityHandle<'_>>
+ pub fn get_data<Data>(&self) -> Option<ComponentHandle<'_, Data>>
+ where
+ Data: 'static,
+ {
+ ComponentHandle::<Data>::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::<Data>()
+ );
+ }
+ },
+ 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<Data>(&self) -> Option<ComponentHandleMut<'_, Data>>
+ where
+ Data: 'static,
+ {
+ ComponentHandleMut::<Data>::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::<Data>()
+ );
+ }
+ },
+ Some,
+ )
+ }
+}
+
+impl<Relation> WithWildcard<'_, 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<EntityHandle<'_>>
{
let archetype = self
.world
.data
.component_storage
- .get_entity_archetype(self.pair_uid.target_entity())?;
+ .get_entity_archetype(self.component_ref.id().target_entity())?;
let Some(archetype_entity) =
- archetype.get_entity_by_id(self.pair_uid.target_entity())
+ archetype.get_entity_by_id(self.component_ref.id().target_entity())
else {
unreachable!();
};
- Some(EntityHandle::new(archetype, archetype_entity))
+ 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<'_, Relation>>
+ {
+ ComponentHandle::<Relation>::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::<Relation>()
+ );
+ }
+ },
+ 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<'_, Relation>>
+ {
+ ComponentHandleMut::<Relation>::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::<Relation>()
+ );
+ }
+ },
+ Some,
+ )
}
}
-pub struct HandleIter<'a>
+/// Used to access matching pairs in a entity containing zero or more matching pairs.
+#[derive(Debug)]
+pub struct MultipleWithWildcard<'a, Relation, Target>
{
- inner: EntityMatchingComponentIter<'a>,
+ entity_handle: EntityHandle<'a>,
world: &'a World,
+ _pd: PhantomData<(Relation, Target)>,
}
-impl<'a> Iterator for HandleIter<'a>
+impl<'world, Relation, Target> MultipleWithWildcard<'world, Relation, Target>
{
- type Item = Handle<'a>;
-
- fn next(&mut self) -> Option<Self::Item>
+ /// 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,
{
- let matching_comp = self.inner.next()?;
+ assert!(Relation::uid() == Wildcard::uid() || Target::uid() == Wildcard::uid());
+
+ assert!(
+ !(Relation::uid() == Wildcard::uid() && Target::uid() == Wildcard::uid())
+ );
- Some(Handle {
+ 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<WithWildcard<'a, Relation, Wildcard>>
+ {
+ Some(WithWildcard {
world: self.world,
- pair_uid: matching_comp.id(),
+ component_ref: self
+ .entity_handle
+ .get_matching_components(
+ Pair::builder()
+ .relation::<Relation>()
+ .target_id(target_id)
+ .build()
+ .id(),
+ )
+ .next()?,
+ _pd: PhantomData,
})
}
}
-pub trait Element: sealed::Sealed
+impl<'a, Relation: Component> IntoIterator
+ for MultipleWithWildcard<'a, Relation, Wildcard>
{
- type Value;
+ type IntoIter = WithWildcardIter<'a, Relation, Wildcard>;
+ type Item = <Self::IntoIter as Iterator>::Item;
+
+ fn into_iter(self) -> Self::IntoIter
+ {
+ WithWildcardIter {
+ inner: self
+ .entity_handle
+ .get_matching_components(Pair::<Relation, Wildcard>::uid()),
+ world: self.world,
+ _pd: PhantomData,
+ }
+ }
}
-impl Element for Uid
+/// Iterator of matching pairs in a entity.
+pub struct WithWildcardIter<'a, Relation, Target>
{
- type Value = Uid;
+ inner: EntityMatchingComponentIter<'a>,
+ world: &'a World,
+ _pd: PhantomData<(Relation, Target)>,
}
-impl sealed::Sealed for Uid {}
-
-impl<WithUidT: WithUid> Element for WithUidT
+impl<'a, Relation, Target> Iterator for WithWildcardIter<'a, Relation, Target>
{
- type Value = Infallible;
-}
+ type Item = WithWildcard<'a, Relation, Target>;
-impl<WithUidT: WithUid> sealed::Sealed for WithUidT {}
+ fn next(&mut self) -> Option<Self::Item>
+ {
+ 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)]
@@ -192,6 +644,43 @@ pub struct DependsOn;
#[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<ComponentT: Component> ComponentOrWildcard for ComponentT
+{
+ fn uid() -> Uid
+ {
+ ComponentT::id()
+ }
+}
+
+impl<ComponentT: Component> sealed::Sealed for ComponentT {}
+
+impl ComponentOrWildcard for Wildcard
+{
+ fn uid() -> Uid
+ {
+ Wildcard::uid()
+ }
+}
+
+impl sealed::Sealed for Wildcard {}
+
mod sealed
{
pub trait Sealed {}