1mod related_methods;
4mod relationship_query;
5mod relationship_source_collection;
6
7use alloc::boxed::Box;
8use bevy_platform::sync::Arc;
9use bevy_ptr::Ptr;
10use core::{any::TypeId, marker::PhantomData};
11
12use alloc::format;
13
14use bevy_utils::prelude::DebugName;
15pub use related_methods::*;
16pub use relationship_query::*;
17pub use relationship_source_collection::*;
18
19use crate::{
20 component::{Component, ComponentCloneBehavior, ComponentId, Components, Mutable},
21 entity::{ComponentCloneCtx, Entity},
22 lifecycle::HookContext,
23 system::EntityCommand,
24 world::{DeferredWorld, EntityWorldMut},
25};
26use log::warn;
27
28pub trait Relationship: Component + Sized {
112 type RelationshipTarget: RelationshipTarget<Relationship = Self>;
115
116 const ALLOW_SELF_REFERENTIAL: bool = false;
128
129 fn get(&self) -> Entity;
131
132 fn from(entity: Entity) -> Self;
134
135 fn set_risky(&mut self, entity: Entity);
148
149 fn on_insert(
151 mut world: DeferredWorld,
152 HookContext {
153 entity,
154 caller,
155 relationship_hook_mode,
156 ..
157 }: HookContext,
158 ) {
159 match relationship_hook_mode {
160 RelationshipHookMode::Run => {}
161 RelationshipHookMode::Skip => return,
162 RelationshipHookMode::RunIfNotLinked => {
163 if <Self::RelationshipTarget as RelationshipTarget>::LINKED_SPAWN {
164 return;
165 }
166 }
167 }
168 let target_entity = world.entity(entity).get::<Self>().unwrap().get();
169 if !Self::ALLOW_SELF_REFERENTIAL && target_entity == entity {
170 warn!(
171 "{}The {}({target_entity:?}) relationship on entity {entity:?} points to itself. The invalid {} relationship has been removed.\nIf this is intended behavior self-referential relations can be enabled with the allow_self_referential attribute: #[relationship(allow_self_referential)]",
172 caller.map(|location|format!("{location}: ")).unwrap_or_default(),
173 DebugName::type_name::<Self>(),
174 DebugName::type_name::<Self>()
175 );
176 world.commands().entity(entity).remove::<Self>();
177 return;
178 }
179 let current_source_to_remove = world
181 .get_entity(target_entity)
182 .ok()
183 .and_then(|target_entity_ref| target_entity_ref.get::<Self::RelationshipTarget>())
184 .and_then(|relationship_target| {
185 relationship_target
186 .collection()
187 .source_to_remove_before_add()
188 });
189
190 if let Some(current_source) = current_source_to_remove {
191 world.commands().entity(current_source).try_remove::<Self>();
192 }
193
194 if let Ok(mut entity_commands) = world.commands().get_entity(target_entity) {
195 entity_commands
197 .entry::<Self::RelationshipTarget>()
198 .and_modify(move |mut relationship_target| {
199 relationship_target.collection_mut_risky().add(entity);
200 })
201 .or_insert_with(move || {
202 let mut target = Self::RelationshipTarget::with_capacity(1);
203 target.collection_mut_risky().add(entity);
204 target
205 });
206 } else {
207 warn!(
208 "{}The {}({target_entity:?}) relationship on entity {entity:?} relates to an entity that does not exist. The invalid {} relationship has been removed.",
209 caller.map(|location|format!("{location}: ")).unwrap_or_default(),
210 DebugName::type_name::<Self>(),
211 DebugName::type_name::<Self>()
212 );
213 world.commands().entity(entity).remove::<Self>();
214 }
215 }
216
217 fn on_discard(
220 mut world: DeferredWorld,
221 HookContext {
222 entity,
223 relationship_hook_mode,
224 ..
225 }: HookContext,
226 ) {
227 match relationship_hook_mode {
228 RelationshipHookMode::Run => {}
229 RelationshipHookMode::Skip => return,
230 RelationshipHookMode::RunIfNotLinked => {
231 if <Self::RelationshipTarget as RelationshipTarget>::LINKED_SPAWN {
232 return;
233 }
234 }
235 }
236 let target_entity = world.entity(entity).get::<Self>().unwrap().get();
237 if let Ok(mut target_entity_mut) = world.get_entity_mut(target_entity)
238 && let Some(mut relationship_target) =
239 target_entity_mut.get_mut::<Self::RelationshipTarget>()
240 {
241 relationship_target.collection_mut_risky().remove(entity);
242 if relationship_target.len() == 0 {
243 let command = |mut entity: EntityWorldMut| {
244 if entity
248 .get::<Self::RelationshipTarget>()
249 .is_some_and(RelationshipTarget::is_empty)
250 {
251 entity.remove::<Self::RelationshipTarget>();
252 }
253 };
254
255 world
256 .commands()
257 .queue_silenced(command.with_entity(target_entity));
258 }
259 }
260 }
261}
262
263pub type SourceIter<'w, R> =
266 <<R as RelationshipTarget>::Collection as RelationshipSourceCollection>::SourceIter<'w>;
267
268pub trait RelationshipTarget: Component<Mutability = Mutable> + Sized {
271 const LINKED_SPAWN: bool;
279 type Relationship: Relationship<RelationshipTarget = Self>;
281 type Collection: RelationshipSourceCollection;
288
289 fn collection(&self) -> &Self::Collection;
291 fn collection_mut_risky(&mut self) -> &mut Self::Collection;
297
298 fn from_collection_risky(collection: Self::Collection) -> Self;
304
305 fn on_discard(
308 mut world: DeferredWorld,
309 HookContext {
310 entity,
311 relationship_hook_mode,
312 ..
313 }: HookContext,
314 ) {
315 match relationship_hook_mode {
316 RelationshipHookMode::Run => {}
317 RelationshipHookMode::Skip | RelationshipHookMode::RunIfNotLinked => return,
319 }
320 let (entities, mut commands) = world.entities_and_commands();
321 let relationship_target = entities.get(entity).unwrap().get::<Self>().unwrap();
322 for source_entity in relationship_target.iter() {
323 commands
324 .entity(source_entity)
325 .try_remove::<Self::Relationship>();
326 }
327 }
328
329 fn on_despawn(mut world: DeferredWorld, HookContext { entity, .. }: HookContext) {
333 let (entities, mut commands) = world.entities_and_commands();
334 let relationship_target = entities.get(entity).unwrap().get::<Self>().unwrap();
335 for source_entity in relationship_target.iter() {
336 commands.entity(source_entity).try_despawn();
337 }
338 }
339
340 fn with_capacity(capacity: usize) -> Self {
342 let collection =
343 <Self::Collection as RelationshipSourceCollection>::with_capacity(capacity);
344 Self::from_collection_risky(collection)
345 }
346
347 #[inline]
349 fn iter(&self) -> SourceIter<'_, Self> {
350 self.collection().iter()
351 }
352
353 #[inline]
355 fn len(&self) -> usize {
356 self.collection().len()
357 }
358
359 #[inline]
361 fn is_empty(&self) -> bool {
362 self.collection().is_empty()
363 }
364}
365
366pub fn clone_relationship_target<T: RelationshipTarget>(
373 component: &T,
374 cloned: &mut T,
375 context: &mut ComponentCloneCtx,
376) {
377 if context.linked_cloning() && T::LINKED_SPAWN {
378 let collection = cloned.collection_mut_risky();
379 for entity in component.iter() {
380 collection.add(entity);
381 context.queue_entity_clone(entity);
382 }
383 } else if context.moving() {
384 let target = context.target();
385 let collection = cloned.collection_mut_risky();
386 for entity in component.iter() {
387 collection.add(entity);
388 context.queue_deferred(move |world, _mapper| {
389 _ = DeferredWorld::from(world)
391 .modify_component_with_relationship_hook_mode::<T::Relationship, ()>(
392 entity,
393 RelationshipHookMode::Skip,
394 |r| r.set_risky(target),
395 );
396 });
397 }
398 }
399}
400
401#[derive(Copy, Clone, Debug)]
403pub enum RelationshipHookMode {
404 Run,
406 RunIfNotLinked,
408 Skip,
410}
411
412#[doc(hidden)]
414pub struct RelationshipCloneBehaviorSpecialization<T>(PhantomData<T>);
415
416impl<T> Default for RelationshipCloneBehaviorSpecialization<T> {
417 fn default() -> Self {
418 Self(PhantomData)
419 }
420}
421
422#[doc(hidden)]
424pub trait RelationshipCloneBehaviorBase {
425 fn default_clone_behavior(&self) -> ComponentCloneBehavior;
426}
427
428impl<C> RelationshipCloneBehaviorBase for RelationshipCloneBehaviorSpecialization<C> {
429 fn default_clone_behavior(&self) -> ComponentCloneBehavior {
430 ComponentCloneBehavior::Ignore
432 }
433}
434
435#[doc(hidden)]
437pub trait RelationshipCloneBehaviorViaReflect {
438 fn default_clone_behavior(&self) -> ComponentCloneBehavior;
439}
440
441#[cfg(feature = "bevy_reflect")]
442impl<C: Relationship + bevy_reflect::Reflect> RelationshipCloneBehaviorViaReflect
443 for &RelationshipCloneBehaviorSpecialization<C>
444{
445 fn default_clone_behavior(&self) -> ComponentCloneBehavior {
446 ComponentCloneBehavior::reflect()
447 }
448}
449
450#[doc(hidden)]
452pub trait RelationshipCloneBehaviorViaClone {
453 fn default_clone_behavior(&self) -> ComponentCloneBehavior;
454}
455
456impl<C: Relationship + Clone> RelationshipCloneBehaviorViaClone
457 for &&RelationshipCloneBehaviorSpecialization<C>
458{
459 fn default_clone_behavior(&self) -> ComponentCloneBehavior {
460 ComponentCloneBehavior::clone::<C>()
461 }
462}
463
464#[doc(hidden)]
466pub trait RelationshipTargetCloneBehaviorViaReflect {
467 fn default_clone_behavior(&self) -> ComponentCloneBehavior;
468}
469
470#[cfg(feature = "bevy_reflect")]
471impl<C: RelationshipTarget + bevy_reflect::Reflect + bevy_reflect::TypePath>
472 RelationshipTargetCloneBehaviorViaReflect for &&&RelationshipCloneBehaviorSpecialization<C>
473{
474 fn default_clone_behavior(&self) -> ComponentCloneBehavior {
475 ComponentCloneBehavior::Custom(|source, context| {
476 if let Some(component) = source.read::<C>()
477 && let Ok(mut cloned) = component.reflect_clone_and_take::<C>()
478 {
479 cloned.collection_mut_risky().clear();
480 clone_relationship_target(component, &mut cloned, context);
481 context.write_target_component(cloned);
482 }
483 })
484 }
485}
486
487#[doc(hidden)]
489pub trait RelationshipTargetCloneBehaviorViaClone {
490 fn default_clone_behavior(&self) -> ComponentCloneBehavior;
491}
492
493impl<C: RelationshipTarget + Clone> RelationshipTargetCloneBehaviorViaClone
494 for &&&&RelationshipCloneBehaviorSpecialization<C>
495{
496 fn default_clone_behavior(&self) -> ComponentCloneBehavior {
497 ComponentCloneBehavior::Custom(|source, context| {
498 if let Some(component) = source.read::<C>() {
499 let mut cloned = component.clone();
500 cloned.collection_mut_risky().clear();
501 clone_relationship_target(component, &mut cloned, context);
502 context.write_target_component(cloned);
503 }
504 })
505 }
506}
507
508#[doc(hidden)]
510pub trait RelationshipTargetCloneBehaviorHierarchy {
511 fn default_clone_behavior(&self) -> ComponentCloneBehavior;
512}
513
514impl RelationshipTargetCloneBehaviorHierarchy
515 for &&&&&RelationshipCloneBehaviorSpecialization<crate::hierarchy::Children>
516{
517 fn default_clone_behavior(&self) -> ComponentCloneBehavior {
518 ComponentCloneBehavior::Custom(|source, context| {
519 if let Some(component) = source.read::<crate::hierarchy::Children>() {
520 let mut cloned = crate::hierarchy::Children::with_capacity(component.len());
521 clone_relationship_target(component, &mut cloned, context);
522 context.write_target_component(cloned);
523 }
524 })
525 }
526}
527
528#[derive(Clone)]
530pub enum RelationshipAccessorInitializer {
531 Relationship {
533 entity_field_offset: usize,
537 linked_spawn: bool,
539 allow_self_referential: bool,
541 relationship_target_getter: Arc<dyn Fn(&Components) -> Option<ComponentId>>,
544 },
545 RelationshipTarget {
547 iter: for<'a> unsafe fn(Ptr<'a>) -> Box<dyn Iterator<Item = Entity> + 'a>,
553 linked_spawn: bool,
555 allow_self_referential: bool,
557 relationship_getter: Arc<dyn Fn(&Components) -> Option<ComponentId>>,
560 },
561}
562
563impl core::fmt::Debug for RelationshipAccessorInitializer {
564 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
565 match self {
566 Self::Relationship {
567 entity_field_offset,
568 linked_spawn,
569 allow_self_referential,
570 relationship_target_getter: _,
571 } => f
572 .debug_struct("Relationship")
573 .field("entity_field_offset", entity_field_offset)
574 .field("linked_spawn", linked_spawn)
575 .field("allow_self_referential", allow_self_referential)
576 .finish(),
577 Self::RelationshipTarget {
578 iter,
579 linked_spawn,
580 allow_self_referential,
581 relationship_getter: _,
582 } => f
583 .debug_struct("RelationshipTarget")
584 .field("iter", iter)
585 .field("linked_spawn", linked_spawn)
586 .field("allow_self_referential", allow_self_referential)
587 .finish(),
588 }
589 }
590}
591
592#[derive(Clone, Debug, Default)]
593pub(crate) enum MaybeRelationshipAccessor {
594 #[default]
596 NoAccessor,
597 Initializer(Box<RelationshipAccessorInitializer>),
600 Accessor(RelationshipAccessor),
602}
603
604impl MaybeRelationshipAccessor {
605 pub fn accessor(&self) -> Option<&RelationshipAccessor> {
607 match self {
608 MaybeRelationshipAccessor::Accessor(relationship_accessor) => {
609 Some(relationship_accessor)
610 }
611 _ => None,
612 }
613 }
614
615 pub fn initialize(&mut self, id: ComponentId, components: &mut Components) {
617 _ = (|| {
618 let accessor = self.initializer_to_accessor(|getter| getter(components))?;
619 let counterpart_id = accessor.counterpart_id();
620 let counterpart_slot = components.get_relationship_accessor_mut(counterpart_id)?;
621 let counterpart_accessor = counterpart_slot.initializer_to_accessor(|_| Some(id))?;
622 *counterpart_slot = MaybeRelationshipAccessor::Accessor(counterpart_accessor);
623 *self = MaybeRelationshipAccessor::Accessor(accessor);
624 Some(())
625 })();
626 }
627
628 fn initializer_to_accessor(
629 &self,
630 mapper: impl FnOnce(&dyn Fn(&Components) -> Option<ComponentId>) -> Option<ComponentId>,
631 ) -> Option<RelationshipAccessor> {
632 let MaybeRelationshipAccessor::Initializer(initializer) = self else {
633 return None;
634 };
635 Some(match *initializer.as_ref() {
636 RelationshipAccessorInitializer::Relationship {
637 entity_field_offset,
638 linked_spawn,
639 allow_self_referential,
640 ref relationship_target_getter,
641 } => {
642 let relationship_target = mapper(relationship_target_getter.as_ref())?;
643 RelationshipAccessor::Relationship {
644 entity_field_offset,
645 linked_spawn,
646 allow_self_referential,
647 relationship_target,
648 }
649 }
650 RelationshipAccessorInitializer::RelationshipTarget {
651 iter,
652 linked_spawn,
653 allow_self_referential,
654 ref relationship_getter,
655 } => {
656 let relationship = mapper(relationship_getter.as_ref())?;
657 RelationshipAccessor::RelationshipTarget {
658 iter,
659 linked_spawn,
660 allow_self_referential,
661 relationship,
662 }
663 }
664 })
665 }
666}
667
668impl From<Option<RelationshipAccessorInitializer>> for MaybeRelationshipAccessor {
669 fn from(value: Option<RelationshipAccessorInitializer>) -> Self {
670 value
671 .map(|v| MaybeRelationshipAccessor::Initializer(Box::new(v)))
672 .unwrap_or(MaybeRelationshipAccessor::NoAccessor)
673 }
674}
675
676#[derive(Debug, Clone, Copy)]
679pub enum RelationshipAccessor {
680 Relationship {
682 entity_field_offset: usize,
686 linked_spawn: bool,
688 allow_self_referential: bool,
690 relationship_target: ComponentId,
692 },
693 RelationshipTarget {
695 iter: for<'a> unsafe fn(Ptr<'a>) -> Box<dyn Iterator<Item = Entity> + 'a>,
701 linked_spawn: bool,
703 allow_self_referential: bool,
705 relationship: ComponentId,
707 },
708}
709
710impl RelationshipAccessor {
711 pub fn counterpart_id(&self) -> ComponentId {
713 match self {
714 RelationshipAccessor::Relationship {
715 relationship_target,
716 ..
717 } => *relationship_target,
718 RelationshipAccessor::RelationshipTarget { relationship, .. } => *relationship,
719 }
720 }
721
722 pub fn linked_spawn(&self) -> bool {
724 match self {
725 RelationshipAccessor::Relationship { linked_spawn, .. }
726 | RelationshipAccessor::RelationshipTarget { linked_spawn, .. } => *linked_spawn,
727 }
728 }
729
730 pub fn allow_self_referential(&self) -> bool {
732 match self {
733 RelationshipAccessor::Relationship {
734 allow_self_referential,
735 ..
736 }
737 | RelationshipAccessor::RelationshipTarget {
738 allow_self_referential,
739 ..
740 } => *allow_self_referential,
741 }
742 }
743}
744
745pub struct ComponentRelationshipAccessor<C: ?Sized> {
747 pub(crate) initializer: RelationshipAccessorInitializer,
748 phantom: PhantomData<C>,
749}
750
751impl<C> ComponentRelationshipAccessor<C> {
752 pub unsafe fn relationship(entity_field_offset: usize) -> Self
757 where
758 C: Relationship,
759 {
760 let getter: Box<dyn Fn(&Components) -> Option<ComponentId>> =
762 Box::new(|components| components.get_id(TypeId::of::<C::RelationshipTarget>()));
763 Self {
764 initializer: RelationshipAccessorInitializer::Relationship {
765 entity_field_offset,
766 linked_spawn: C::RelationshipTarget::LINKED_SPAWN,
767 allow_self_referential: C::ALLOW_SELF_REFERENTIAL,
768 relationship_target_getter: Arc::from(getter),
769 },
770 phantom: Default::default(),
771 }
772 }
773
774 pub fn relationship_target() -> Self
776 where
777 C: RelationshipTarget,
778 {
779 let getter: Box<dyn Fn(&Components) -> Option<ComponentId>> =
781 Box::new(|components| components.get_id(TypeId::of::<C::Relationship>()));
782 Self {
783 initializer: RelationshipAccessorInitializer::RelationshipTarget {
784 iter: |ptr| unsafe { Box::new(RelationshipTarget::iter(ptr.deref::<C>())) },
786 linked_spawn: C::LINKED_SPAWN,
787 allow_self_referential: C::Relationship::ALLOW_SELF_REFERENTIAL,
788 relationship_getter: Arc::from(getter),
789 },
790 phantom: Default::default(),
791 }
792 }
793}
794
795#[cfg(test)]
796mod tests {
797 use core::marker::PhantomData;
798 use core::sync::atomic::AtomicBool;
799
800 use crate::lifecycle::HookContext;
801 use crate::prelude::{ChildOf, Children};
802 use crate::relationship::{Relationship, RelationshipAccessor};
803 use crate::world::{DeferredWorld, World};
804 use crate::{component::Component, entity::Entity};
805 use alloc::vec::Vec;
806
807 #[test]
808 fn custom_relationship() {
809 #[derive(Component)]
810 #[relationship(relationship_target = LikedBy)]
811 struct Likes(pub Entity);
812
813 #[derive(Component)]
814 #[relationship_target(relationship = Likes)]
815 struct LikedBy(Vec<Entity>);
816
817 let mut world = World::new();
818 let a = world.spawn_empty().id();
819 let b = world.spawn(Likes(a)).id();
820 let c = world.spawn(Likes(a)).id();
821 assert_eq!(world.entity(a).get::<LikedBy>().unwrap().0, &[b, c]);
822 }
823
824 #[test]
825 fn self_relationship_fails_by_default() {
826 #[derive(Component)]
827 #[relationship(relationship_target = RelTarget)]
828 struct Rel(Entity);
829
830 #[derive(Component)]
831 #[relationship_target(relationship = Rel)]
832 struct RelTarget(Vec<Entity>);
833
834 let mut world = World::new();
835 let a = world.spawn_empty().id();
836 world.entity_mut(a).insert(Rel(a));
837 assert!(!world.entity(a).contains::<Rel>());
838 assert!(!world.entity(a).contains::<RelTarget>());
839 }
840
841 #[test]
842 fn self_relationship_succeeds_with_allow_self_referential() {
843 #[derive(Component)]
844 #[relationship(relationship_target = RelTarget, allow_self_referential)]
845 struct Rel(Entity);
846
847 #[derive(Component)]
848 #[relationship_target(relationship = Rel)]
849 struct RelTarget(Vec<Entity>);
850
851 let mut world = World::new();
852 let a = world.spawn_empty().id();
853 world.entity_mut(a).insert(Rel(a));
854 assert!(world.entity(a).contains::<Rel>());
855 assert!(world.entity(a).contains::<RelTarget>());
856 assert_eq!(world.entity(a).get::<Rel>().unwrap().get(), a);
857 assert_eq!(&*world.entity(a).get::<RelTarget>().unwrap().0, &[a]);
858 }
859
860 #[test]
861 fn self_relationship_removal_with_allow_self_referential() {
862 #[derive(Component)]
863 #[relationship(relationship_target = RelTarget, allow_self_referential)]
864 struct Rel(Entity);
865
866 #[derive(Component)]
867 #[relationship_target(relationship = Rel)]
868 struct RelTarget(Vec<Entity>);
869
870 let mut world = World::new();
871 let a = world.spawn_empty().id();
872 world.entity_mut(a).insert(Rel(a));
873 assert!(world.entity(a).contains::<Rel>());
874 assert!(world.entity(a).contains::<RelTarget>());
875
876 world.entity_mut(a).remove::<Rel>();
878 assert!(!world.entity(a).contains::<Rel>());
879 assert!(!world.entity(a).contains::<RelTarget>());
880 }
881
882 #[test]
883 fn relationship_with_missing_target_fails() {
884 #[derive(Component)]
885 #[relationship(relationship_target = RelTarget)]
886 struct Rel(Entity);
887
888 #[derive(Component)]
889 #[relationship_target(relationship = Rel)]
890 struct RelTarget(Vec<Entity>);
891
892 let mut world = World::new();
893 let a = world.spawn_empty().id();
894 world.despawn(a);
895 let b = world.spawn(Rel(a)).id();
896 assert!(!world.entity(b).contains::<Rel>());
897 assert!(!world.entity(b).contains::<RelTarget>());
898 }
899
900 #[test]
901 fn relationship_with_multiple_non_target_fields_compiles() {
902 #[expect(
903 dead_code,
904 reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
905 )]
906 #[derive(Component)]
907 #[relationship(relationship_target=Target)]
908 struct Source {
909 #[relationship]
910 target: Entity,
911 foo: u8,
912 bar: u8,
913 }
914
915 #[expect(
916 dead_code,
917 reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
918 )]
919 #[derive(Component)]
920 #[relationship_target(relationship=Source)]
921 struct Target(Vec<Entity>);
922
923 }
925 #[test]
926 fn relationship_target_with_multiple_non_target_fields_compiles() {
927 #[expect(
928 dead_code,
929 reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
930 )]
931 #[derive(Component)]
932 #[relationship(relationship_target=Target)]
933 struct Source(Entity);
934
935 #[expect(
936 dead_code,
937 reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
938 )]
939 #[derive(Component)]
940 #[relationship_target(relationship=Source)]
941 struct Target {
942 #[relationship]
943 target: Vec<Entity>,
944 foo: u8,
945 bar: u8,
946 }
947
948 }
950
951 #[test]
952 fn relationship_with_multiple_unnamed_non_target_fields_compiles() {
953 #[expect(
954 dead_code,
955 reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
956 )]
957 #[derive(Component)]
958 #[relationship(relationship_target=Target<T>)]
959 struct Source<T: Send + Sync + 'static>(#[relationship] Entity, PhantomData<T>);
960
961 #[expect(
962 dead_code,
963 reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
964 )]
965 #[derive(Component)]
966 #[relationship_target(relationship=Source<T>)]
967 struct Target<T: Send + Sync + 'static>(#[relationship] Vec<Entity>, PhantomData<T>);
968
969 }
971
972 #[test]
973 fn parent_child_relationship_with_custom_relationship() {
974 #[derive(Component)]
975 #[relationship(relationship_target = RelTarget)]
976 struct Rel(Entity);
977
978 #[derive(Component)]
979 #[relationship_target(relationship = Rel)]
980 struct RelTarget(Entity);
981
982 let mut world = World::new();
983
984 let mut commands = world.commands();
987 let child = commands.spawn_empty().id();
988 let parent = commands.spawn(Rel(child)).add_child(child).id();
989 commands.entity(parent).despawn();
990 world.flush();
991
992 assert!(world.get_entity(child).is_err());
993 assert!(world.get_entity(parent).is_err());
994
995 let mut commands = world.commands();
998 let child = commands.spawn_empty().id();
999 let parent = commands.spawn(Rel(child)).add_child(child).id();
1000 commands.entity(child).despawn();
1001 world.flush();
1002
1003 assert!(world.get_entity(child).is_err());
1004 assert!(!world.entity(parent).contains::<Rel>());
1005
1006 let mut commands = world.commands();
1009 let parent = commands.spawn_empty().id();
1010 let child = commands.spawn((ChildOf(parent), Rel(parent))).id();
1011 commands.entity(parent).despawn();
1012 world.flush();
1013
1014 assert!(world.get_entity(child).is_err());
1015 assert!(world.get_entity(parent).is_err());
1016
1017 let mut commands = world.commands();
1020 let parent = commands.spawn_empty().id();
1021 let child = commands.spawn((ChildOf(parent), Rel(parent))).id();
1022 commands.entity(child).despawn();
1023 world.flush();
1024
1025 assert!(world.get_entity(child).is_err());
1026 assert!(!world.entity(parent).contains::<RelTarget>());
1027 }
1028
1029 #[test]
1030 fn spawn_batch_with_relationship() {
1031 let mut world = World::new();
1032 let parent = world.spawn_empty().id();
1033 let children = world
1034 .spawn_batch((0..10).map(|_| ChildOf(parent)))
1035 .collect::<Vec<_>>();
1036
1037 for &child in &children {
1038 assert!(world
1039 .get::<ChildOf>(child)
1040 .is_some_and(|child_of| child_of.parent() == parent));
1041 }
1042 assert!(world
1043 .get::<Children>(parent)
1044 .is_some_and(|children| children.len() == 10));
1045 }
1046
1047 #[test]
1048 fn insert_batch_with_relationship() {
1049 let mut world = World::new();
1050 let parent = world.spawn_empty().id();
1051 let child = world.spawn_empty().id();
1052 world.insert_batch([(child, ChildOf(parent))]);
1053 world.flush();
1054
1055 assert!(world.get::<ChildOf>(child).is_some());
1056 assert!(world.get::<Children>(parent).is_some());
1057 }
1058
1059 #[test]
1060 fn dynamically_traverse_hierarchy() {
1061 let mut world = World::new();
1062 let child_of_id = world.register_component::<ChildOf>();
1063 let children_id = world.register_component::<Children>();
1064
1065 let parent = world.spawn_empty().id();
1066 let child = world.spawn_empty().id();
1067 world.entity_mut(child).insert(ChildOf(parent));
1068 world.flush();
1069
1070 let children_ptr = world.get_by_id(parent, children_id).unwrap();
1071 let RelationshipAccessor::RelationshipTarget { iter, .. } = world
1072 .components()
1073 .get_info(children_id)
1074 .unwrap()
1075 .relationship_accessor()
1076 .unwrap()
1077 else {
1078 unreachable!()
1079 };
1080 let children: Vec<_> = unsafe { iter(children_ptr).collect() };
1082 assert_eq!(children, alloc::vec![child]);
1083
1084 let child_of_ptr = world.get_by_id(child, child_of_id).unwrap();
1085 let RelationshipAccessor::Relationship {
1086 entity_field_offset,
1087 ..
1088 } = world
1089 .components()
1090 .get_info(child_of_id)
1091 .unwrap()
1092 .relationship_accessor()
1093 .unwrap()
1094 else {
1095 unreachable!()
1096 };
1097 let child_of_entity: Entity =
1101 unsafe { *child_of_ptr.byte_add(*entity_field_offset).deref() };
1102 assert_eq!(child_of_entity, parent);
1103 }
1104
1105 #[test]
1106 fn relationship_accessor() {
1107 #[derive(Component)]
1108 #[relationship(relationship_target = LikedBy)]
1109 struct Likes {
1110 _a: u16,
1111 #[relationship]
1112 e: Entity,
1113 _b: (i8, u8),
1114 }
1115
1116 #[derive(Component)]
1117 #[relationship_target(relationship = Likes)]
1118 struct LikedBy(Vec<Entity>);
1119
1120 let mut world = World::new();
1121 let likes_id = world.register_component::<Likes>();
1122 let liked_by_id = world.register_component::<LikedBy>();
1123
1124 let likes_accessor = world
1125 .components()
1126 .get_info(likes_id)
1127 .unwrap()
1128 .relationship_accessor()
1129 .unwrap();
1130 match *likes_accessor {
1131 RelationshipAccessor::Relationship {
1132 entity_field_offset,
1133 linked_spawn,
1134 allow_self_referential,
1135 relationship_target,
1136 } => {
1137 assert_eq!(entity_field_offset, core::mem::offset_of!(Likes, e));
1138 assert!(!linked_spawn);
1139 assert!(!allow_self_referential);
1140 assert_eq!(relationship_target, liked_by_id);
1141 }
1142 _ => {
1143 panic!("Not a Relationship")
1144 }
1145 }
1146
1147 let liked_by_accessor = world
1148 .components()
1149 .get_info(liked_by_id)
1150 .unwrap()
1151 .relationship_accessor()
1152 .unwrap();
1153 match *liked_by_accessor {
1154 RelationshipAccessor::RelationshipTarget {
1155 iter,
1156 linked_spawn,
1157 allow_self_referential,
1158 relationship,
1159 } => {
1160 let liked_by = LikedBy(alloc::vec![
1161 world.spawn_empty().id(),
1162 world.spawn_empty().id(),
1163 world.spawn_empty().id()
1164 ]);
1165 unsafe {
1167 assert_eq!(iter((&liked_by).into()).collect::<Vec<_>>(), liked_by.0);
1168 }
1169 assert!(!linked_spawn);
1170 assert!(!allow_self_referential);
1171 assert_eq!(relationship, likes_id);
1172 }
1173 _ => {
1174 panic!("Not a RelationshipTarget")
1175 }
1176 }
1177
1178 #[derive(Component)]
1179 #[relationship(relationship_target = RelTarget, allow_self_referential)]
1180 struct Rel(Entity);
1181
1182 #[derive(Component)]
1183 #[relationship_target(relationship = Rel, linked_spawn)]
1184 struct RelTarget(Vec<Entity>);
1185
1186 let rel_id = world.register_component::<Rel>();
1187 let rel_target_id = world.register_component::<RelTarget>();
1188
1189 let rel_accessor = world
1190 .components()
1191 .get_info(rel_id)
1192 .unwrap()
1193 .relationship_accessor()
1194 .unwrap();
1195 assert!(rel_accessor.linked_spawn());
1196 assert!(rel_accessor.allow_self_referential());
1197 let rel_target_accessor = world
1198 .components()
1199 .get_info(rel_target_id)
1200 .unwrap()
1201 .relationship_accessor()
1202 .unwrap();
1203 assert!(rel_target_accessor.linked_spawn());
1204 assert!(rel_target_accessor.allow_self_referential());
1205 }
1206
1207 #[test]
1208 pub fn component_hooks_compatibility() {
1209 static ADD_CALLED: AtomicBool = AtomicBool::new(false);
1210 static INSERT_CALLED: AtomicBool = AtomicBool::new(false);
1211 static DISCARD_CALLED: AtomicBool = AtomicBool::new(false);
1212 static REMOVE_CALLED: AtomicBool = AtomicBool::new(false);
1213 static DESPAWN_CALLED: AtomicBool = AtomicBool::new(false);
1214
1215 #[derive(Component)]
1216 #[relationship(relationship_target = RelTarget)]
1217 #[component(on_add, on_insert, on_discard, on_remove, on_despawn)]
1218 struct Rel(Entity);
1219
1220 #[derive(Component)]
1221 #[relationship_target(relationship = Rel)]
1222 struct RelTarget(Entity);
1223
1224 impl Rel {
1225 fn on_add(world: DeferredWorld, context: HookContext) {
1226 let &Rel(target) = world.get(context.entity).unwrap();
1227 assert!(!world.entity(target).contains::<RelTarget>());
1228 ADD_CALLED.store(true, core::sync::atomic::Ordering::Relaxed);
1229 }
1230
1231 fn on_insert(world: DeferredWorld, context: HookContext) {
1232 let &Rel(target) = world.get(context.entity).unwrap();
1233 assert!(!world.entity(target).contains::<RelTarget>());
1234 INSERT_CALLED.store(true, core::sync::atomic::Ordering::Relaxed);
1235 }
1236
1237 fn on_discard(world: DeferredWorld, context: HookContext) {
1238 let &Rel(target) = world.get(context.entity).unwrap();
1239 assert!(world.entity(target).contains::<RelTarget>());
1240 DISCARD_CALLED.store(true, core::sync::atomic::Ordering::Relaxed);
1241 }
1242
1243 fn on_remove(world: DeferredWorld, context: HookContext) {
1244 let &Rel(target) = world.get(context.entity).unwrap();
1245 assert!(world.entity(target).contains::<RelTarget>());
1246 REMOVE_CALLED.store(true, core::sync::atomic::Ordering::Relaxed);
1247 }
1248
1249 fn on_despawn(world: DeferredWorld, context: HookContext) {
1250 let &Rel(target) = world.get(context.entity).unwrap();
1251 assert!(world.entity(target).contains::<RelTarget>());
1252 DESPAWN_CALLED.store(true, core::sync::atomic::Ordering::Relaxed);
1253 }
1254 }
1255
1256 let mut world = World::new();
1257 let target = world.spawn_empty().id();
1258 let source = world.spawn(Rel(target)).id();
1259 assert!(world.entity(target).contains::<RelTarget>());
1260 assert!(ADD_CALLED.load(core::sync::atomic::Ordering::Relaxed));
1261 assert!(INSERT_CALLED.load(core::sync::atomic::Ordering::Relaxed));
1262 world.despawn(source);
1263 assert!(DISCARD_CALLED.load(core::sync::atomic::Ordering::Relaxed));
1264 assert!(REMOVE_CALLED.load(core::sync::atomic::Ordering::Relaxed));
1265 assert!(DESPAWN_CALLED.load(core::sync::atomic::Ordering::Relaxed));
1266 }
1267}