1//! This module provides functionality to link entities to each other using specialized components called "relationships". See the [`Relationship`] trait for more info.
23mod related_methods;
4mod relationship_query;
5mod relationship_source_collection;
67use alloc::boxed::Box;
8use bevy_platform::sync::Arc;
9use bevy_ptr::Ptr;
10use core::{any::TypeId, marker::PhantomData};
1112use alloc::format;
1314use bevy_utils::prelude::DebugName;
15pub use related_methods::*;
16pub use relationship_query::*;
17pub use relationship_source_collection::*;
1819use crate::{
20 component::{Component, ComponentCloneBehavior, ComponentId, Components, Mutable},
21 entity::{ComponentCloneCtx, Entity},
22lifecycle::HookContext,
23system::EntityCommand,
24 world::{DeferredWorld, EntityWorldMut},
25};
26use log::warn;
2728/// A [`Component`] on a "source" [`Entity`] that references another target [`Entity`], creating a "relationship" between them. Every [`Relationship`]
29/// has a corresponding [`RelationshipTarget`] type (and vice-versa), which exists on the "target" entity of a relationship and contains the list of all
30/// "source" entities that relate to the given "target".
31///
32/// A [`Relationship`] may only be one-to-many (or one-to-one): an [`Entity`] may point to at most one [`Entity`] through the [`Relationship`] component.
33///
34/// The [`Relationship`] component is the "source of truth" and the [`RelationshipTarget`] component reflects that source of truth. When a [`Relationship`]
35/// component is inserted on an [`Entity`], the corresponding [`RelationshipTarget`] component is immediately inserted on the target component if it does
36/// not already exist, and the "source" entity is automatically added to the [`RelationshipTarget`] collection (this is done via "component hooks").
37///
38/// 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)
39/// [`Relationship`] and the [`Children`](crate::hierarchy::Children) [`RelationshipTarget`].
40///
41/// [`Relationship`] and [`RelationshipTarget`] should always be derived via the [`Component`] trait to ensure the hooks are set up properly.
42///
43/// ## Derive
44///
45/// [`Relationship`] and [`RelationshipTarget`] can only be derived for structs with a single unnamed field, single named field
46/// or for named structs where one field is annotated with `#[relationship]`.
47/// If there are additional fields, they must all implement [`Default`].
48///
49/// [`RelationshipTarget`] also requires that the relationship field is private to prevent direct mutation,
50/// ensuring the correctness of relationships.
51/// ```
52/// # use bevy_ecs::component::Component;
53/// # use bevy_ecs::entity::Entity;
54/// #[derive(Component)]
55/// #[relationship(relationship_target = Children)]
56/// pub struct ChildOf {
57/// #[relationship]
58/// pub parent: Entity,
59/// internal: u8,
60/// };
61///
62/// #[derive(Component)]
63/// #[relationship_target(relationship = ChildOf)]
64/// pub struct Children(Vec<Entity>);
65/// ```
66///
67/// A one-to-one relationship can be created by putting a single [`Entity`] in the [`RelationshipTarget`]'s field.
68/// In that case, if another entity is added to the relationship, the original entity is removed.
69///
70/// ```
71/// # use bevy_ecs::component::Component;
72/// # use bevy_ecs::entity::Entity;
73/// #[derive(Component)]
74/// #[relationship(relationship_target = View)]
75/// pub struct ViewOf(pub Entity);
76///
77/// #[derive(Component)]
78/// #[relationship_target(relationship = ViewOf)]
79/// pub struct View(Entity);
80/// ```
81///
82/// When deriving [`RelationshipTarget`] you can specify the `#[relationship_target(linked_spawn)]` attribute to
83/// automatically despawn entities stored in an entity's [`RelationshipTarget`] when that entity is despawned:
84///
85/// ```
86/// # use bevy_ecs::component::Component;
87/// # use bevy_ecs::entity::Entity;
88/// #[derive(Component)]
89/// #[relationship(relationship_target = Children)]
90/// pub struct ChildOf(pub Entity);
91///
92/// #[derive(Component)]
93/// #[relationship_target(relationship = ChildOf, linked_spawn)]
94/// pub struct Children(Vec<Entity>);
95/// ```
96///
97/// By default, relationships cannot point to their own entity. If you want to allow self-referential
98/// relationships, you can use the `allow_self_referential` attribute:
99///
100/// ```
101/// # use bevy_ecs::component::Component;
102/// # use bevy_ecs::entity::Entity;
103/// #[derive(Component)]
104/// #[relationship(relationship_target = PeopleILike, allow_self_referential)]
105/// pub struct LikedBy(pub Entity);
106///
107/// #[derive(Component)]
108/// #[relationship_target(relationship = LikedBy)]
109/// pub struct PeopleILike(Vec<Entity>);
110/// ```
111pub trait Relationship: Component + Sized {
112/// The [`Component`] added to the "target" entities of this [`Relationship`], which contains the list of all "source"
113 /// entities that relate to the "target".
114type RelationshipTarget: RelationshipTarget<Relationship = Self>;
115116/// If `true`, a relationship is allowed to point to its own entity.
117 ///
118 /// Set this to `true` when self-relationships are semantically valid for your use case,
119 /// such as `Likes(self)`, `EmployedBy(self)`, or a `ColliderOf` relationship where
120 /// a collider can be attached to its own entity.
121 ///
122 /// # Warning
123 ///
124 /// When `ALLOW_SELF` is `true`, be careful when using recursive traversal methods
125 /// like `iter_ancestors` or `root_ancestor`, as they will loop infinitely if an entity
126 /// points to itself.
127const ALLOW_SELF_REFERENTIAL: bool = false;
128129/// Gets the [`Entity`] ID of the related entity.
130fn get(&self) -> Entity;
131132/// Creates this [`Relationship`] from the given `entity`.
133fn from(entity: Entity) -> Self;
134135/// Changes the current [`Entity`] ID of the entity containing the [`RelationshipTarget`] to another one.
136 ///
137 /// This is useful for updating the relationship without overwriting other fields stored in `Self`.
138 ///
139 /// # Warning
140 ///
141 /// This should generally not be called by user code, as modifying the related entity could invalidate the
142 /// relationship. If this method is used, then the hooks [`on_discard`](Relationship::on_discard) have to
143 /// run before and [`on_insert`](Relationship::on_insert) after it.
144 /// This happens automatically when this method is called with [`EntityWorldMut::modify_component`].
145 ///
146 /// Prefer to use regular means of insertions when possible.
147fn set_risky(&mut self, entity: Entity);
148149/// The `on_insert` component hook that maintains the [`Relationship`] / [`RelationshipTarget`] connection.
150fn on_insert(
151mut world: DeferredWorld,
152HookContext {
153 entity,
154 caller,
155 relationship_hook_mode,
156 ..
157 }: HookContext,
158 ) {
159match relationship_hook_mode {
160 RelationshipHookMode::Run => {}
161 RelationshipHookMode::Skip => return,
162 RelationshipHookMode::RunIfNotLinked => {
163if <Self::RelationshipTarget as RelationshipTarget>::LINKED_SPAWN {
164return;
165 }
166 }
167 }
168let target_entity = world.entity(entity).get::<Self>().unwrap().get();
169if !Self::ALLOW_SELF_REFERENTIAL && target_entity == entity {
170{
{
let lvl = ::log::Level::Warn;
if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() {
::log::__private_api::log({ ::log::__private_api::GlobalLogger },
format_args!("{0}The {1}({3:?}) relationship on entity {4:?} points to itself. The invalid {2} 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)]",
caller.map(|location|
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}: ", location))
})).unwrap_or_default(), DebugName::type_name::<Self>(),
DebugName::type_name::<Self>(), target_entity, entity), lvl,
&("bevy_ecs::relationship", "bevy_ecs::relationship",
::log::__private_api::loc()), ());
}
}
};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 );
176world.commands().entity(entity).remove::<Self>();
177return;
178 }
179// For one-to-one relationships, remove existing relationship before adding new one
180let current_source_to_remove = world181 .get_entity(target_entity)
182 .ok()
183 .and_then(|target_entity_ref| target_entity_ref.get::<Self::RelationshipTarget>())
184 .and_then(|relationship_target| {
185relationship_target186 .collection()
187 .source_to_remove_before_add()
188 });
189190if let Some(current_source) = current_source_to_remove {
191world.commands().entity(current_source).try_remove::<Self>();
192 }
193194if let Ok(mut entity_commands) = world.commands().get_entity(target_entity) {
195// Deferring is necessary for batch mode
196entity_commands197 .entry::<Self::RelationshipTarget>()
198 .and_modify(move |mut relationship_target| {
199relationship_target.collection_mut_risky().add(entity);
200 })
201 .or_insert_with(move || {
202let mut target = Self::RelationshipTarget::with_capacity(1);
203target.collection_mut_risky().add(entity);
204target205 });
206 } else {
207{
{
let lvl = ::log::Level::Warn;
if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() {
::log::__private_api::log({ ::log::__private_api::GlobalLogger },
format_args!("{0}The {1}({3:?}) relationship on entity {4:?} relates to an entity that does not exist. The invalid {2} relationship has been removed.",
caller.map(|location|
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}: ", location))
})).unwrap_or_default(), DebugName::type_name::<Self>(),
DebugName::type_name::<Self>(), target_entity, entity), lvl,
&("bevy_ecs::relationship", "bevy_ecs::relationship",
::log::__private_api::loc()), ());
}
}
};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 );
213world.commands().entity(entity).remove::<Self>();
214 }
215 }
216217/// The `on_discard` component hook that maintains the [`Relationship`] / [`RelationshipTarget`] connection.
218// note: think of this as "on_drop"
219fn on_discard(
220mut world: DeferredWorld,
221HookContext {
222 entity,
223 relationship_hook_mode,
224 ..
225 }: HookContext,
226 ) {
227match relationship_hook_mode {
228 RelationshipHookMode::Run => {}
229 RelationshipHookMode::Skip => return,
230 RelationshipHookMode::RunIfNotLinked => {
231if <Self::RelationshipTarget as RelationshipTarget>::LINKED_SPAWN {
232return;
233 }
234 }
235 }
236let target_entity = world.entity(entity).get::<Self>().unwrap().get();
237if let Ok(mut target_entity_mut) = world.get_entity_mut(target_entity)
238 && let Some(mut relationship_target) =
239target_entity_mut.get_mut::<Self::RelationshipTarget>()
240 {
241relationship_target.collection_mut_risky().remove(entity);
242if relationship_target.len() == 0 {
243let command = |mut entity: EntityWorldMut| {
244// this "remove" operation must check emptiness because in the event that an identical
245 // relationship is inserted on top, this despawn would result in the removal of that identical
246 // relationship ... not what we want!
247if entity248 .get::<Self::RelationshipTarget>()
249 .is_some_and(RelationshipTarget::is_empty)
250 {
251entity.remove::<Self::RelationshipTarget>();
252 }
253 };
254255world256 .commands()
257 .queue_silenced(command.with_entity(target_entity));
258 }
259 }
260 }
261}
262263/// The iterator type for the source entities in a [`RelationshipTarget`] collection,
264/// as defined in the [`RelationshipSourceCollection`] trait.
265pub type SourceIter<'w, R> =
266 <<R as RelationshipTarget>::Collectionas RelationshipSourceCollection>::SourceIter<'w>;
267268/// A [`Component`] containing the collection of entities that relate to this [`Entity`] via the associated `Relationship` type.
269/// See the [`Relationship`] documentation for more information.
270pub trait RelationshipTarget: Component<Mutability = Mutable> + Sized {
271/// 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.
272 ///
273 /// 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).
274 /// This means that when a parent is despawned, any children targeting that parent are also despawned (and the same applies to cloning).
275 ///
276 /// To get around this behavior, you can first break the relationship between entities, and *then* despawn or clone.
277 /// This defaults to false when derived.
278const LINKED_SPAWN: bool;
279/// The [`Relationship`] that populates this [`RelationshipTarget`] collection.
280type Relationship: Relationship<RelationshipTarget = Self>;
281/// The collection type that stores the "source" entities for this [`RelationshipTarget`] component.
282 ///
283 /// Check the list of types which implement [`RelationshipSourceCollection`] for the data structures that can be used inside of your component.
284 /// If you need a new collection type, you can implement the [`RelationshipSourceCollection`] trait
285 /// for a type you own which wraps the collection you want to use (to avoid the orphan rule),
286 /// or open an issue on the Bevy repository to request first-party support for your collection type.
287type Collection: RelationshipSourceCollection;
288289/// Returns a reference to the stored [`RelationshipTarget::Collection`].
290fn collection(&self) -> &Self::Collection;
291/// Returns a mutable reference to the stored [`RelationshipTarget::Collection`].
292 ///
293 /// # Warning
294 /// This should generally not be called by user code, as modifying the internal collection could invalidate the relationship.
295 /// The collection should not contain duplicates.
296fn collection_mut_risky(&mut self) -> &mut Self::Collection;
297298/// Creates a new [`RelationshipTarget`] from the given [`RelationshipTarget::Collection`].
299 ///
300 /// # Warning
301 /// This should generally not be called by user code, as constructing the internal collection could invalidate the relationship.
302 /// The collection should not contain duplicates.
303fn from_collection_risky(collection: Self::Collection) -> Self;
304305/// The `on_discard` component hook that maintains the [`Relationship`] / [`RelationshipTarget`] connection.
306// note: think of this as "on_drop"
307fn on_discard(
308mut world: DeferredWorld,
309HookContext {
310 entity,
311 relationship_hook_mode,
312 ..
313 }: HookContext,
314 ) {
315match relationship_hook_mode {
316 RelationshipHookMode::Run => {}
317// For RelationshipTarget we don't want to run this hook even if it isn't linked, but for Relationship we do.
318RelationshipHookMode::Skip | RelationshipHookMode::RunIfNotLinked => return,
319 }
320let (entities, mut commands) = world.entities_and_commands();
321let relationship_target = entities.get(entity).unwrap().get::<Self>().unwrap();
322for source_entity in relationship_target.iter() {
323 commands
324 .entity(source_entity)
325 .try_remove::<Self::Relationship>();
326 }
327 }
328329/// The `on_despawn` component hook that despawns entities stored in an entity's [`RelationshipTarget`] when
330 /// that entity is despawned.
331// note: think of this as "on_drop"
332fn on_despawn(mut world: DeferredWorld, HookContext { entity, .. }: HookContext) {
333let (entities, mut commands) = world.entities_and_commands();
334let relationship_target = entities.get(entity).unwrap().get::<Self>().unwrap();
335for source_entity in relationship_target.iter() {
336 commands.entity(source_entity).try_despawn();
337 }
338 }
339340/// Creates this [`RelationshipTarget`] with the given pre-allocated entity capacity.
341fn with_capacity(capacity: usize) -> Self {
342let collection =
343 <Self::Collection as RelationshipSourceCollection>::with_capacity(capacity);
344Self::from_collection_risky(collection)
345 }
346347/// Iterates the entities stored in this collection.
348#[inline]
349fn iter(&self) -> SourceIter<'_, Self> {
350self.collection().iter()
351 }
352353/// Returns the number of entities in this collection.
354#[inline]
355fn len(&self) -> usize {
356self.collection().len()
357 }
358359/// Returns true if this entity collection is empty.
360#[inline]
361fn is_empty(&self) -> bool {
362self.collection().is_empty()
363 }
364}
365366/// The "clone behavior" for [`RelationshipTarget`]. The [`RelationshipTarget`] will be populated with the proper components
367/// when the corresponding [`Relationship`] sources of truth are inserted. Cloning the actual entities
368/// in the original [`RelationshipTarget`] would result in duplicates, so we don't do that!
369///
370/// This will also queue up clones of the relationship sources if the [`EntityCloner`](crate::entity::EntityCloner) is configured
371/// to spawn recursively.
372pub fn clone_relationship_target<T: RelationshipTarget>(
373 component: &T,
374 cloned: &mut T,
375 context: &mut ComponentCloneCtx,
376) {
377if context.linked_cloning() && T::LINKED_SPAWN {
378let collection = cloned.collection_mut_risky();
379for entity in component.iter() {
380 collection.add(entity);
381 context.queue_entity_clone(entity);
382 }
383 } else if context.moving() {
384let target = context.target();
385let collection = cloned.collection_mut_risky();
386for entity in component.iter() {
387 collection.add(entity);
388 context.queue_deferred(move |world, _mapper| {
389// We don't want relationships hooks to run because we are manually constructing the collection here
390_ = 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}
400401/// Configures the conditions under which the Relationship insert/discard hooks will be run.
402#[derive(#[automatically_derived]
impl ::core::marker::Copy for RelationshipHookMode { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for RelationshipHookMode { }
#[automatically_derived]
impl ::core::clone::Clone for RelationshipHookMode {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for RelationshipHookMode {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
RelationshipHookMode::Run => "Run",
RelationshipHookMode::RunIfNotLinked => "RunIfNotLinked",
RelationshipHookMode::Skip => "Skip",
})
}
}Debug)]
403pub enum RelationshipHookMode {
404/// Relationship insert/discard hooks will always run
405Run,
406/// Relationship insert/discard hooks will run if [`RelationshipTarget::LINKED_SPAWN`] is false
407RunIfNotLinked,
408/// Relationship insert/discard hooks will always be skipped
409Skip,
410}
411412/// Wrapper for components clone specialization using autoderef.
413#[doc(hidden)]
414pub struct RelationshipCloneBehaviorSpecialization<T>(PhantomData<T>);
415416impl<T> Defaultfor RelationshipCloneBehaviorSpecialization<T> {
417fn default() -> Self {
418Self(PhantomData)
419 }
420}
421422/// Base trait for relationship clone specialization using autoderef.
423#[doc(hidden)]
424pub trait RelationshipCloneBehaviorBase {
425fn default_clone_behavior(&self) -> ComponentCloneBehavior;
426}
427428impl<C> RelationshipCloneBehaviorBasefor RelationshipCloneBehaviorSpecialization<C> {
429fn default_clone_behavior(&self) -> ComponentCloneBehavior {
430// Relationships currently must have `Clone`/`Reflect`-based handler for cloning/moving logic to properly work.
431ComponentCloneBehavior::Ignore432 }
433}
434435/// Specialized trait for relationship clone specialization using autoderef.
436#[doc(hidden)]
437pub trait RelationshipCloneBehaviorViaReflect {
438fn default_clone_behavior(&self) -> ComponentCloneBehavior;
439}
440441#[cfg(feature = "bevy_reflect")]
442impl<C: Relationship + bevy_reflect::Reflect> RelationshipCloneBehaviorViaReflect443for &RelationshipCloneBehaviorSpecialization<C>
444{
445fn default_clone_behavior(&self) -> ComponentCloneBehavior {
446ComponentCloneBehavior::reflect()
447 }
448}
449450/// Specialized trait for relationship clone specialization using autoderef.
451#[doc(hidden)]
452pub trait RelationshipCloneBehaviorViaClone {
453fn default_clone_behavior(&self) -> ComponentCloneBehavior;
454}
455456impl<C: Relationship + Clone> RelationshipCloneBehaviorViaClone457for &&RelationshipCloneBehaviorSpecialization<C>
458{
459fn default_clone_behavior(&self) -> ComponentCloneBehavior {
460ComponentCloneBehavior::clone::<C>()
461 }
462}
463464/// Specialized trait for relationship target clone specialization using autoderef.
465#[doc(hidden)]
466pub trait RelationshipTargetCloneBehaviorViaReflect {
467fn default_clone_behavior(&self) -> ComponentCloneBehavior;
468}
469470#[cfg(feature = "bevy_reflect")]
471impl<C: RelationshipTarget + bevy_reflect::Reflect + bevy_reflect::TypePath>
472RelationshipTargetCloneBehaviorViaReflectfor &&&RelationshipCloneBehaviorSpecialization<C>
473{
474fn default_clone_behavior(&self) -> ComponentCloneBehavior {
475 ComponentCloneBehavior::Custom(|source, context| {
476if let Some(component) = source.read::<C>()
477 && let Ok(mut cloned) = component.reflect_clone_and_take::<C>()
478 {
479cloned.collection_mut_risky().clear();
480clone_relationship_target(component, &mut cloned, context);
481context.write_target_component(cloned);
482 }
483 })
484 }
485}
486487/// Specialized trait for relationship target clone specialization using autoderef.
488#[doc(hidden)]
489pub trait RelationshipTargetCloneBehaviorViaClone {
490fn default_clone_behavior(&self) -> ComponentCloneBehavior;
491}
492493impl<C: RelationshipTarget + Clone> RelationshipTargetCloneBehaviorViaClone494for &&&&RelationshipCloneBehaviorSpecialization<C>
495{
496fn default_clone_behavior(&self) -> ComponentCloneBehavior {
497 ComponentCloneBehavior::Custom(|source, context| {
498if let Some(component) = source.read::<C>() {
499let mut cloned = component.clone();
500cloned.collection_mut_risky().clear();
501clone_relationship_target(component, &mut cloned, context);
502context.write_target_component(cloned);
503 }
504 })
505 }
506}
507508/// We know there's no additional data on Children, so this handler is an optimization to avoid cloning the entire Collection.
509#[doc(hidden)]
510pub trait RelationshipTargetCloneBehaviorHierarchy {
511fn default_clone_behavior(&self) -> ComponentCloneBehavior;
512}
513514impl RelationshipTargetCloneBehaviorHierarchy515for &&&&&RelationshipCloneBehaviorSpecialization<crate::hierarchy::Children>
516{
517fn default_clone_behavior(&self) -> ComponentCloneBehavior {
518 ComponentCloneBehavior::Custom(|source, context| {
519if let Some(component) = source.read::<crate::hierarchy::Children>() {
520let mut cloned = crate::hierarchy::Children::with_capacity(component.len());
521clone_relationship_target(component, &mut cloned, context);
522context.write_target_component(cloned);
523 }
524 })
525 }
526}
527528/// Initializer enum for [`RelationshipAccessor`] that allows to configure relationship for dynamic components.
529#[derive(#[automatically_derived]
impl ::core::clone::Clone for RelationshipAccessorInitializer {
#[inline]
fn clone(&self) -> Self {
match self {
Self::Relationship {
entity_field_offset: __self_0,
linked_spawn: __self_1,
allow_self_referential: __self_2,
relationship_target_getter: __self_3 } =>
Self::Relationship {
entity_field_offset: ::core::clone::Clone::clone(__self_0),
linked_spawn: ::core::clone::Clone::clone(__self_1),
allow_self_referential: ::core::clone::Clone::clone(__self_2),
relationship_target_getter: ::core::clone::Clone::clone(__self_3),
},
Self::RelationshipTarget {
iter: __self_0,
linked_spawn: __self_1,
allow_self_referential: __self_2,
relationship_getter: __self_3 } =>
Self::RelationshipTarget {
iter: ::core::clone::Clone::clone(__self_0),
linked_spawn: ::core::clone::Clone::clone(__self_1),
allow_self_referential: ::core::clone::Clone::clone(__self_2),
relationship_getter: ::core::clone::Clone::clone(__self_3),
},
}
}
}Clone)]
530pub enum RelationshipAccessorInitializer {
531/// Describes a [`Relationship`] component.
532Relationship {
533/// Offset of the field containing [`Entity`] from the base of the component.
534 ///
535 /// Dynamic equivalent of [`Relationship::get`].
536entity_field_offset: usize,
537/// Value of [`RelationshipTarget::LINKED_SPAWN`] for the [`Relationship::RelationshipTarget`] of this [`Relationship`].
538linked_spawn: bool,
539/// Value of [`Relationship::ALLOW_SELF_REFERENTIAL`] of this [`Relationship`].
540allow_self_referential: bool,
541/// Getter for [`ComponentId`] of the [`RelationshipTarget`] counterpart.
542 /// Should return `None` if [`RelationshipTarget`] isn't registered yet.
543relationship_target_getter: Arc<dyn Fn(&Components) -> Option<ComponentId>>,
544 },
545/// Describes a [`RelationshipTarget`] component.
546RelationshipTarget {
547/// Function that returns an iterator over all [`Entity`]s of this [`RelationshipTarget`]'s collection.
548 ///
549 /// Dynamic equivalent of [`RelationshipTarget::iter`].
550 /// # Safety
551 /// Passed pointer must point to the value of the same component as the one that this accessor was registered to.
552iter: for<'a> unsafe fn(Ptr<'a>) -> Box<dyn Iterator<Item = Entity> + 'a>,
553/// Value of [`RelationshipTarget::LINKED_SPAWN`] of this [`RelationshipTarget`].
554linked_spawn: bool,
555/// Value of [`Relationship::ALLOW_SELF_REFERENTIAL`] for the [`Relationship`] of this [`RelationshipTarget`].
556allow_self_referential: bool,
557/// Getter for [`ComponentId`] of the [`Relationship`] counterpart.
558 /// Should return `None` if [`Relationship`] isn't registered yet.
559relationship_getter: Arc<dyn Fn(&Components) -> Option<ComponentId>>,
560 },
561}
562563impl core::fmt::Debugfor RelationshipAccessorInitializer {
564fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
565match self {
566Self::Relationship {
567 entity_field_offset,
568 linked_spawn,
569 allow_self_referential,
570 relationship_target_getter: _,
571 } => f572 .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(),
577Self::RelationshipTarget {
578 iter,
579 linked_spawn,
580 allow_self_referential,
581 relationship_getter: _,
582 } => f583 .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}
591592#[derive(#[automatically_derived]
impl ::core::clone::Clone for MaybeRelationshipAccessor {
#[inline]
fn clone(&self) -> Self {
match self {
Self::NoAccessor => Self::NoAccessor,
Self::Initializer(__self_0) =>
Self::Initializer(::core::clone::Clone::clone(__self_0)),
Self::Accessor(__self_0) =>
Self::Accessor(::core::clone::Clone::clone(__self_0)),
}
}
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for MaybeRelationshipAccessor {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::NoAccessor =>
::core::fmt::Formatter::write_str(f, "NoAccessor"),
Self::Initializer(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"Initializer", &__self_0),
Self::Accessor(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"Accessor", &__self_0),
}
}
}Debug, #[automatically_derived]
impl ::core::default::Default for MaybeRelationshipAccessor {
#[inline]
fn default() -> Self { Self::NoAccessor }
}Default)]
593pub(crate) enum MaybeRelationshipAccessor {
594/// Not a relationship
595#[default]
596NoAccessor,
597/// Uninitialized relationship, which will be initialized when the second component of the relationship is registered.
598 /// Boxed to reduce size overhead.
599Initializer(Box<RelationshipAccessorInitializer>),
600/// Relationship
601Accessor(RelationshipAccessor),
602}
603604impl MaybeRelationshipAccessor {
605/// Returns [`RelationshipAccessor`] if this component is a part of relationship and the accessor is initialized.
606pub fn accessor(&self) -> Option<&RelationshipAccessor> {
607match self {
608 MaybeRelationshipAccessor::Accessor(relationship_accessor) => {
609Some(relationship_accessor)
610 }
611_ => None,
612 }
613 }
614615/// Initializes the relationship accessor if it isn't initialized already and the counterpart is registered.
616pub fn initialize(&mut self, id: ComponentId, components: &mut Components) {
617_ = (|| {
618let accessor = self.initializer_to_accessor(|getter| getter(components))?;
619let counterpart_id = accessor.counterpart_id();
620let counterpart_slot = components.get_relationship_accessor_mut(counterpart_id)?;
621let counterpart_accessor = counterpart_slot.initializer_to_accessor(|_| Some(id))?;
622*counterpart_slot = MaybeRelationshipAccessor::Accessor(counterpart_accessor);
623*self = MaybeRelationshipAccessor::Accessor(accessor);
624Some(())
625 })();
626 }
627628fn initializer_to_accessor(
629&self,
630 mapper: impl FnOnce(&dyn Fn(&Components) -> Option<ComponentId>) -> Option<ComponentId>,
631 ) -> Option<RelationshipAccessor> {
632let MaybeRelationshipAccessor::Initializer(initializer) = selfelse {
633return None;
634 };
635Some(match *initializer.as_ref() {
636 RelationshipAccessorInitializer::Relationship {
637 entity_field_offset,
638 linked_spawn,
639 allow_self_referential,
640ref relationship_target_getter,
641 } => {
642let relationship_target = mapper(relationship_target_getter.as_ref())?;
643 RelationshipAccessor::Relationship {
644entity_field_offset,
645linked_spawn,
646allow_self_referential,
647relationship_target,
648 }
649 }
650 RelationshipAccessorInitializer::RelationshipTarget {
651 iter,
652 linked_spawn,
653 allow_self_referential,
654ref relationship_getter,
655 } => {
656let relationship = mapper(relationship_getter.as_ref())?;
657 RelationshipAccessor::RelationshipTarget {
658iter,
659linked_spawn,
660allow_self_referential,
661relationship,
662 }
663 }
664 })
665 }
666}
667668impl From<Option<RelationshipAccessorInitializer>> for MaybeRelationshipAccessor {
669fn from(value: Option<RelationshipAccessorInitializer>) -> Self {
670value671 .map(|v| MaybeRelationshipAccessor::Initializer(Box::new(v)))
672 .unwrap_or(MaybeRelationshipAccessor::NoAccessor)
673 }
674}
675676/// This enum describes a way to access the entities of [`Relationship`] and [`RelationshipTarget`] components
677/// in a type-erased context.
678#[derive(#[automatically_derived]
impl ::core::fmt::Debug for RelationshipAccessor {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::Relationship {
entity_field_offset: __self_0,
linked_spawn: __self_1,
allow_self_referential: __self_2,
relationship_target: __self_3 } =>
::core::fmt::Formatter::debug_struct_field4_finish(f,
"Relationship", "entity_field_offset", __self_0,
"linked_spawn", __self_1, "allow_self_referential",
__self_2, "relationship_target", &__self_3),
Self::RelationshipTarget {
iter: __self_0,
linked_spawn: __self_1,
allow_self_referential: __self_2,
relationship: __self_3 } =>
::core::fmt::Formatter::debug_struct_field4_finish(f,
"RelationshipTarget", "iter", __self_0, "linked_spawn",
__self_1, "allow_self_referential", __self_2,
"relationship", &__self_3),
}
}
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for RelationshipAccessor { }
#[automatically_derived]
impl ::core::clone::Clone for RelationshipAccessor {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<usize>;
let _: ::core::clone::AssertParamIsClone<bool>;
let _: ::core::clone::AssertParamIsClone<ComponentId>;
let _:
::core::clone::AssertParamIsClone<for<'a> unsafe fn(Ptr<'a>)
-> Box<dyn Iterator<Item = Entity> + 'a>>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for RelationshipAccessor { }Copy)]
679pub enum RelationshipAccessor {
680/// This component is a [`Relationship`].
681Relationship {
682/// Offset of the field containing [`Entity`] from the base of the component.
683 ///
684 /// Dynamic equivalent of [`Relationship::get`].
685entity_field_offset: usize,
686/// Value of [`RelationshipTarget::LINKED_SPAWN`] for the [`Relationship::RelationshipTarget`] of this [`Relationship`].
687linked_spawn: bool,
688/// Value of [`Relationship::ALLOW_SELF_REFERENTIAL`] of this [`Relationship`].
689allow_self_referential: bool,
690/// [`ComponentId`] of the [`RelationshipTarget`] counterpart.
691relationship_target: ComponentId,
692 },
693/// This component is a [`RelationshipTarget`].
694RelationshipTarget {
695/// Function that returns an iterator over all [`Entity`]s of this [`RelationshipTarget`]'s collection.
696 ///
697 /// Dynamic equivalent of [`RelationshipTarget::iter`].
698 /// # Safety
699 /// Passed pointer must point to the value of the same component as the one that this accessor was registered to.
700iter: for<'a> unsafe fn(Ptr<'a>) -> Box<dyn Iterator<Item = Entity> + 'a>,
701/// Value of [`RelationshipTarget::LINKED_SPAWN`] of this [`RelationshipTarget`].
702linked_spawn: bool,
703/// Value of [`Relationship::ALLOW_SELF_REFERENTIAL`] for the [`Relationship`] of this [`RelationshipTarget`].
704allow_self_referential: bool,
705/// [`ComponentId`] of the [`Relationship`] counterpart.
706relationship: ComponentId,
707 },
708}
709710impl RelationshipAccessor {
711/// Returns [`ComponentId`] of [`RelationshipTarget`] for this [`Relationship`] and vice-versa.
712pub fn counterpart_id(&self) -> ComponentId {
713match self {
714 RelationshipAccessor::Relationship {
715 relationship_target,
716 ..
717 } => *relationship_target,
718 RelationshipAccessor::RelationshipTarget { relationship, .. } => *relationship,
719 }
720 }
721722/// Returns the value of [`RelationshipTarget::LINKED_SPAWN`].
723pub fn linked_spawn(&self) -> bool {
724match self {
725 RelationshipAccessor::Relationship { linked_spawn, .. }
726 | RelationshipAccessor::RelationshipTarget { linked_spawn, .. } => *linked_spawn,
727 }
728 }
729730/// Returns the value of [`Relationship::ALLOW_SELF_REFERENTIAL`].
731pub fn allow_self_referential(&self) -> bool {
732match 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}
744745/// A type-safe convenience wrapper over [`RelationshipAccessor`].
746pub struct ComponentRelationshipAccessor<C: ?Sized> {
747pub(crate) initializer: RelationshipAccessorInitializer,
748 phantom: PhantomData<C>,
749}
750751impl<C> ComponentRelationshipAccessor<C> {
752/// Create a new [`ComponentRelationshipAccessor`] for a [`Relationship`] component.
753 /// # Safety
754 /// `entity_field_offset` should be the offset from the base of this component and point to a field that stores value of type [`Entity`].
755 /// This value can be obtained using the [`core::mem::offset_of`] macro.
756pub unsafe fn relationship(entity_field_offset: usize) -> Self
757where
758C: Relationship,
759 {
760// Due to https://github.com/taiki-e/portable-atomic/issues/143 we have to box this first, and then get the Arc from the box
761let getter: Box<dyn Fn(&Components) -> Option<ComponentId>> =
762Box::new(|components| components.get_id(TypeId::of::<C::RelationshipTarget>()));
763Self {
764 initializer: RelationshipAccessorInitializer::Relationship {
765entity_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 }
773774/// Create a new [`ComponentRelationshipAccessor`] for a [`RelationshipTarget`] component.
775pub fn relationship_target() -> Self
776where
777C: RelationshipTarget,
778 {
779// Due to https://github.com/taiki-e/portable-atomic/issues/143 we have to box this first, and then get the Arc from the box
780let getter: Box<dyn Fn(&Components) -> Option<ComponentId>> =
781Box::new(|components| components.get_id(TypeId::of::<C::Relationship>()));
782Self {
783 initializer: RelationshipAccessorInitializer::RelationshipTarget {
784// Safety: caller ensures that `ptr` is of type `C`.
785iter: |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}
794795#[cfg(test)]
796mod tests {
797use core::marker::PhantomData;
798use core::sync::atomic::AtomicBool;
799800use crate::lifecycle::HookContext;
801use crate::prelude::{ChildOf, Children};
802use crate::relationship::{Relationship, RelationshipAccessor};
803use crate::world::{DeferredWorld, World};
804use crate::{component::Component, entity::Entity};
805use alloc::vec::Vec;
806807#[test]
808fn custom_relationship() {
809#[derive(Component)]
810 #[relationship(relationship_target = LikedBy)]
811struct Likes(pub Entity);
812813#[derive(Component)]
814 #[relationship_target(relationship = Likes)]
815struct LikedBy(Vec<Entity>);
816817let mut world = World::new();
818let a = world.spawn_empty().id();
819let b = world.spawn(Likes(a)).id();
820let c = world.spawn(Likes(a)).id();
821assert_eq!(world.entity(a).get::<LikedBy>().unwrap().0, &[b, c]);
822 }
823824#[test]
825fn self_relationship_fails_by_default() {
826#[derive(Component)]
827 #[relationship(relationship_target = RelTarget)]
828struct Rel(Entity);
829830#[derive(Component)]
831 #[relationship_target(relationship = Rel)]
832struct RelTarget(Vec<Entity>);
833834let mut world = World::new();
835let a = world.spawn_empty().id();
836 world.entity_mut(a).insert(Rel(a));
837assert!(!world.entity(a).contains::<Rel>());
838assert!(!world.entity(a).contains::<RelTarget>());
839 }
840841#[test]
842fn self_relationship_succeeds_with_allow_self_referential() {
843#[derive(Component)]
844 #[relationship(relationship_target = RelTarget, allow_self_referential)]
845struct Rel(Entity);
846847#[derive(Component)]
848 #[relationship_target(relationship = Rel)]
849struct RelTarget(Vec<Entity>);
850851let mut world = World::new();
852let a = world.spawn_empty().id();
853 world.entity_mut(a).insert(Rel(a));
854assert!(world.entity(a).contains::<Rel>());
855assert!(world.entity(a).contains::<RelTarget>());
856assert_eq!(world.entity(a).get::<Rel>().unwrap().get(), a);
857assert_eq!(&*world.entity(a).get::<RelTarget>().unwrap().0, &[a]);
858 }
859860#[test]
861fn self_relationship_removal_with_allow_self_referential() {
862#[derive(Component)]
863 #[relationship(relationship_target = RelTarget, allow_self_referential)]
864struct Rel(Entity);
865866#[derive(Component)]
867 #[relationship_target(relationship = Rel)]
868struct RelTarget(Vec<Entity>);
869870let mut world = World::new();
871let a = world.spawn_empty().id();
872 world.entity_mut(a).insert(Rel(a));
873assert!(world.entity(a).contains::<Rel>());
874assert!(world.entity(a).contains::<RelTarget>());
875876// Remove the relationship and verify cleanup
877world.entity_mut(a).remove::<Rel>();
878assert!(!world.entity(a).contains::<Rel>());
879assert!(!world.entity(a).contains::<RelTarget>());
880 }
881882#[test]
883fn relationship_with_missing_target_fails() {
884#[derive(Component)]
885 #[relationship(relationship_target = RelTarget)]
886struct Rel(Entity);
887888#[derive(Component)]
889 #[relationship_target(relationship = Rel)]
890struct RelTarget(Vec<Entity>);
891892let mut world = World::new();
893let a = world.spawn_empty().id();
894 world.despawn(a);
895let b = world.spawn(Rel(a)).id();
896assert!(!world.entity(b).contains::<Rel>());
897assert!(!world.entity(b).contains::<RelTarget>());
898 }
899900#[test]
901fn 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)]
908struct Source {
909#[relationship]
910target: Entity,
911 foo: u8,
912 bar: u8,
913 }
914915#[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)]
921struct Target(Vec<Entity>);
922923// No assert necessary, looking to make sure compilation works with the macros
924}
925#[test]
926fn 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)]
933struct Source(Entity);
934935#[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)]
941struct Target {
942#[relationship]
943target: Vec<Entity>,
944 foo: u8,
945 bar: u8,
946 }
947948// No assert necessary, looking to make sure compilation works with the macros
949}
950951#[test]
952fn 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>)]
959struct Source<T: Send + Sync + 'static>(#[relationship] Entity, PhantomData<T>);
960961#[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>)]
967struct Target<T: Send + Sync + 'static>(#[relationship] Vec<Entity>, PhantomData<T>);
968969// No assert necessary, looking to make sure compilation works with the macros
970}
971972#[test]
973fn parent_child_relationship_with_custom_relationship() {
974#[derive(Component)]
975 #[relationship(relationship_target = RelTarget)]
976struct Rel(Entity);
977978#[derive(Component)]
979 #[relationship_target(relationship = Rel)]
980struct RelTarget(Entity);
981982let mut world = World::new();
983984// Rel on Parent
985 // Despawn Parent
986let mut commands = world.commands();
987let child = commands.spawn_empty().id();
988let parent = commands.spawn(Rel(child)).add_child(child).id();
989 commands.entity(parent).despawn();
990 world.flush();
991992assert!(world.get_entity(child).is_err());
993assert!(world.get_entity(parent).is_err());
994995// Rel on Parent
996 // Despawn Child
997let mut commands = world.commands();
998let child = commands.spawn_empty().id();
999let parent = commands.spawn(Rel(child)).add_child(child).id();
1000 commands.entity(child).despawn();
1001 world.flush();
10021003assert!(world.get_entity(child).is_err());
1004assert!(!world.entity(parent).contains::<Rel>());
10051006// Rel on Child
1007 // Despawn Parent
1008let mut commands = world.commands();
1009let parent = commands.spawn_empty().id();
1010let child = commands.spawn((ChildOf(parent), Rel(parent))).id();
1011 commands.entity(parent).despawn();
1012 world.flush();
10131014assert!(world.get_entity(child).is_err());
1015assert!(world.get_entity(parent).is_err());
10161017// Rel on Child
1018 // Despawn Child
1019let mut commands = world.commands();
1020let parent = commands.spawn_empty().id();
1021let child = commands.spawn((ChildOf(parent), Rel(parent))).id();
1022 commands.entity(child).despawn();
1023 world.flush();
10241025assert!(world.get_entity(child).is_err());
1026assert!(!world.entity(parent).contains::<RelTarget>());
1027 }
10281029#[test]
1030fn spawn_batch_with_relationship() {
1031let mut world = World::new();
1032let parent = world.spawn_empty().id();
1033let children = world
1034 .spawn_batch((0..10).map(|_| ChildOf(parent)))
1035 .collect::<Vec<_>>();
10361037for &child in &children {
1038assert!(world
1039 .get::<ChildOf>(child)
1040 .is_some_and(|child_of| child_of.parent() == parent));
1041 }
1042assert!(world
1043 .get::<Children>(parent)
1044 .is_some_and(|children| children.len() == 10));
1045 }
10461047#[test]
1048fn insert_batch_with_relationship() {
1049let mut world = World::new();
1050let parent = world.spawn_empty().id();
1051let child = world.spawn_empty().id();
1052 world.insert_batch([(child, ChildOf(parent))]);
1053 world.flush();
10541055assert!(world.get::<ChildOf>(child).is_some());
1056assert!(world.get::<Children>(parent).is_some());
1057 }
10581059#[test]
1060fn dynamically_traverse_hierarchy() {
1061let mut world = World::new();
1062let child_of_id = world.register_component::<ChildOf>();
1063let children_id = world.register_component::<Children>();
10641065let parent = world.spawn_empty().id();
1066let child = world.spawn_empty().id();
1067 world.entity_mut(child).insert(ChildOf(parent));
1068 world.flush();
10691070let children_ptr = world.get_by_id(parent, children_id).unwrap();
1071let RelationshipAccessor::RelationshipTarget { iter, .. } = world
1072 .components()
1073 .get_info(children_id)
1074 .unwrap()
1075 .relationship_accessor()
1076 .unwrap()
1077else {
1078unreachable!()
1079 };
1080// Safety: `children_ptr` contains value of the same type as the one this accessor was registered for.
1081let children: Vec<_> = unsafe { iter(children_ptr).collect() };
1082assert_eq!(children, alloc::vec![child]);
10831084let child_of_ptr = world.get_by_id(child, child_of_id).unwrap();
1085let RelationshipAccessor::Relationship {
1086 entity_field_offset,
1087 ..
1088 } = world
1089 .components()
1090 .get_info(child_of_id)
1091 .unwrap()
1092 .relationship_accessor()
1093 .unwrap()
1094else {
1095unreachable!()
1096 };
1097// Safety:
1098 // - offset is in bounds, aligned and has the same lifetime as the original pointer.
1099 // - value at offset is guaranteed to be a valid Entity
1100let child_of_entity: Entity =
1101unsafe { *child_of_ptr.byte_add(*entity_field_offset).deref() };
1102assert_eq!(child_of_entity, parent);
1103 }
11041105#[test]
1106fn relationship_accessor() {
1107#[derive(Component)]
1108 #[relationship(relationship_target = LikedBy)]
1109struct Likes {
1110 _a: u16,
1111#[relationship]
1112e: Entity,
1113 _b: (i8, u8),
1114 }
11151116#[derive(Component)]
1117 #[relationship_target(relationship = Likes)]
1118struct LikedBy(Vec<Entity>);
11191120let mut world = World::new();
1121let likes_id = world.register_component::<Likes>();
1122let liked_by_id = world.register_component::<LikedBy>();
11231124let likes_accessor = world
1125 .components()
1126 .get_info(likes_id)
1127 .unwrap()
1128 .relationship_accessor()
1129 .unwrap();
1130match *likes_accessor {
1131 RelationshipAccessor::Relationship {
1132 entity_field_offset,
1133 linked_spawn,
1134 allow_self_referential,
1135 relationship_target,
1136 } => {
1137assert_eq!(entity_field_offset, core::mem::offset_of!(Likes, e));
1138assert!(!linked_spawn);
1139assert!(!allow_self_referential);
1140assert_eq!(relationship_target, liked_by_id);
1141 }
1142_ => {
1143panic!("Not a Relationship")
1144 }
1145 }
11461147let liked_by_accessor = world
1148 .components()
1149 .get_info(liked_by_id)
1150 .unwrap()
1151 .relationship_accessor()
1152 .unwrap();
1153match *liked_by_accessor {
1154 RelationshipAccessor::RelationshipTarget {
1155 iter,
1156 linked_spawn,
1157 allow_self_referential,
1158 relationship,
1159 } => {
1160let liked_by = LikedBy(alloc::vec![
1161 world.spawn_empty().id(),
1162 world.spawn_empty().id(),
1163 world.spawn_empty().id()
1164 ]);
1165// SAFETY: liked_by is of type LikedBy
1166unsafe {
1167assert_eq!(iter((&liked_by).into()).collect::<Vec<_>>(), liked_by.0);
1168 }
1169assert!(!linked_spawn);
1170assert!(!allow_self_referential);
1171assert_eq!(relationship, likes_id);
1172 }
1173_ => {
1174panic!("Not a RelationshipTarget")
1175 }
1176 }
11771178#[derive(Component)]
1179 #[relationship(relationship_target = RelTarget, allow_self_referential)]
1180struct Rel(Entity);
11811182#[derive(Component)]
1183 #[relationship_target(relationship = Rel, linked_spawn)]
1184struct RelTarget(Vec<Entity>);
11851186let rel_id = world.register_component::<Rel>();
1187let rel_target_id = world.register_component::<RelTarget>();
11881189let rel_accessor = world
1190 .components()
1191 .get_info(rel_id)
1192 .unwrap()
1193 .relationship_accessor()
1194 .unwrap();
1195assert!(rel_accessor.linked_spawn());
1196assert!(rel_accessor.allow_self_referential());
1197let rel_target_accessor = world
1198 .components()
1199 .get_info(rel_target_id)
1200 .unwrap()
1201 .relationship_accessor()
1202 .unwrap();
1203assert!(rel_target_accessor.linked_spawn());
1204assert!(rel_target_accessor.allow_self_referential());
1205 }
12061207#[test]
1208pub fn component_hooks_compatibility() {
1209static ADD_CALLED: AtomicBool = AtomicBool::new(false);
1210static INSERT_CALLED: AtomicBool = AtomicBool::new(false);
1211static DISCARD_CALLED: AtomicBool = AtomicBool::new(false);
1212static REMOVE_CALLED: AtomicBool = AtomicBool::new(false);
1213static DESPAWN_CALLED: AtomicBool = AtomicBool::new(false);
12141215#[derive(Component)]
1216 #[relationship(relationship_target = RelTarget)]
1217 #[component(on_add, on_insert, on_discard, on_remove, on_despawn)]
1218struct Rel(Entity);
12191220#[derive(Component)]
1221 #[relationship_target(relationship = Rel)]
1222struct RelTarget(Entity);
12231224impl Rel {
1225fn on_add(world: DeferredWorld, context: HookContext) {
1226let &Rel(target) = world.get(context.entity).unwrap();
1227assert!(!world.entity(target).contains::<RelTarget>());
1228 ADD_CALLED.store(true, core::sync::atomic::Ordering::Relaxed);
1229 }
12301231fn on_insert(world: DeferredWorld, context: HookContext) {
1232let &Rel(target) = world.get(context.entity).unwrap();
1233assert!(!world.entity(target).contains::<RelTarget>());
1234 INSERT_CALLED.store(true, core::sync::atomic::Ordering::Relaxed);
1235 }
12361237fn on_discard(world: DeferredWorld, context: HookContext) {
1238let &Rel(target) = world.get(context.entity).unwrap();
1239assert!(world.entity(target).contains::<RelTarget>());
1240 DISCARD_CALLED.store(true, core::sync::atomic::Ordering::Relaxed);
1241 }
12421243fn on_remove(world: DeferredWorld, context: HookContext) {
1244let &Rel(target) = world.get(context.entity).unwrap();
1245assert!(world.entity(target).contains::<RelTarget>());
1246 REMOVE_CALLED.store(true, core::sync::atomic::Ordering::Relaxed);
1247 }
12481249fn on_despawn(world: DeferredWorld, context: HookContext) {
1250let &Rel(target) = world.get(context.entity).unwrap();
1251assert!(world.entity(target).contains::<RelTarget>());
1252 DESPAWN_CALLED.store(true, core::sync::atomic::Ordering::Relaxed);
1253 }
1254 }
12551256let mut world = World::new();
1257let target = world.spawn_empty().id();
1258let source = world.spawn(Rel(target)).id();
1259assert!(world.entity(target).contains::<RelTarget>());
1260assert!(ADD_CALLED.load(core::sync::atomic::Ordering::Relaxed));
1261assert!(INSERT_CALLED.load(core::sync::atomic::Ordering::Relaxed));
1262 world.despawn(source);
1263assert!(DISCARD_CALLED.load(core::sync::atomic::Ordering::Relaxed));
1264assert!(REMOVE_CALLED.load(core::sync::atomic::Ordering::Relaxed));
1265assert!(DESPAWN_CALLED.load(core::sync::atomic::Ordering::Relaxed));
1266 }
1267}