bevy_ecs/relationship/
mod.rs

1//! This module provides functionality to link entities to each other using specialized components called "relationships". See the [`Relationship`] trait for more info.
2
3mod related_methods;
4mod relationship_query;
5mod relationship_source_collection;
6
7use alloc::boxed::Box;
8use bevy_ptr::Ptr;
9use core::marker::PhantomData;
10
11use alloc::format;
12
13use bevy_utils::prelude::DebugName;
14pub use related_methods::*;
15pub use relationship_query::*;
16pub use relationship_source_collection::*;
17
18use crate::{
19    component::{Component, ComponentCloneBehavior, Mutable},
20    entity::{ComponentCloneCtx, Entity},
21    error::CommandWithEntity,
22    lifecycle::HookContext,
23    world::{DeferredWorld, EntityWorldMut},
24};
25use log::warn;
26
27/// A [`Component`] on a "source" [`Entity`] that references another target [`Entity`], creating a "relationship" between them. Every [`Relationship`]
28/// has a corresponding [`RelationshipTarget`] type (and vice-versa), which exists on the "target" entity of a relationship and contains the list of all
29/// "source" entities that relate to the given "target"
30///
31/// The [`Relationship`] component is the "source of truth" and the [`RelationshipTarget`] component reflects that source of truth. When a [`Relationship`]
32/// component is inserted on an [`Entity`], the corresponding [`RelationshipTarget`] component is immediately inserted on the target component if it does
33/// not already exist, and the "source" entity is automatically added to the [`RelationshipTarget`] collection (this is done via "component hooks").
34///
35/// A common example of a [`Relationship`] is the parent / child relationship. Bevy ECS includes a canonical form of this via the [`ChildOf`](crate::hierarchy::ChildOf)
36/// [`Relationship`] and the [`Children`](crate::hierarchy::Children) [`RelationshipTarget`].
37///
38/// [`Relationship`] and [`RelationshipTarget`] should always be derived via the [`Component`] trait to ensure the hooks are set up properly.
39///
40/// ## Derive
41///
42/// [`Relationship`] and [`RelationshipTarget`] can only be derived for structs with a single unnamed field, single named field
43/// or for named structs where one field is annotated with `#[relationship]`.
44/// If there are additional fields, they must all implement [`Default`].
45///
46/// [`RelationshipTarget`] also requires that the relationship field is private to prevent direct mutation,
47/// ensuring the correctness of relationships.
48/// ```
49/// # use bevy_ecs::component::Component;
50/// # use bevy_ecs::entity::Entity;
51/// #[derive(Component)]
52/// #[relationship(relationship_target = Children)]
53/// pub struct ChildOf {
54///     #[relationship]
55///     pub parent: Entity,
56///     internal: u8,
57/// };
58///
59/// #[derive(Component)]
60/// #[relationship_target(relationship = ChildOf)]
61/// pub struct Children(Vec<Entity>);
62/// ```
63///
64/// When deriving [`RelationshipTarget`] you can specify the `#[relationship_target(linked_spawn)]` attribute to
65/// automatically despawn entities stored in an entity's [`RelationshipTarget`] when that entity is despawned:
66///
67/// ```
68/// # use bevy_ecs::component::Component;
69/// # use bevy_ecs::entity::Entity;
70/// #[derive(Component)]
71/// #[relationship(relationship_target = Children)]
72/// pub struct ChildOf(pub Entity);
73///
74/// #[derive(Component)]
75/// #[relationship_target(relationship = ChildOf, linked_spawn)]
76/// pub struct Children(Vec<Entity>);
77/// ```
78pub trait Relationship: Component + Sized {
79    /// The [`Component`] added to the "target" entities of this [`Relationship`], which contains the list of all "source"
80    /// entities that relate to the "target".
81    type RelationshipTarget: RelationshipTarget<Relationship = Self>;
82
83    /// Gets the [`Entity`] ID of the related entity.
84    fn get(&self) -> Entity;
85
86    /// Creates this [`Relationship`] from the given `entity`.
87    fn from(entity: Entity) -> Self;
88
89    /// Changes the current [`Entity`] ID of the entity containing the [`RelationshipTarget`] to another one.
90    ///
91    /// This is useful for updating the relationship without overwriting other fields stored in `Self`.
92    ///
93    /// # Warning
94    ///
95    /// This should generally not be called by user code, as modifying the related entity could invalidate the
96    /// relationship. If this method is used, then the hooks [`on_replace`](Relationship::on_replace) have to
97    /// run before and [`on_insert`](Relationship::on_insert) after it.
98    /// This happens automatically when this method is called with [`EntityWorldMut::modify_component`].
99    ///
100    /// Prefer to use regular means of insertions when possible.
101    fn set_risky(&mut self, entity: Entity);
102
103    /// The `on_insert` component hook that maintains the [`Relationship`] / [`RelationshipTarget`] connection.
104    fn on_insert(
105        mut world: DeferredWorld,
106        HookContext {
107            entity,
108            caller,
109            relationship_hook_mode,
110            ..
111        }: HookContext,
112    ) {
113        match relationship_hook_mode {
114            RelationshipHookMode::Run => {}
115            RelationshipHookMode::Skip => return,
116            RelationshipHookMode::RunIfNotLinked => {
117                if <Self::RelationshipTarget as RelationshipTarget>::LINKED_SPAWN {
118                    return;
119                }
120            }
121        }
122        let target_entity = world.entity(entity).get::<Self>().unwrap().get();
123        if target_entity == entity {
124            warn!(
125                "{}The {}({target_entity:?}) relationship on entity {entity:?} points to itself. The invalid {} relationship has been removed.",
126                caller.map(|location|format!("{location}: ")).unwrap_or_default(),
127                DebugName::type_name::<Self>(),
128                DebugName::type_name::<Self>()
129            );
130            world.commands().entity(entity).remove::<Self>();
131            return;
132        }
133        // For one-to-one relationships, remove existing relationship before adding new one
134        let current_source_to_remove = world
135            .get_entity(target_entity)
136            .ok()
137            .and_then(|target_entity_ref| target_entity_ref.get::<Self::RelationshipTarget>())
138            .and_then(|relationship_target| {
139                relationship_target
140                    .collection()
141                    .source_to_remove_before_add()
142            });
143
144        if let Some(current_source) = current_source_to_remove {
145            world.commands().entity(current_source).try_remove::<Self>();
146        }
147
148        if let Ok(mut entity_commands) = world.commands().get_entity(target_entity) {
149            // Deferring is necessary for batch mode
150            entity_commands
151                .entry::<Self::RelationshipTarget>()
152                .and_modify(move |mut relationship_target| {
153                    relationship_target.collection_mut_risky().add(entity);
154                })
155                .or_insert_with(move || {
156                    let mut target = Self::RelationshipTarget::with_capacity(1);
157                    target.collection_mut_risky().add(entity);
158                    target
159                });
160        } else {
161            warn!(
162                "{}The {}({target_entity:?}) relationship on entity {entity:?} relates to an entity that does not exist. The invalid {} relationship has been removed.",
163                caller.map(|location|format!("{location}: ")).unwrap_or_default(),
164                DebugName::type_name::<Self>(),
165                DebugName::type_name::<Self>()
166            );
167            world.commands().entity(entity).remove::<Self>();
168        }
169    }
170
171    /// The `on_replace` component hook that maintains the [`Relationship`] / [`RelationshipTarget`] connection.
172    // note: think of this as "on_drop"
173    fn on_replace(
174        mut world: DeferredWorld,
175        HookContext {
176            entity,
177            relationship_hook_mode,
178            ..
179        }: HookContext,
180    ) {
181        match relationship_hook_mode {
182            RelationshipHookMode::Run => {}
183            RelationshipHookMode::Skip => return,
184            RelationshipHookMode::RunIfNotLinked => {
185                if <Self::RelationshipTarget as RelationshipTarget>::LINKED_SPAWN {
186                    return;
187                }
188            }
189        }
190        let target_entity = world.entity(entity).get::<Self>().unwrap().get();
191        if let Ok(mut target_entity_mut) = world.get_entity_mut(target_entity)
192            && let Some(mut relationship_target) =
193                target_entity_mut.get_mut::<Self::RelationshipTarget>()
194        {
195            relationship_target.collection_mut_risky().remove(entity);
196            if relationship_target.len() == 0 {
197                let command = |mut entity: EntityWorldMut| {
198                    // this "remove" operation must check emptiness because in the event that an identical
199                    // relationship is inserted on top, this despawn would result in the removal of that identical
200                    // relationship ... not what we want!
201                    if entity
202                        .get::<Self::RelationshipTarget>()
203                        .is_some_and(RelationshipTarget::is_empty)
204                    {
205                        entity.remove::<Self::RelationshipTarget>();
206                    }
207                };
208
209                world
210                    .commands()
211                    .queue_silenced(command.with_entity(target_entity));
212            }
213        }
214    }
215}
216
217/// The iterator type for the source entities in a [`RelationshipTarget`] collection,
218/// as defined in the [`RelationshipSourceCollection`] trait.
219pub type SourceIter<'w, R> =
220    <<R as RelationshipTarget>::Collection as RelationshipSourceCollection>::SourceIter<'w>;
221
222/// A [`Component`] containing the collection of entities that relate to this [`Entity`] via the associated `Relationship` type.
223/// See the [`Relationship`] documentation for more information.
224pub trait RelationshipTarget: Component<Mutability = Mutable> + Sized {
225    /// If this is true, when despawning or cloning (when [linked cloning is enabled](crate::entity::EntityClonerBuilder::linked_cloning)), the related entities targeting this entity will also be despawned or cloned.
226    ///
227    /// For example, this is set to `true` for Bevy's built-in parent-child relation, defined by [`ChildOf`](crate::prelude::ChildOf) and [`Children`](crate::prelude::Children).
228    /// This means that when a parent is despawned, any children targeting that parent are also despawned (and the same applies to cloning).
229    ///
230    /// To get around this behavior, you can first break the relationship between entities, and *then* despawn or clone.
231    /// This defaults to false when derived.
232    const LINKED_SPAWN: bool;
233    /// The [`Relationship`] that populates this [`RelationshipTarget`] collection.
234    type Relationship: Relationship<RelationshipTarget = Self>;
235    /// The collection type that stores the "source" entities for this [`RelationshipTarget`] component.
236    ///
237    /// Check the list of types which implement [`RelationshipSourceCollection`] for the data structures that can be used inside of your component.
238    /// If you need a new collection type, you can implement the [`RelationshipSourceCollection`] trait
239    /// for a type you own which wraps the collection you want to use (to avoid the orphan rule),
240    /// or open an issue on the Bevy repository to request first-party support for your collection type.
241    type Collection: RelationshipSourceCollection;
242
243    /// Returns a reference to the stored [`RelationshipTarget::Collection`].
244    fn collection(&self) -> &Self::Collection;
245    /// Returns a mutable reference to the stored [`RelationshipTarget::Collection`].
246    ///
247    /// # Warning
248    /// This should generally not be called by user code, as modifying the internal collection could invalidate the relationship.
249    /// The collection should not contain duplicates.
250    fn collection_mut_risky(&mut self) -> &mut Self::Collection;
251
252    /// Creates a new [`RelationshipTarget`] from the given [`RelationshipTarget::Collection`].
253    ///
254    /// # Warning
255    /// This should generally not be called by user code, as constructing the internal collection could invalidate the relationship.
256    /// The collection should not contain duplicates.
257    fn from_collection_risky(collection: Self::Collection) -> Self;
258
259    /// The `on_replace` component hook that maintains the [`Relationship`] / [`RelationshipTarget`] connection.
260    // note: think of this as "on_drop"
261    fn on_replace(
262        mut world: DeferredWorld,
263        HookContext {
264            entity,
265            relationship_hook_mode,
266            ..
267        }: HookContext,
268    ) {
269        match relationship_hook_mode {
270            RelationshipHookMode::Run => {}
271            // For RelationshipTarget we don't want to run this hook even if it isn't linked, but for Relationship we do.
272            RelationshipHookMode::Skip | RelationshipHookMode::RunIfNotLinked => return,
273        }
274        let (entities, mut commands) = world.entities_and_commands();
275        let relationship_target = entities.get(entity).unwrap().get::<Self>().unwrap();
276        for source_entity in relationship_target.iter() {
277            commands
278                .entity(source_entity)
279                .try_remove::<Self::Relationship>();
280        }
281    }
282
283    /// The `on_despawn` component hook that despawns entities stored in an entity's [`RelationshipTarget`] when
284    /// that entity is despawned.
285    // note: think of this as "on_drop"
286    fn on_despawn(mut world: DeferredWorld, HookContext { entity, .. }: HookContext) {
287        let (entities, mut commands) = world.entities_and_commands();
288        let relationship_target = entities.get(entity).unwrap().get::<Self>().unwrap();
289        for source_entity in relationship_target.iter() {
290            commands.entity(source_entity).try_despawn();
291        }
292    }
293
294    /// Creates this [`RelationshipTarget`] with the given pre-allocated entity capacity.
295    fn with_capacity(capacity: usize) -> Self {
296        let collection =
297            <Self::Collection as RelationshipSourceCollection>::with_capacity(capacity);
298        Self::from_collection_risky(collection)
299    }
300
301    /// Iterates the entities stored in this collection.
302    #[inline]
303    fn iter(&self) -> SourceIter<'_, Self> {
304        self.collection().iter()
305    }
306
307    /// Returns the number of entities in this collection.
308    #[inline]
309    fn len(&self) -> usize {
310        self.collection().len()
311    }
312
313    /// Returns true if this entity collection is empty.
314    #[inline]
315    fn is_empty(&self) -> bool {
316        self.collection().is_empty()
317    }
318}
319
320/// The "clone behavior" for [`RelationshipTarget`]. The [`RelationshipTarget`] will be populated with the proper components
321/// when the corresponding [`Relationship`] sources of truth are inserted. Cloning the actual entities
322/// in the original [`RelationshipTarget`] would result in duplicates, so we don't do that!
323///
324/// This will also queue up clones of the relationship sources if the [`EntityCloner`](crate::entity::EntityCloner) is configured
325/// to spawn recursively.
326pub fn clone_relationship_target<T: RelationshipTarget>(
327    component: &T,
328    cloned: &mut T,
329    context: &mut ComponentCloneCtx,
330) {
331    if context.linked_cloning() && T::LINKED_SPAWN {
332        let collection = cloned.collection_mut_risky();
333        for entity in component.iter() {
334            collection.add(entity);
335            context.queue_entity_clone(entity);
336        }
337    } else if context.moving() {
338        let target = context.target();
339        let collection = cloned.collection_mut_risky();
340        for entity in component.iter() {
341            collection.add(entity);
342            context.queue_deferred(move |world, _mapper| {
343                // We don't want relationships hooks to run because we are manually constructing the collection here
344                _ = DeferredWorld::from(world)
345                    .modify_component_with_relationship_hook_mode::<T::Relationship, ()>(
346                        entity,
347                        RelationshipHookMode::Skip,
348                        |r| r.set_risky(target),
349                    );
350            });
351        }
352    }
353}
354
355/// Configures the conditions under which the Relationship insert/replace hooks will be run.
356#[derive(Copy, Clone, Debug)]
357pub enum RelationshipHookMode {
358    /// Relationship insert/replace hooks will always run
359    Run,
360    /// Relationship insert/replace hooks will run if [`RelationshipTarget::LINKED_SPAWN`] is false
361    RunIfNotLinked,
362    /// Relationship insert/replace hooks will always be skipped
363    Skip,
364}
365
366/// Wrapper for components clone specialization using autoderef.
367#[doc(hidden)]
368pub struct RelationshipCloneBehaviorSpecialization<T>(PhantomData<T>);
369
370impl<T> Default for RelationshipCloneBehaviorSpecialization<T> {
371    fn default() -> Self {
372        Self(PhantomData)
373    }
374}
375
376/// Base trait for relationship clone specialization using autoderef.
377#[doc(hidden)]
378pub trait RelationshipCloneBehaviorBase {
379    fn default_clone_behavior(&self) -> ComponentCloneBehavior;
380}
381
382impl<C> RelationshipCloneBehaviorBase for RelationshipCloneBehaviorSpecialization<C> {
383    fn default_clone_behavior(&self) -> ComponentCloneBehavior {
384        // Relationships currently must have `Clone`/`Reflect`-based handler for cloning/moving logic to properly work.
385        ComponentCloneBehavior::Ignore
386    }
387}
388
389/// Specialized trait for relationship clone specialization using autoderef.
390#[doc(hidden)]
391pub trait RelationshipCloneBehaviorViaReflect {
392    fn default_clone_behavior(&self) -> ComponentCloneBehavior;
393}
394
395#[cfg(feature = "bevy_reflect")]
396impl<C: Relationship + bevy_reflect::Reflect> RelationshipCloneBehaviorViaReflect
397    for &RelationshipCloneBehaviorSpecialization<C>
398{
399    fn default_clone_behavior(&self) -> ComponentCloneBehavior {
400        ComponentCloneBehavior::reflect()
401    }
402}
403
404/// Specialized trait for relationship clone specialization using autoderef.
405#[doc(hidden)]
406pub trait RelationshipCloneBehaviorViaClone {
407    fn default_clone_behavior(&self) -> ComponentCloneBehavior;
408}
409
410impl<C: Relationship + Clone> RelationshipCloneBehaviorViaClone
411    for &&RelationshipCloneBehaviorSpecialization<C>
412{
413    fn default_clone_behavior(&self) -> ComponentCloneBehavior {
414        ComponentCloneBehavior::clone::<C>()
415    }
416}
417
418/// Specialized trait for relationship target clone specialization using autoderef.
419#[doc(hidden)]
420pub trait RelationshipTargetCloneBehaviorViaReflect {
421    fn default_clone_behavior(&self) -> ComponentCloneBehavior;
422}
423
424#[cfg(feature = "bevy_reflect")]
425impl<C: RelationshipTarget + bevy_reflect::Reflect + bevy_reflect::TypePath>
426    RelationshipTargetCloneBehaviorViaReflect for &&&RelationshipCloneBehaviorSpecialization<C>
427{
428    fn default_clone_behavior(&self) -> ComponentCloneBehavior {
429        ComponentCloneBehavior::Custom(|source, context| {
430            if let Some(component) = source.read::<C>()
431                && let Ok(mut cloned) = component.reflect_clone_and_take::<C>()
432            {
433                cloned.collection_mut_risky().clear();
434                clone_relationship_target(component, &mut cloned, context);
435                context.write_target_component(cloned);
436            }
437        })
438    }
439}
440
441/// Specialized trait for relationship target clone specialization using autoderef.
442#[doc(hidden)]
443pub trait RelationshipTargetCloneBehaviorViaClone {
444    fn default_clone_behavior(&self) -> ComponentCloneBehavior;
445}
446
447impl<C: RelationshipTarget + Clone> RelationshipTargetCloneBehaviorViaClone
448    for &&&&RelationshipCloneBehaviorSpecialization<C>
449{
450    fn default_clone_behavior(&self) -> ComponentCloneBehavior {
451        ComponentCloneBehavior::Custom(|source, context| {
452            if let Some(component) = source.read::<C>() {
453                let mut cloned = component.clone();
454                cloned.collection_mut_risky().clear();
455                clone_relationship_target(component, &mut cloned, context);
456                context.write_target_component(cloned);
457            }
458        })
459    }
460}
461
462/// We know there's no additional data on Children, so this handler is an optimization to avoid cloning the entire Collection.
463#[doc(hidden)]
464pub trait RelationshipTargetCloneBehaviorHierarchy {
465    fn default_clone_behavior(&self) -> ComponentCloneBehavior;
466}
467
468impl RelationshipTargetCloneBehaviorHierarchy
469    for &&&&&RelationshipCloneBehaviorSpecialization<crate::hierarchy::Children>
470{
471    fn default_clone_behavior(&self) -> ComponentCloneBehavior {
472        ComponentCloneBehavior::Custom(|source, context| {
473            if let Some(component) = source.read::<crate::hierarchy::Children>() {
474                let mut cloned = crate::hierarchy::Children::with_capacity(component.len());
475                clone_relationship_target(component, &mut cloned, context);
476                context.write_target_component(cloned);
477            }
478        })
479    }
480}
481
482/// This enum describes a way to access the entities of [`Relationship`] and [`RelationshipTarget`] components
483/// in a type-erased context.
484#[derive(Debug, Clone, Copy)]
485pub enum RelationshipAccessor {
486    /// This component is a [`Relationship`].
487    Relationship {
488        /// Offset of the field containing [`Entity`] from the base of the component.
489        ///
490        /// Dynamic equivalent of [`Relationship::get`].
491        entity_field_offset: usize,
492        /// Value of [`RelationshipTarget::LINKED_SPAWN`] for the [`Relationship::RelationshipTarget`] of this [`Relationship`].
493        linked_spawn: bool,
494    },
495    /// This component is a [`RelationshipTarget`].
496    RelationshipTarget {
497        /// Function that returns an iterator over all [`Entity`]s of this [`RelationshipTarget`]'s collection.
498        ///
499        /// Dynamic equivalent of [`RelationshipTarget::iter`].
500        /// # Safety
501        /// Passed pointer must point to the value of the same component as the one that this accessor was registered to.
502        iter: for<'a> unsafe fn(Ptr<'a>) -> Box<dyn Iterator<Item = Entity> + 'a>,
503        /// Value of [`RelationshipTarget::LINKED_SPAWN`] of this [`RelationshipTarget`].
504        linked_spawn: bool,
505    },
506}
507
508/// A type-safe convenience wrapper over [`RelationshipAccessor`].
509pub struct ComponentRelationshipAccessor<C: ?Sized> {
510    pub(crate) accessor: RelationshipAccessor,
511    phantom: PhantomData<C>,
512}
513
514impl<C> ComponentRelationshipAccessor<C> {
515    /// Create a new [`ComponentRelationshipAccessor`] for a [`Relationship`] component.
516    /// # Safety
517    /// `entity_field_offset` should be the offset from the base of this component and point to a field that stores value of type [`Entity`].
518    /// This value can be obtained using the [`core::mem::offset_of`] macro.
519    pub unsafe fn relationship(entity_field_offset: usize) -> Self
520    where
521        C: Relationship,
522    {
523        Self {
524            accessor: RelationshipAccessor::Relationship {
525                entity_field_offset,
526                linked_spawn: C::RelationshipTarget::LINKED_SPAWN,
527            },
528            phantom: Default::default(),
529        }
530    }
531
532    /// Create a new [`ComponentRelationshipAccessor`] for a [`RelationshipTarget`] component.
533    pub fn relationship_target() -> Self
534    where
535        C: RelationshipTarget,
536    {
537        Self {
538            accessor: RelationshipAccessor::RelationshipTarget {
539                // Safety: caller ensures that `ptr` is of type `C`.
540                iter: |ptr| unsafe { Box::new(RelationshipTarget::iter(ptr.deref::<C>())) },
541                linked_spawn: C::LINKED_SPAWN,
542            },
543            phantom: Default::default(),
544        }
545    }
546}
547
548#[cfg(test)]
549mod tests {
550    use core::marker::PhantomData;
551
552    use crate::prelude::{ChildOf, Children};
553    use crate::relationship::RelationshipAccessor;
554    use crate::world::World;
555    use crate::{component::Component, entity::Entity};
556    use alloc::vec::Vec;
557
558    #[test]
559    fn custom_relationship() {
560        #[derive(Component)]
561        #[relationship(relationship_target = LikedBy)]
562        struct Likes(pub Entity);
563
564        #[derive(Component)]
565        #[relationship_target(relationship = Likes)]
566        struct LikedBy(Vec<Entity>);
567
568        let mut world = World::new();
569        let a = world.spawn_empty().id();
570        let b = world.spawn(Likes(a)).id();
571        let c = world.spawn(Likes(a)).id();
572        assert_eq!(world.entity(a).get::<LikedBy>().unwrap().0, &[b, c]);
573    }
574
575    #[test]
576    fn self_relationship_fails() {
577        #[derive(Component)]
578        #[relationship(relationship_target = RelTarget)]
579        struct Rel(Entity);
580
581        #[derive(Component)]
582        #[relationship_target(relationship = Rel)]
583        struct RelTarget(Vec<Entity>);
584
585        let mut world = World::new();
586        let a = world.spawn_empty().id();
587        world.entity_mut(a).insert(Rel(a));
588        assert!(!world.entity(a).contains::<Rel>());
589        assert!(!world.entity(a).contains::<RelTarget>());
590    }
591
592    #[test]
593    fn relationship_with_missing_target_fails() {
594        #[derive(Component)]
595        #[relationship(relationship_target = RelTarget)]
596        struct Rel(Entity);
597
598        #[derive(Component)]
599        #[relationship_target(relationship = Rel)]
600        struct RelTarget(Vec<Entity>);
601
602        let mut world = World::new();
603        let a = world.spawn_empty().id();
604        world.despawn(a);
605        let b = world.spawn(Rel(a)).id();
606        assert!(!world.entity(b).contains::<Rel>());
607        assert!(!world.entity(b).contains::<RelTarget>());
608    }
609
610    #[test]
611    fn relationship_with_multiple_non_target_fields_compiles() {
612        #[expect(
613            dead_code,
614            reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
615        )]
616        #[derive(Component)]
617        #[relationship(relationship_target=Target)]
618        struct Source {
619            #[relationship]
620            target: Entity,
621            foo: u8,
622            bar: u8,
623        }
624
625        #[expect(
626            dead_code,
627            reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
628        )]
629        #[derive(Component)]
630        #[relationship_target(relationship=Source)]
631        struct Target(Vec<Entity>);
632
633        // No assert necessary, looking to make sure compilation works with the macros
634    }
635    #[test]
636    fn relationship_target_with_multiple_non_target_fields_compiles() {
637        #[expect(
638            dead_code,
639            reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
640        )]
641        #[derive(Component)]
642        #[relationship(relationship_target=Target)]
643        struct Source(Entity);
644
645        #[expect(
646            dead_code,
647            reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
648        )]
649        #[derive(Component)]
650        #[relationship_target(relationship=Source)]
651        struct Target {
652            #[relationship]
653            target: Vec<Entity>,
654            foo: u8,
655            bar: u8,
656        }
657
658        // No assert necessary, looking to make sure compilation works with the macros
659    }
660
661    #[test]
662    fn relationship_with_multiple_unnamed_non_target_fields_compiles() {
663        #[expect(
664            dead_code,
665            reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
666        )]
667        #[derive(Component)]
668        #[relationship(relationship_target=Target<T>)]
669        struct Source<T: Send + Sync + 'static>(#[relationship] Entity, PhantomData<T>);
670
671        #[expect(
672            dead_code,
673            reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
674        )]
675        #[derive(Component)]
676        #[relationship_target(relationship=Source<T>)]
677        struct Target<T: Send + Sync + 'static>(#[relationship] Vec<Entity>, PhantomData<T>);
678
679        // No assert necessary, looking to make sure compilation works with the macros
680    }
681
682    #[test]
683    fn parent_child_relationship_with_custom_relationship() {
684        #[derive(Component)]
685        #[relationship(relationship_target = RelTarget)]
686        struct Rel(Entity);
687
688        #[derive(Component)]
689        #[relationship_target(relationship = Rel)]
690        struct RelTarget(Entity);
691
692        let mut world = World::new();
693
694        // Rel on Parent
695        // Despawn Parent
696        let mut commands = world.commands();
697        let child = commands.spawn_empty().id();
698        let parent = commands.spawn(Rel(child)).add_child(child).id();
699        commands.entity(parent).despawn();
700        world.flush();
701
702        assert!(world.get_entity(child).is_err());
703        assert!(world.get_entity(parent).is_err());
704
705        // Rel on Parent
706        // Despawn Child
707        let mut commands = world.commands();
708        let child = commands.spawn_empty().id();
709        let parent = commands.spawn(Rel(child)).add_child(child).id();
710        commands.entity(child).despawn();
711        world.flush();
712
713        assert!(world.get_entity(child).is_err());
714        assert!(!world.entity(parent).contains::<Rel>());
715
716        // Rel on Child
717        // Despawn Parent
718        let mut commands = world.commands();
719        let parent = commands.spawn_empty().id();
720        let child = commands.spawn((ChildOf(parent), Rel(parent))).id();
721        commands.entity(parent).despawn();
722        world.flush();
723
724        assert!(world.get_entity(child).is_err());
725        assert!(world.get_entity(parent).is_err());
726
727        // Rel on Child
728        // Despawn Child
729        let mut commands = world.commands();
730        let parent = commands.spawn_empty().id();
731        let child = commands.spawn((ChildOf(parent), Rel(parent))).id();
732        commands.entity(child).despawn();
733        world.flush();
734
735        assert!(world.get_entity(child).is_err());
736        assert!(!world.entity(parent).contains::<RelTarget>());
737    }
738
739    #[test]
740    fn spawn_batch_with_relationship() {
741        let mut world = World::new();
742        let parent = world.spawn_empty().id();
743        let children = world
744            .spawn_batch((0..10).map(|_| ChildOf(parent)))
745            .collect::<Vec<_>>();
746
747        for &child in &children {
748            assert!(world
749                .get::<ChildOf>(child)
750                .is_some_and(|child_of| child_of.parent() == parent));
751        }
752        assert!(world
753            .get::<Children>(parent)
754            .is_some_and(|children| children.len() == 10));
755    }
756
757    #[test]
758    fn insert_batch_with_relationship() {
759        let mut world = World::new();
760        let parent = world.spawn_empty().id();
761        let child = world.spawn_empty().id();
762        world.insert_batch([(child, ChildOf(parent))]);
763        world.flush();
764
765        assert!(world.get::<ChildOf>(child).is_some());
766        assert!(world.get::<Children>(parent).is_some());
767    }
768
769    #[test]
770    fn dynamically_traverse_hierarchy() {
771        let mut world = World::new();
772        let child_of_id = world.register_component::<ChildOf>();
773        let children_id = world.register_component::<Children>();
774
775        let parent = world.spawn_empty().id();
776        let child = world.spawn_empty().id();
777        world.entity_mut(child).insert(ChildOf(parent));
778        world.flush();
779
780        let children_ptr = world.get_by_id(parent, children_id).unwrap();
781        let RelationshipAccessor::RelationshipTarget { iter, .. } = world
782            .components()
783            .get_info(children_id)
784            .unwrap()
785            .relationship_accessor()
786            .unwrap()
787        else {
788            unreachable!()
789        };
790        // Safety: `children_ptr` contains value of the same type as the one this accessor was registered for.
791        let children: Vec<_> = unsafe { iter(children_ptr).collect() };
792        assert_eq!(children, alloc::vec![child]);
793
794        let child_of_ptr = world.get_by_id(child, child_of_id).unwrap();
795        let RelationshipAccessor::Relationship {
796            entity_field_offset,
797            ..
798        } = world
799            .components()
800            .get_info(child_of_id)
801            .unwrap()
802            .relationship_accessor()
803            .unwrap()
804        else {
805            unreachable!()
806        };
807        // Safety:
808        // - offset is in bounds, aligned and has the same lifetime as the original pointer.
809        // - value at offset is guaranteed to be a valid Entity
810        let child_of_entity: Entity =
811            unsafe { *child_of_ptr.byte_add(*entity_field_offset).deref() };
812        assert_eq!(child_of_entity, parent);
813    }
814}