summaryrefslogtreecommitdiff
path: root/engine-ecs/src/pair.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine-ecs/src/pair.rs')
-rw-r--r--engine-ecs/src/pair.rs946
1 files changed, 946 insertions, 0 deletions
diff --git a/engine-ecs/src/pair.rs b/engine-ecs/src/pair.rs
new file mode 100644
index 0000000..834077c
--- /dev/null
+++ b/engine-ecs/src/pair.rs
@@ -0,0 +1,946 @@
+use std::any::{type_name, TypeId};
+use std::convert::Infallible;
+use std::marker::PhantomData;
+
+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,
+};
+use crate::query::{
+ SearchResult,
+ Term as QueryTerm,
+ TermMetadata as QueryTermMetadata,
+ TermsBuilder as QueryTermsBuilder,
+ TermsBuilderInterface,
+};
+use crate::reflection::Type as TypeReflection;
+use crate::uid::{PairParams as UidPairParams, Uid, With as WithUid};
+use crate::util::impl_multiple;
+use crate::{Component, EntityComponentRef, World};
+
+/// Pair builder.
+#[derive(Debug)]
+pub struct Builder<Relation, Target>
+{
+ relation: Relation,
+ target: Target,
+ relation_metadata: Option<MemberMetadata>,
+ target_metadata: Option<MemberMetadata>,
+}
+
+impl<Relation, Target> Builder<Relation, Target>
+{
+ pub fn relation<NewRelation: Component>(self) -> Builder<Uid, Target>
+ {
+ Builder {
+ relation: NewRelation::id(),
+ target: self.target,
+ relation_metadata: Some(MemberMetadata {
+ ty: NewRelation::type_reflection(),
+ ty_id: TypeId::of::<NewRelation>(),
+ name: type_name::<NewRelation>(),
+ is_sole: false,
+ }),
+ target_metadata: self.target_metadata,
+ }
+ }
+
+ pub fn relation_id(self, id: Uid) -> Builder<Uid, Target>
+ {
+ Builder {
+ relation: id,
+ target: self.target,
+ relation_metadata: None,
+ target_metadata: self.target_metadata,
+ }
+ }
+
+ pub fn target<NewTarget: Component>(self) -> Builder<Relation, Uid>
+ {
+ Builder {
+ relation: self.relation,
+ target: NewTarget::id(),
+ relation_metadata: self.relation_metadata,
+ target_metadata: Some(MemberMetadata {
+ ty: NewTarget::type_reflection(),
+ ty_id: TypeId::of::<NewTarget>(),
+ name: type_name::<NewTarget>(),
+ is_sole: false,
+ }),
+ }
+ }
+
+ pub fn target_id(self, id: Uid) -> Builder<Relation, Uid>
+ {
+ Builder {
+ relation: self.relation,
+ target: id,
+ relation_metadata: self.relation_metadata,
+ target_metadata: None,
+ }
+ }
+}
+
+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,
+ relation_metadata: self.relation_metadata,
+ target_metadata: Some(MemberMetadata {
+ ty: NewTarget::type_reflection(),
+ ty_id: TypeId::of::<NewTarget>(),
+ name: type_name::<NewTarget>(),
+ is_sole: false,
+ }),
+ }
+ }
+ }
+);
+
+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,
+ relation_metadata: Some(MemberMetadata {
+ ty: NewRelation::type_reflection(),
+ ty_id: TypeId::of::<NewRelation>(),
+ name: type_name::<NewRelation>(),
+ is_sole: false,
+ }),
+ target_metadata: self.target_metadata,
+ }
+ }
+ }
+);
+
+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,
+ relation_metadata: self.relation_metadata,
+ target_metadata: self.target_metadata,
+ }
+ }
+ }
+);
+
+impl Default for Builder<(), ()>
+{
+ fn default() -> Self
+ {
+ Self {
+ relation: (),
+ target: (),
+ relation_metadata: None,
+ target_metadata: None,
+ }
+ }
+}
+
+#[derive(Debug)]
+pub struct Pair<Relation, Target>
+{
+ relation: Relation,
+ target: Target,
+ relation_metadata: Option<MemberMetadata>,
+ target_metadata: Option<MemberMetadata>,
+}
+
+impl Pair<(), ()>
+{
+ #[must_use]
+ pub fn builder() -> Builder<(), ()>
+ {
+ Builder::default()
+ }
+}
+
+impl Pair<Uid, Uid>
+{
+ #[must_use]
+ 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
+ {
+ let id = self.id();
+
+ ComponentParts::builder()
+ .name("Pair")
+ .pair_relation_metadata(self.relation_metadata)
+ .pair_target_metadata(self.target_metadata)
+ .build(id, ())
+ }
+}
+
+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")
+ .pair_relation_metadata(self.relation_metadata)
+ .pair_target_metadata(self.target_metadata)
+ .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")
+ .pair_relation_metadata(self.relation_metadata)
+ .pair_target_metadata(self.target_metadata)
+ .build(id, self.relation)
+ }
+}
+
+impl<'query, Relation, Target> QueryTerm<'query> for Pair<Relation, &Target>
+where
+ Relation: Component,
+ Target: Component,
+{
+ type Fields = (ComponentHandle<'query, Target>,);
+
+ fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
+ terms_builder: &mut QueryTermsBuilder<MAX_TERM_CNT>,
+ _term_metadata: QueryTermMetadata,
+ )
+ {
+ terms_builder.present([Pair::<Relation, Target>::uid()]);
+ }
+
+ fn fields(
+ _world: &'query World,
+ search_result: &SearchResult<'query, '_>,
+ _term_metadata: QueryTermMetadata,
+ ) -> Self::Fields
+ {
+ let target_component = search_result
+ .entity_handle
+ .get_matching_components(Pair::<Relation, Target>::uid())
+ .next()
+ .expect("Not possible");
+
+ let target_component =
+ match ComponentHandle::<Target>::from_entity_component_ref(&target_component)
+ {
+ Ok(target_component) => target_component,
+ Err(err) => {
+ panic!(
+ "Creating handle to target component {} failed: {err}",
+ type_name::<Target>()
+ );
+ }
+ };
+
+ (target_component,)
+ }
+}
+
+impl<'query, Relation, Target> QueryTerm<'query> for Pair<Relation, &mut Target>
+where
+ Relation: Component,
+ Target: Component,
+{
+ type Fields = (ComponentHandleMut<'query, Target>,);
+
+ fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
+ terms_builder: &mut QueryTermsBuilder<MAX_TERM_CNT>,
+ _term_metadata: QueryTermMetadata,
+ )
+ {
+ terms_builder.present([Pair::<Relation, Target>::uid()]);
+ }
+
+ fn fields(
+ world: &'query World,
+ search_result: &SearchResult<'query, '_>,
+ _term_metadata: QueryTermMetadata,
+ ) -> Self::Fields
+ {
+ let target_component = search_result
+ .entity_handle
+ .get_matching_components(Pair::<Relation, Target>::uid())
+ .next()
+ .expect("Not possible");
+
+ let target_component =
+ match ComponentHandleMut::<Target>::from_entity_component_ref(
+ &target_component,
+ world,
+ ) {
+ Ok(target_component) => target_component,
+ Err(err) => {
+ panic!(
+ "Creating mut handle to target component {} failed: {err}",
+ type_name::<Target>()
+ );
+ }
+ };
+
+ (target_component,)
+ }
+}
+
+// TODO: implement QueryTerm for Pair<&Relation, Target> (or equivalent)
+// TODO: implement QueryTerm for Pair<&mut Relation, Target> (or equivalent)
+
+impl<'query, Relation> QueryTerm<'query> for Pair<Relation, Wildcard>
+where
+ Relation: Component,
+{
+ type Fields = (WithWildcard<'query, Relation, Wildcard>,);
+
+ fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
+ terms_builder: &mut QueryTermsBuilder<MAX_TERM_CNT>,
+ _term_metadata: QueryTermMetadata,
+ )
+ {
+ terms_builder.present([Self::uid()]);
+ }
+
+ fn fields(
+ world: &'query World,
+ search_result: &SearchResult<'query, '_>,
+ _term_metadata: QueryTermMetadata,
+ ) -> Self::Fields
+ {
+ let first_matching_comp = search_result
+ .entity_handle
+ .get_matching_components(Self::uid())
+ .next()
+ .expect("Not possible");
+
+ (WithWildcard {
+ world,
+ component_ref: first_matching_comp,
+ _pd: PhantomData,
+ },)
+ }
+}
+
+impl<Relation, Target> WithUid for Pair<Relation, Target>
+where
+ Relation: Component,
+ Target: Component,
+{
+ fn uid() -> Uid
+ {
+ Uid::new_pair(&UidPairParams {
+ relation: Relation::id(),
+ target: Target::id(),
+ })
+ }
+}
+
+impl<Relation> WithUid for Pair<Relation, Wildcard>
+where
+ Relation: Component,
+{
+ fn uid() -> Uid
+ {
+ Uid::new_pair(&UidPairParams {
+ relation: Relation::id(),
+ target: Wildcard::uid(),
+ })
+ }
+}
+
+impl<'query, Relation> QueryTerm<'query> for &[Pair<Relation, Wildcard>]
+where
+ Relation: Component,
+{
+ type Fields = (MultipleWithWildcard<'query, Relation, Wildcard>,);
+
+ fn apply_to_terms_builder<const MAX_TERM_CNT: usize>(
+ _terms_builder: &mut QueryTermsBuilder<MAX_TERM_CNT>,
+ _term_metadata: QueryTermMetadata,
+ )
+ {
+ }
+
+ fn fields(
+ world: &'query World,
+ search_result: &SearchResult<'query, '_>,
+ _term_metadata: QueryTermMetadata,
+ ) -> Self::Fields
+ {
+ (MultipleWithWildcard {
+ entity_handle: search_result.entity_handle.clone(),
+ world,
+ _pd: PhantomData,
+ },)
+ }
+}
+
+/// Reference to a pair with a wildcard relation/target.
+#[derive(Debug)]
+pub struct WithWildcard<'query, Relation, Target>
+{
+ world: &'query World,
+ component_ref: EntityComponentRef<'query>,
+ _pd: PhantomData<(Relation, Target)>,
+}
+
+impl<'query, Relation, Target> WithWildcard<'query, 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: &'query World, component_ref: EntityComponentRef<'query>) -> Self
+ where
+ Relation: ComponentOrWildcard,
+ Target: ComponentOrWildcard,
+ {
+ let component_id = component_ref.id();
+
+ assert!(component_id.is_pair());
+
+ assert!(
+ Relation::uid() == Wildcard::uid()
+ || component_id.relation() == Relation::uid()
+ );
+
+ assert!(
+ Target::uid() == Wildcard::uid() || component_id.target() == 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_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<'query, Relation> WithWildcard<'query, 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<'query>>
+ {
+ let archetype = self
+ .world
+ .data
+ .component_storage
+ .get_entity_archetype(self.component_ref.id().target())?;
+
+ let Some(archetype_entity) =
+ archetype.get_entity_by_id(self.component_ref.id().target())
+ else {
+ unreachable!();
+ };
+
+ 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,
+ )
+ }
+}
+
+/// Used to access matching pairs in a entity containing zero or more matching pairs.
+#[derive(Debug)]
+pub struct MultipleWithWildcard<'a, Relation, Target>
+{
+ entity_handle: EntityHandle<'a>,
+ world: &'a World,
+ _pd: PhantomData<(Relation, Target)>,
+}
+
+impl<'query, Relation, Target> MultipleWithWildcard<'query, Relation, Target>
+{
+ /// 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: &'query World, entity_handle: EntityHandle<'query>) -> Self
+ where
+ Relation: ComponentOrWildcard,
+ Target: ComponentOrWildcard,
+ {
+ assert!(Relation::uid() == Wildcard::uid() || Target::uid() == Wildcard::uid());
+
+ assert!(
+ !(Relation::uid() == Wildcard::uid() && Target::uid() == Wildcard::uid())
+ );
+
+ 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,
+ component_ref: self
+ .entity_handle
+ .get_matching_components(
+ Pair::builder()
+ .relation::<Relation>()
+ .target_id(target_id)
+ .build()
+ .id(),
+ )
+ .next()?,
+ _pd: PhantomData,
+ })
+ }
+}
+
+impl<'a, Relation: Component> IntoIterator
+ for MultipleWithWildcard<'a, Relation, Wildcard>
+{
+ 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,
+ }
+ }
+}
+
+/// Iterator of matching pairs in a entity.
+pub struct WithWildcardIter<'a, Relation, Target>
+{
+ inner: EntityMatchingComponentIter<'a>,
+ world: &'a World,
+ _pd: PhantomData<(Relation, Target)>,
+}
+
+impl<'a, Relation, Target> Iterator for WithWildcardIter<'a, Relation, Target>
+{
+ type Item = WithWildcard<'a, Relation, Target>;
+
+ 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)]
+pub struct DependsOn;
+
+/// Relation denoting being the child of another entity.
+#[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 {}
+
+#[derive(Debug, Clone)]
+#[non_exhaustive]
+pub struct MemberMetadata
+{
+ pub ty: Option<&'static TypeReflection>,
+ pub ty_id: TypeId,
+ pub name: &'static str,
+ pub is_sole: bool,
+}
+
+#[macro_export]
+macro_rules! pair {
+
+ (Wildcard, $target: tt) => {
+ {
+ let pair: $crate::pair::Pair<(), ()> = std::compile_error!(
+ "Use shorthand * instead of Wildcard as relation"
+ );
+
+ pair
+ }
+ };
+
+ ($relation: tt, Wildcard) => {
+ {
+ let pair: $crate::pair::Pair<(), ()> = std::compile_error!(
+ "Use shorthand * instead of Wildcard as target"
+ );
+
+ pair
+ }
+ };
+
+ (={ $relation: tt }, ={ $target: tt }) => {
+ {
+ let pair: $crate::pair::Pair<(), ()> = std::compile_error!(
+ "Cannot use both relation and target as pair data"
+ );
+
+ pair
+ }
+ };
+
+ (={ $relation: expr }, $target: tt) => {
+ $crate::pair!(@inner (=, { $relation }), (, $target))
+ };
+
+ ($relation: tt, ={ $target: expr }) => {
+ $crate::pair!(@inner (,$relation), (=, { $target }))
+ };
+
+ ($relation: tt, $target: tt) => {
+ $crate::pair!(@inner (,$relation), (, $target))
+ };
+
+ (
+ @inner
+ (
+ $(=$($relation_eq: literal)?)?,
+ $relation: tt
+ ),
+ (
+ $(=$($target_eq: literal)?)?,
+ $target: tt
+ )
+ ) => {
+ {
+ #[allow(dead_code)]
+ fn get_type_uid<T: $crate::pair::ComponentOrWildcard>()
+ -> $crate::uid::Uid
+ {
+ T::uid()
+ }
+
+ let builder = $crate::pair::Pair::builder();
+
+ $crate::pair!(
+ @set_member_in_builder, builder, relation, $(=$($relation_eq)?)? $relation
+ );
+
+ $crate::pair!(
+ @set_member_in_builder, builder, target, $(=$($target_eq)?)? $target
+ );
+
+ builder.build()
+ }
+ };
+
+ (@set_member_in_builder, $builder: ident, $member: ident, *) => {
+ $crate::pair::__private::paste! {
+ let $builder = $builder.[<$member _id>]($crate::uid::Uid::wildcard());
+ }
+ };
+
+ (@set_member_in_builder, $builder: ident, $member: ident, $src: ty) => {
+ let $builder = $builder.$member::<$src>();
+ };
+
+ (@set_member_in_builder, $builder: ident, $member: ident, { $src: expr }) => {
+ $crate::pair::__private::paste! {
+ let $builder = $builder.[<$member _id>]($src);
+ }
+ };
+
+ (@set_member_in_builder, $builder: ident, $member: ident, ={ $src: expr }) => {
+ $crate::pair::__private::paste! {
+ let $builder = $builder.[<$member _as_data>]($src);
+ }
+ };
+}
+
+#[doc(hidden)]
+pub mod __private
+{
+ pub use paste::paste;
+}
+
+mod sealed
+{
+ pub trait Sealed {}
+}
+
+#[cfg(test)]
+mod tests
+{
+ use crate::pair::ChildOf;
+ use crate::uid::Uid;
+ use crate::Component;
+
+ #[derive(Debug, Component)]
+ struct Foo;
+
+ #[derive(Debug, Component, PartialEq, Eq)]
+ struct Bar
+ {
+ number: u32,
+ }
+
+ #[test]
+ fn macro_works()
+ {
+ let pair_a = pair!(ChildOf, Foo);
+
+ assert_eq!(pair_a.relation, ChildOf::id());
+ assert_eq!(pair_a.target, Foo::id());
+
+ let pair_b = pair!(ChildOf, *);
+
+ assert_eq!(pair_b.relation, ChildOf::id());
+ assert_eq!(pair_b.target, Uid::wildcard());
+
+ let pair_c = pair!(*, Foo);
+
+ assert_eq!(pair_c.relation, Uid::wildcard());
+ assert_eq!(pair_c.target, Foo::id());
+
+ let pair_d = pair!(Foo, ={ Bar { number: 1234 } });
+
+ assert_eq!(pair_d.relation, Foo::id());
+ assert_eq!(pair_d.target, Bar { number: 1234 });
+
+ let pair_e = pair!(={ Bar { number: 789} }, Foo);
+
+ assert_eq!(pair_e.relation, Bar { number: 789 });
+ assert_eq!(pair_e.target, Foo::id());
+
+ let pair_f = pair!(ChildOf, { Foo::id() });
+
+ assert_eq!(pair_f.relation, ChildOf::id());
+ assert_eq!(pair_f.target, Foo::id());
+
+ let pair_g = pair!({ Bar::id() }, Foo);
+
+ assert_eq!(pair_g.relation, Bar::id());
+ assert_eq!(pair_g.target, Foo::id());
+ }
+}