aery/
edges.rs

1use std::marker::PhantomData;
2
3use smallvec::SmallVec;
4
5use bevy_derive::{Deref, DerefMut};
6use bevy_ecs::{
7    component::{Component, ComponentHooks, ComponentId, StorageType},
8    entity::{Entity, EntityMapper, MapEntities},
9    event::Event,
10    query::{AnyOf, Changed, Or, QueryData, QueryFilter, With, Without},
11    reflect::{ReflectComponent, ReflectMapEntities},
12    system::EntityCommands,
13    world::{Command, DeferredWorld, EntityWorldMut, World},
14};
15use bevy_hierarchy::{Children, Parent};
16use bevy_log::warn;
17use bevy_reflect::{utility::GenericTypePathCell, Reflect, TypePath};
18
19use crate::relation::{CleanupPolicy, Relation, ZstOrPanic};
20
21// Small Stable Unique Vec
22#[derive(Reflect)]
23pub(crate) struct SSUVec<T: PartialEq> {
24    pub vec: SmallVec<[T; 1]>,
25}
26
27impl<T: PartialEq> Default for SSUVec<T> {
28    fn default() -> Self {
29        Self {
30            vec: SmallVec::default(),
31        }
32    }
33}
34
35impl<T: PartialEq> SSUVec<T> {
36    pub(crate) fn add(&mut self, val: T) {
37        if self.vec.iter().all(|item| *item != val) {
38            self.vec.push(val)
39        }
40    }
41
42    pub(crate) fn remove(&mut self, val: T) -> bool {
43        if let Some(n) = self
44            .vec
45            .iter()
46            .enumerate()
47            .find_map(|(n, item)| (*item == val).then_some(n))
48        {
49            self.vec.remove(n);
50            true
51        } else {
52            false
53        }
54    }
55}
56
57// For cleanup types:
58// - Orphan
59// - Counted
60pub(crate) fn unset_edges<R: Relation>(mut world: DeferredWorld, id: Entity, _: ComponentId) {
61    let hosts = world
62        .get_mut::<Hosts<R>>(id)
63        .map(|mut hosts| std::mem::take(&mut hosts.vec.vec))
64        .unwrap_or_default();
65
66    let targets = world
67        .get_mut::<Targets<R>>(id)
68        .map(|mut targets| std::mem::take(&mut targets.vec.vec))
69        .unwrap_or_default();
70
71    let mut cmds = world.commands();
72
73    for host in hosts.iter().copied() {
74        cmds.queue(UnsetAsymmetric::<R>::buffered(host, id));
75    }
76
77    for target in targets.iter().copied() {
78        cmds.queue(UnsetAsymmetric::<R>::buffered(id, target));
79    }
80}
81
82// For cleanup types:
83// - Recrusive
84// - Total
85pub(crate) fn clean_recursive<R: Relation>(mut world: DeferredWorld, id: Entity, _: ComponentId) {
86    let hosts = world
87        .get_mut::<Hosts<R>>(id)
88        .map(|mut edges| std::mem::take(&mut edges.vec.vec))
89        .unwrap_or_default();
90
91    let targets = world
92        .get_mut::<Targets<R>>(id)
93        .map(|mut edges| std::mem::take(&mut edges.vec.vec))
94        .unwrap_or_default();
95
96    let mut cmds = world.commands();
97
98    for host in hosts.iter().copied() {
99        cmds.queue(move |world: &mut World| {
100            world.despawn(host);
101        });
102    }
103
104    for target in targets.iter().copied() {
105        cmds.queue(UnsetAsymmetric::<R>::buffered(id, target));
106    }
107}
108
109#[derive(Deref, DerefMut, Reflect)]
110#[reflect(Component, MapEntities, type_path = false, where R: Relation)]
111pub(crate) struct Hosts<R: Relation> {
112    #[deref]
113    pub(crate) vec: SSUVec<Entity>,
114    #[reflect(ignore)]
115    _phantom: PhantomData<R>,
116}
117
118impl<R: Relation> MapEntities for Hosts<R> {
119    fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
120        for entity in self.vec.vec.iter_mut() {
121            *entity = entity_mapper.map_entity(*entity);
122        }
123    }
124}
125
126impl<R: Relation> TypePath for Hosts<R> {
127    fn type_path() -> &'static str {
128        static CELL: GenericTypePathCell = GenericTypePathCell::new();
129        CELL.get_or_insert::<Self, _>(|| {
130            format!("aery::edges::Hosts<{}>", std::any::type_name::<R>())
131        })
132    }
133
134    fn short_type_path() -> &'static str {
135        static CELL: GenericTypePathCell = GenericTypePathCell::new();
136        CELL.get_or_insert::<Self, _>(|| format!("Hosts<{}>", std::any::type_name::<R>()))
137    }
138
139    fn type_ident() -> Option<&'static str> {
140        Some(std::any::type_name::<R>())
141    }
142
143    fn crate_name() -> Option<&'static str> {
144        Some("aery")
145    }
146}
147
148impl<R: Relation> Default for Hosts<R> {
149    fn default() -> Self {
150        Self {
151            vec: SSUVec::default(),
152            _phantom: PhantomData,
153        }
154    }
155}
156
157impl<R: Relation> Component for Hosts<R> {
158    const STORAGE_TYPE: StorageType = StorageType::Table;
159    fn register_component_hooks(hooks: &mut ComponentHooks) {
160        hooks.on_remove(match R::CLEANUP_POLICY {
161            CleanupPolicy::Orphan | CleanupPolicy::Counted => unset_edges::<R>,
162            CleanupPolicy::Recursive | CleanupPolicy::Total => clean_recursive::<R>,
163        });
164    }
165}
166
167#[derive(Deref, DerefMut, Reflect)]
168#[reflect(Component, MapEntities, type_path = false, where R: Relation)]
169pub(crate) struct Targets<R: Relation> {
170    #[deref]
171    pub(crate) vec: SSUVec<Entity>,
172    #[reflect(ignore)]
173    _phantom: PhantomData<R>,
174}
175
176impl<R: Relation> MapEntities for Targets<R> {
177    fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
178        for entity in self.vec.vec.iter_mut() {
179            *entity = entity_mapper.map_entity(*entity);
180        }
181    }
182}
183
184impl<R: Relation> TypePath for Targets<R> {
185    fn type_path() -> &'static str {
186        static CELL: GenericTypePathCell = GenericTypePathCell::new();
187        CELL.get_or_insert::<Self, _>(|| {
188            format!("aery::edges::Targets<{}>", std::any::type_name::<R>())
189        })
190    }
191
192    fn short_type_path() -> &'static str {
193        static CELL: GenericTypePathCell = GenericTypePathCell::new();
194        CELL.get_or_insert::<Self, _>(|| format!("Targets<{}>", std::any::type_name::<R>()))
195    }
196
197    fn type_ident() -> Option<&'static str> {
198        Some(std::any::type_name::<R>())
199    }
200
201    fn crate_name() -> Option<&'static str> {
202        Some("aery")
203    }
204}
205
206impl<R: Relation> Default for Targets<R> {
207    fn default() -> Self {
208        Self {
209            vec: SSUVec::default(),
210            _phantom: PhantomData,
211        }
212    }
213}
214
215impl<R: Relation> Component for Targets<R> {
216    const STORAGE_TYPE: StorageType = StorageType::Table;
217    fn register_component_hooks(hooks: &mut ComponentHooks) {
218        hooks.on_remove(match R::CLEANUP_POLICY {
219            CleanupPolicy::Orphan | CleanupPolicy::Counted => unset_edges::<R>,
220            CleanupPolicy::Recursive | CleanupPolicy::Total => clean_recursive::<R>,
221        });
222    }
223}
224
225#[allow(missing_docs)]
226pub type EdgeIter<'a> = std::iter::Copied<std::slice::Iter<'a, Entity>>;
227
228/// Edges world query for hierarchy compatibility
229#[derive(QueryData)]
230pub struct HierarchyEdges(pub(crate) AnyOf<(&'static Children, &'static Parent)>);
231
232/// World query to get the edge info of a Relation.
233#[derive(QueryData)]
234pub struct Edges<R: Relation>(pub(crate) AnyOf<(&'static Hosts<R>, &'static Targets<R>)>);
235
236/// Get information from a single edge bucket.
237pub trait EdgeInfo {
238    /// Get all hosts.
239    fn hosts(&self) -> &[Entity];
240    /// Get all targets.
241    fn targets(&self) -> &[Entity];
242}
243
244impl EdgeInfo for HierarchyEdgesItem<'_> {
245    fn hosts(&self) -> &[Entity] {
246        match self {
247            Self((Some(hosts), _)) => hosts,
248            _ => &[],
249        }
250    }
251
252    fn targets(&self) -> &[Entity] {
253        match self {
254            Self((_, Some(target))) => target.as_slice(),
255            _ => &[],
256        }
257    }
258}
259
260impl<R: Relation> EdgeInfo for EdgesItem<'_, R> {
261    fn hosts(&self) -> &[Entity] {
262        match self {
263            Self((Some(hosts), _)) => &hosts.vec.vec,
264            _ => &[],
265        }
266    }
267
268    fn targets(&self) -> &[Entity] {
269        match self {
270            Self((_, Some(targets))) => &targets.vec.vec,
271            _ => &[],
272        }
273    }
274}
275
276// Usually bad but needed for operation API glue
277impl<E: EdgeInfo> EdgeInfo for Option<E> {
278    fn hosts(&self) -> &[Entity] {
279        match self {
280            Some(edges) => edges.hosts(),
281            None => &[],
282        }
283    }
284
285    fn targets(&self) -> &[Entity] {
286        match self {
287            Some(edges) => edges.targets(),
288            None => &[],
289        }
290    }
291}
292
293/// Filter to find roots of a relationship graph.
294/// An entity is a root of `R` if:
295/// - It is targeted by atleast one other entity via `R`.
296/// - It does not target any other entity via `R`.
297#[derive(QueryFilter)]
298pub struct Root<R: Relation>((With<Hosts<R>>, Without<Targets<R>>));
299
300/// Filter to find branches of a relationship graph.
301/// A branch of `R` has **both** hosts and targets.
302#[derive(QueryFilter)]
303pub struct Branch<R: Relation>((With<Hosts<R>>, With<Targets<R>>));
304
305/// Filter to find leaves of a relationship graph.
306/// An entity is a leaf of `R` if:
307/// - It targets atleast 1 other entity via `R`.
308/// - It is not targeted by any other entity via `R`.
309#[derive(QueryFilter)]
310pub struct Leaf<R: Relation>((Without<Hosts<R>>, With<Targets<R>>));
311
312/// Filter to find participants of a relationship.
313/// A participant of `R` has **either** hosts or targets.
314#[derive(QueryFilter)]
315pub struct Participates<R: Relation>(Or<(With<Hosts<R>>, With<Targets<R>>)>);
316
317/// Filter to find entities that do not participante in a relationship.
318/// Ie. have no edges comming in or out.
319#[derive(QueryFilter)]
320pub struct Abstains<R: Relation>((Without<Hosts<R>>, Without<Targets<R>>));
321
322/// Filter to check entities that recently had a relation changed.
323#[derive(QueryFilter)]
324pub struct EdgeChanged<R: Relation>(Or<(Changed<Hosts<R>>, Changed<Targets<R>>)>);
325
326/// Event triggered whenever an entity gets a new relation
327#[derive(Event, Clone, Copy, Debug)]
328pub struct SetEvent<R: Relation> {
329    /// The target entity of the event. The triggers entity is the host.
330    pub target: Entity,
331    _phantom: PhantomData<R>,
332}
333
334/// Event triggered whenever an entity loses a relation
335#[derive(Event, Clone, Copy, Debug)]
336pub struct UnsetEvent<R: Relation> {
337    /// The target entity of the event. The triggers entity is the host.
338    pub target: Entity,
339    _phantom: PhantomData<R>,
340}
341
342/// Command to set a relationship target for an entity. If either of the participants do not exist
343/// or the host tries to target itself the operation will be ignored and logged.
344pub struct Set<R>
345where
346    R: Relation,
347{
348    host: Entity,
349    target: Entity,
350    symmetric_action: bool,
351    _phantom: PhantomData<R>,
352}
353
354impl<R: Relation> Set<R> {
355    #[allow(missing_docs)]
356    pub fn new(host: Entity, target: Entity) -> Self {
357        Self {
358            host,
359            target,
360            symmetric_action: false,
361            _phantom: PhantomData,
362        }
363    }
364}
365
366impl<R> Command for Set<R>
367where
368    R: Relation,
369{
370    fn apply(self, world: &mut World) {
371        let _ = R::ZST_OR_PANIC;
372
373        if self.host == self.target {
374            warn!(
375                "{host:?} Tried to target to itself with {rel}. \
376                Self referential relations are not allowed. \
377                Ignoring.",
378                host = self.host,
379                rel = std::any::type_name::<R>(),
380            );
381            return;
382        }
383
384        if world.get_entity(self.target).is_err() {
385            warn!(
386                "{host:?} tried to target {target:?} with {rel}. \
387                {target:?} does not exist. \
388                Ignoring.",
389                host = self.host,
390                target = self.target,
391                rel = std::any::type_name::<R>(),
392            );
393            return;
394        }
395
396        if world.get_entity(self.host).is_err() {
397            warn!(
398                "{host:?} tried to target {target:?} with {rel}. \
399                {host:?} does not exist. \
400                Ignoring.",
401                host = self.host,
402                target = self.target,
403                rel = std::any::type_name::<R>(),
404            );
405            return;
406        }
407
408        let mut old: Option<Entity> = None;
409
410        let mut host_entity = world.entity_mut(self.host);
411        if let Some(mut host_targets) = host_entity.get_mut::<Targets<R>>() {
412            // Check if this target is already present
413            if host_targets.vec.vec.contains(&self.target) {
414                return;
415            } else {
416                old = host_targets.vec.vec.first().copied();
417                host_targets.add(self.target);
418            }
419        } else {
420            // If Targets<R> doesn't exist on the host, create and insert a new one
421            let mut new_host_targets = Targets::<R>::default();
422            new_host_targets.add(self.target);
423            host_entity.insert(new_host_targets);
424        }
425
426        let mut target_entity = world.entity_mut(self.target);
427        if let Some(mut target_hosts) = target_entity.get_mut::<Hosts<R>>() {
428            // Check if this host is already present
429            if target_hosts.vec.vec.contains(&self.host) {
430                return;
431            } else {
432                target_hosts.vec.add(self.host);
433            }
434        } else {
435            // If Hosts<R> doesn't exist on the target, create and insert a new one
436            let mut new_target_hosts = Hosts::<R>::default();
437            new_target_hosts.vec.add(self.host);
438            target_entity.insert(new_target_hosts);
439        }
440
441        world.trigger_targets(
442            SetEvent::<R> {
443                target: self.target,
444                _phantom: PhantomData,
445            },
446            self.host,
447        );
448
449        // Symmetric set has to happen before exclusivity unset otherwise
450        // an entity can get despawned when it shouldn't.
451        if R::SYMMETRIC && !self.symmetric_action {
452            Command::apply(
453                Set::<R> {
454                    host: self.target,
455                    target: self.host,
456                    symmetric_action: true,
457                    _phantom: PhantomData,
458                },
459                world,
460            );
461        }
462
463        if let Some(old) = old.filter(|old| R::EXCLUSIVE && self.target != *old) {
464            Command::apply(UnsetAsymmetric::<R>::new(self.host, old), world);
465        }
466    }
467}
468
469/// Command to remove relationships between entities.
470/// This operation is not noisy so if either participant does not exist or
471/// the relation does not exist nothing happens.
472pub struct Unset<R>
473where
474    R: Relation,
475{
476    host: Entity,
477    target: Entity,
478    _phantom: PhantomData<R>,
479}
480
481impl<R: Relation> Unset<R> {
482    #[allow(missing_docs)]
483    pub fn new(host: Entity, target: Entity) -> Self {
484        Self {
485            host,
486            target,
487            _phantom: PhantomData,
488        }
489    }
490}
491
492impl<R: Relation> Command for Unset<R> {
493    fn apply(self, world: &mut World) {
494        Command::apply(UnsetAsymmetric::<R>::new(self.host, self.target), world);
495
496        if R::SYMMETRIC {
497            Command::apply(UnsetAsymmetric::<R>::new(self.target, self.host), world);
498        }
499    }
500}
501
502struct UnsetAsymmetric<R: Relation> {
503    host: Entity,
504    target: Entity,
505    buffered: bool,
506    _phantom: PhantomData<R>,
507}
508
509impl<R: Relation> UnsetAsymmetric<R> {
510    pub fn new(host: Entity, target: Entity) -> Self {
511        Self {
512            host,
513            target,
514            buffered: false,
515            _phantom: PhantomData,
516        }
517    }
518
519    pub(crate) fn buffered(host: Entity, target: Entity) -> Self {
520        Self {
521            host,
522            target,
523            buffered: true,
524            _phantom: PhantomData,
525        }
526    }
527}
528
529impl<R: Relation> Command for UnsetAsymmetric<R> {
530    fn apply(self, world: &mut World) {
531        let mut host_targets = world
532            .get_mut::<Targets<R>>(self.host)
533            .map(|mut edges| std::mem::take(&mut *edges))
534            .unwrap_or_default();
535
536        let mut target_hosts = world
537            .get_mut::<Hosts<R>>(self.target)
538            .map(|mut edges| std::mem::take(&mut *edges))
539            .unwrap_or_default();
540
541        let target_has_host_as_target = if let Some(targets) = world.get::<Targets<R>>(self.target)
542        {
543            targets.vec.vec.contains(&self.host)
544        } else {
545            false
546        };
547
548        // Remove edges from containers
549        let target_removed_from_host = host_targets.remove(self.target);
550
551        let host_removed_from_target = target_hosts.remove(self.host);
552
553        let mut host_entity_exists_in_world = false;
554
555        if !host_targets.vec.vec.is_empty() {
556            world.entity_mut(self.host).insert(host_targets);
557            host_entity_exists_in_world = true;
558        } else if let Ok(mut host) = world.get_entity_mut(self.host) {
559            host_entity_exists_in_world = true;
560            host.remove::<Targets<R>>();
561        }
562
563        let mut target_entity_exists_in_world = false;
564
565        if !target_hosts.vec.vec.is_empty() {
566            world.entity_mut(self.target).insert(target_hosts);
567            target_entity_exists_in_world = true;
568        } else if matches!(
569            R::CLEANUP_POLICY,
570            CleanupPolicy::Counted | CleanupPolicy::Total
571        ) {
572            if self.buffered {
573                world.commands().queue(move |world: &mut World| {
574                    world.despawn(self.target);
575                });
576            } else {
577                world.despawn(self.target);
578            }
579        } else if let Ok(mut target) = world.get_entity_mut(self.target) {
580            target_entity_exists_in_world = true;
581            target.remove::<Hosts<R>>();
582        }
583
584        if target_removed_from_host && host_entity_exists_in_world {
585            world.trigger_targets(
586                UnsetEvent::<R> {
587                    target: self.target,
588                    _phantom: PhantomData,
589                },
590                self.host,
591            );
592        }
593        // Need to check situation if !R::EXCLUSIVE - it is possible that the target also has us as target, so we need to send event
594        // to the target also
595        if host_removed_from_target && target_entity_exists_in_world {
596            if (R::SYMMETRIC && R::EXCLUSIVE) || (!R::EXCLUSIVE && target_has_host_as_target) {
597                world.trigger_targets(
598                    UnsetEvent::<R> {
599                        target: self.host,
600                        _phantom: PhantomData,
601                    },
602                    self.target,
603                );
604            }
605        }
606    }
607}
608
609/// Command for entities to untarget all of their relations of a given type.
610pub struct UnsetAll<R>
611where
612    R: Relation,
613{
614    entity: Entity,
615    _phantom: PhantomData<R>,
616}
617
618impl<R: Relation> UnsetAll<R> {
619    #[allow(missing_docs)]
620    pub fn new(entity: Entity) -> Self {
621        Self {
622            entity,
623            _phantom: PhantomData,
624        }
625    }
626}
627
628impl<R: Relation> Command for UnsetAll<R> {
629    #[allow(clippy::let_unit_value)]
630    fn apply(self, world: &mut World) {
631        while let Some(target) = world
632            .get::<Targets<R>>(self.entity)
633            .and_then(|targets| targets.vec.vec.last())
634            .copied()
635        {
636            let _ = R::ZST_OR_PANIC;
637
638            Command::apply(
639                Unset::<R> {
640                    target,
641                    host: self.entity,
642                    _phantom: PhantomData,
643                },
644                world,
645            );
646        }
647    }
648}
649
650/// Command for entities to remove themselves as the target of all relations of a given type.
651pub struct Withdraw<R>
652where
653    R: Relation,
654{
655    entity: Entity,
656    _phantom: PhantomData<R>,
657}
658
659impl<R: Relation> Withdraw<R> {
660    #[allow(missing_docs)]
661    pub fn new(entity: Entity) -> Self {
662        Self {
663            entity,
664            _phantom: PhantomData,
665        }
666    }
667}
668
669impl<R: Relation> Command for Withdraw<R> {
670    #[allow(clippy::let_unit_value)]
671    fn apply(self, world: &mut World) {
672        while let Some(host) = world
673            .get::<Hosts<R>>(self.entity)
674            .and_then(|hosts| hosts.vec.vec.last())
675            .copied()
676        {
677            let _ = R::ZST_OR_PANIC;
678
679            Command::apply(
680                Unset::<R> {
681                    host,
682                    target: self.entity,
683                    _phantom: PhantomData,
684                },
685                world,
686            );
687        }
688    }
689}
690
691/// An extension API to sugar using relation commands.
692pub trait RelationCommands {
693    /// [`Set`] a relationship target.
694    fn set<R: Relation>(&mut self, target: Entity) -> &mut Self;
695    /// [`Unset`] a relationship target.
696    fn unset<R: Relation>(&mut self, target: Entity) -> &mut Self;
697    /// [`UnsetAll`] relationship targets.
698    fn unset_all<R: Relation>(&mut self) -> &mut Self;
699    /// [`Withdraw`] from a relationship.
700    fn withdraw<R: Relation>(&mut self) -> &mut Self;
701}
702
703impl RelationCommands for EntityWorldMut<'_> {
704    fn set<R: Relation>(&mut self, target: Entity) -> &mut Self {
705        let _ = R::ZST_OR_PANIC;
706
707        let id = self.id();
708        self.world_scope(|world| {
709            Command::apply(Set::<R>::new(id, target), world);
710        });
711
712        self.update_location();
713        self
714    }
715
716    fn unset<R: Relation>(&mut self, target: Entity) -> &mut Self {
717        let _ = R::ZST_OR_PANIC;
718
719        let id = self.id();
720        self.world_scope(|world| {
721            Command::apply(
722                Unset::<R> {
723                    host: id,
724                    target,
725                    _phantom: PhantomData,
726                },
727                world,
728            );
729        });
730
731        self.update_location();
732        self
733    }
734
735    fn unset_all<R: Relation>(&mut self) -> &mut Self {
736        let _ = R::ZST_OR_PANIC;
737
738        let id = self.id();
739        self.world_scope(|world| {
740            Command::apply(
741                UnsetAll::<R> {
742                    entity: id,
743                    _phantom: PhantomData,
744                },
745                world,
746            );
747        });
748
749        self.update_location();
750        self
751    }
752
753    fn withdraw<R: Relation>(&mut self) -> &mut Self {
754        let _ = R::ZST_OR_PANIC;
755
756        let id = self.id();
757        self.world_scope(|world| {
758            Command::apply(
759                Withdraw::<R> {
760                    entity: id,
761                    _phantom: PhantomData,
762                },
763                world,
764            );
765        });
766
767        self.update_location();
768        self
769    }
770}
771
772impl RelationCommands for EntityCommands<'_> {
773    fn set<R: Relation>(&mut self, target: Entity) -> &mut Self {
774        let _ = R::ZST_OR_PANIC;
775
776        let id = self.id();
777        self.commands().queue(Set::<R>::new(id, target));
778        self
779    }
780
781    fn unset<R: Relation>(&mut self, target: Entity) -> &mut Self {
782        let _ = R::ZST_OR_PANIC;
783
784        let id = self.id();
785        self.commands().queue(Unset::<R> {
786            host: id,
787            target,
788            _phantom: PhantomData,
789        });
790        self
791    }
792
793    fn unset_all<R: Relation>(&mut self) -> &mut Self {
794        let _ = R::ZST_OR_PANIC;
795
796        let id = self.id();
797        self.commands().queue(UnsetAll::<R> {
798            entity: id,
799            _phantom: PhantomData,
800        });
801        self
802    }
803
804    fn withdraw<R: Relation>(&mut self) -> &mut Self {
805        let _ = R::ZST_OR_PANIC;
806
807        let id = self.id();
808        self.commands().queue(Withdraw::<R> {
809            entity: id,
810            _phantom: PhantomData,
811        });
812        self
813    }
814}
815
816#[cfg(test)]
817mod tests {
818    use super::Hosts;
819    use super::Targets;
820    use crate::prelude::*;
821    use bevy::prelude::*;
822    use std::array::from_fn;
823
824    fn has_edges<R: Relation>(world: &World, entity: Entity) -> bool {
825        world.get::<Hosts<R>>(entity).is_some() || world.get::<Targets<R>>(entity).is_some()
826    }
827
828    fn is_root<R: Relation>(world: &World, entity: Entity) -> bool {
829        world.get::<Hosts<R>>(entity).is_some() && world.get::<Targets<R>>(entity).is_none()
830    }
831
832    fn is_participant<R: Relation>(world: &World, entity: Entity) -> bool {
833        world.get::<Hosts<R>>(entity).is_some() || world.get::<Targets<R>>(entity).is_some()
834    }
835
836    fn targeting<R: Relation>(world: &World, host: Entity, target: Entity) -> bool {
837        let host_is_targeting = world
838            .get::<Targets<R>>(host)
839            .map_or(false, |vec| vec.vec.vec.contains(&target));
840
841        let target_is_hosted = world
842            .get::<Hosts<R>>(target)
843            .map_or(false, |vec| vec.vec.vec.contains(&host));
844
845        if host_is_targeting != target_is_hosted {
846            panic!("Out of sync edge info");
847        }
848
849        host_is_targeting
850    }
851
852    #[test]
853    fn set_unset() {
854        #[derive(Relation)]
855        struct R;
856
857        let mut world = World::new();
858        let [host, target] = from_fn(|_| world.spawn_empty().id());
859
860        world.entity_mut(host).set::<R>(target);
861        assert!(targeting::<R>(&world, host, target));
862        assert!(is_participant::<R>(&world, host));
863        assert!(is_root::<R>(&world, target));
864
865        world.entity_mut(host).unset::<R>(target);
866        assert!(!has_edges::<R>(&world, target));
867        assert!(!has_edges::<R>(&world, host));
868        assert!(!is_participant::<R>(&world, host));
869        assert!(!is_root::<R>(&world, target));
870    }
871
872    #[test]
873    fn exclusive() {
874        #[derive(Relation)]
875        struct R;
876
877        let mut world = World::new();
878        let [host, t0, t1] = from_fn(|_| world.spawn_empty().id());
879
880        // Before overwrite
881        world.entity_mut(host).set::<R>(t0);
882
883        assert!(targeting::<R>(&world, host, t0));
884        assert!(is_participant::<R>(&world, host));
885        assert!(is_root::<R>(&world, t0));
886
887        // After overwrite
888        world.entity_mut(host).set::<R>(t1);
889
890        assert!(targeting::<R>(&world, host, t1));
891        assert!(is_participant::<R>(&world, host));
892        assert!(is_root::<R>(&world, t1));
893
894        assert!(!has_edges::<R>(&world, t0));
895        assert!(!is_root::<R>(&world, t0));
896    }
897
898    #[derive(Relation)]
899    struct Orphan;
900
901    #[derive(Relation)]
902    #[aery(Counted)]
903    struct Counted;
904
905    #[derive(Relation)]
906    #[aery(Recursive)]
907    struct Recursive;
908
909    #[derive(Relation)]
910    #[aery(Total)]
911    struct Total;
912
913    #[derive(Debug)]
914    struct TestEdges {
915        orphan: Entity,
916        counted: Entity,
917        recursive: Entity,
918        total: Entity,
919    }
920
921    #[derive(Debug)]
922    struct Test {
923        center: Entity,
924        targets: TestEdges,
925        hosts: TestEdges,
926    }
927
928    impl Test {
929        fn new(world: &mut World) -> Self {
930            let test = Self {
931                center: world.spawn_empty().id(),
932                targets: TestEdges {
933                    orphan: world.spawn_empty().id(),
934                    counted: world.spawn_empty().id(),
935                    recursive: world.spawn_empty().id(),
936                    total: world.spawn_empty().id(),
937                },
938                hosts: TestEdges {
939                    orphan: world.spawn_empty().id(),
940                    counted: world.spawn_empty().id(),
941                    recursive: world.spawn_empty().id(),
942                    total: world.spawn_empty().id(),
943                },
944            };
945
946            world
947                .entity_mut(test.hosts.orphan)
948                .set::<Orphan>(test.center);
949            world
950                .entity_mut(test.center)
951                .set::<Orphan>(test.targets.orphan);
952
953            world
954                .entity_mut(test.hosts.counted)
955                .set::<Counted>(test.center);
956            world
957                .entity_mut(test.center)
958                .set::<Counted>(test.targets.counted);
959
960            world
961                .entity_mut(test.hosts.recursive)
962                .set::<Recursive>(test.center);
963            world
964                .entity_mut(test.center)
965                .set::<Recursive>(test.targets.recursive);
966
967            world.entity_mut(test.hosts.total).set::<Total>(test.center);
968            world
969                .entity_mut(test.center)
970                .set::<Total>(test.targets.total);
971
972            test
973        }
974
975        fn assert_unchanged(&self, world: &World) {
976            assert!(targeting::<Orphan>(world, self.hosts.orphan, self.center));
977            assert!(targeting::<Orphan>(world, self.center, self.targets.orphan));
978            assert!(is_participant::<Orphan>(world, self.hosts.orphan,));
979            assert!(is_root::<Orphan>(world, self.targets.orphan));
980
981            assert!(targeting::<Counted>(world, self.hosts.counted, self.center));
982            assert!(targeting::<Counted>(
983                world,
984                self.center,
985                self.targets.counted
986            ));
987            assert!(is_participant::<Counted>(world, self.hosts.counted,));
988            assert!(is_root::<Counted>(world, self.targets.counted));
989
990            assert!(targeting::<Recursive>(
991                world,
992                self.hosts.recursive,
993                self.center
994            ));
995            assert!(targeting::<Recursive>(
996                world,
997                self.center,
998                self.targets.recursive
999            ));
1000            assert!(is_participant::<Recursive>(world, self.hosts.recursive,));
1001            assert!(is_root::<Recursive>(world, self.targets.recursive));
1002
1003            assert!(targeting::<Total>(world, self.hosts.total, self.center));
1004            assert!(targeting::<Total>(world, self.center, self.targets.total));
1005            assert!(is_participant::<Total>(world, self.hosts.total));
1006            assert!(is_root::<Total>(world, self.targets.total));
1007
1008            assert!(is_participant::<Orphan>(world, self.center));
1009            assert!(is_participant::<Counted>(world, self.center));
1010            assert!(is_participant::<Recursive>(world, self.center));
1011            assert!(is_participant::<Total>(world, self.center));
1012        }
1013
1014        fn assert_cleaned(&self, world: &World) {
1015            assert!(world.get_entity(self.center).is_err());
1016
1017            assert!(
1018                !(has_edges::<Orphan>(world, self.hosts.orphan)
1019                    || has_edges::<Counted>(world, self.hosts.orphan)
1020                    || has_edges::<Recursive>(world, self.hosts.orphan)
1021                    || has_edges::<Total>(world, self.hosts.orphan))
1022            );
1023            assert!(
1024                !(has_edges::<Orphan>(world, self.targets.orphan)
1025                    || has_edges::<Counted>(world, self.targets.orphan)
1026                    || has_edges::<Recursive>(world, self.targets.orphan)
1027                    || has_edges::<Total>(world, self.targets.orphan))
1028            );
1029            assert!(!is_participant::<Orphan>(world, self.hosts.orphan));
1030            assert!(!is_root::<Orphan>(world, self.targets.orphan));
1031
1032            assert!(world.get_entity(self.targets.counted).is_err());
1033            assert!(
1034                !(has_edges::<Orphan>(world, self.hosts.counted)
1035                    || has_edges::<Counted>(world, self.hosts.counted)
1036                    || has_edges::<Recursive>(world, self.hosts.counted)
1037                    || has_edges::<Total>(world, self.hosts.counted))
1038            );
1039            assert!(!is_participant::<Counted>(world, self.hosts.counted,));
1040
1041            assert!(world.get_entity(self.hosts.recursive).is_err());
1042            assert!(
1043                !(has_edges::<Orphan>(world, self.targets.recursive)
1044                    || has_edges::<Counted>(world, self.targets.recursive)
1045                    || has_edges::<Recursive>(world, self.targets.recursive)
1046                    || has_edges::<Total>(world, self.targets.recursive))
1047            );
1048            assert!(!is_root::<Recursive>(world, self.targets.recursive));
1049
1050            assert!(world.get_entity(self.hosts.total).is_err());
1051            assert!(world.get_entity(self.targets.total).is_err());
1052        }
1053    }
1054
1055    #[test]
1056    fn orphan_in_despawned() {
1057        #[derive(Relation)]
1058        struct R;
1059
1060        let mut world = World::new();
1061
1062        let test = Test::new(&mut world);
1063
1064        let mut e = world.spawn_empty();
1065        e.set::<R>(test.center);
1066        e.despawn();
1067
1068        test.assert_unchanged(&world);
1069        assert!(!is_participant::<R>(&world, test.center));
1070    }
1071
1072    #[test]
1073    fn orphan_out_despawned() {
1074        #[derive(Relation)]
1075        struct R;
1076
1077        let mut world = World::new();
1078
1079        let test = Test::new(&mut world);
1080
1081        let e = world.spawn_empty().id();
1082        world.entity_mut(test.center).set::<R>(e);
1083        world.entity_mut(e).despawn();
1084
1085        test.assert_unchanged(&world);
1086        assert!(!is_participant::<R>(&world, test.center));
1087    }
1088
1089    #[test]
1090    fn counted_in_despawned() {
1091        #[derive(Relation)]
1092        #[aery(Counted)]
1093        struct R;
1094
1095        let mut world = World::new();
1096
1097        let test = Test::new(&mut world);
1098
1099        let mut e = world.spawn_empty();
1100        e.set::<R>(test.center);
1101        e.despawn();
1102
1103        test.assert_cleaned(&world);
1104    }
1105
1106    #[test]
1107    fn counted_out_despawned() {
1108        #[derive(Relation)]
1109        #[aery(Counted)]
1110        struct R;
1111
1112        let mut world = World::new();
1113
1114        let test = Test::new(&mut world);
1115
1116        let e = world.spawn_empty().id();
1117        world.entity_mut(test.center).set::<R>(e);
1118        world.entity_mut(e).despawn();
1119
1120        test.assert_unchanged(&world);
1121        assert!(!is_participant::<R>(&world, test.center));
1122    }
1123
1124    #[test]
1125    fn recursive_in_despawned() {
1126        #[derive(Relation)]
1127        #[aery(Recursive)]
1128        struct R;
1129
1130        let mut world = World::new();
1131
1132        let test = Test::new(&mut world);
1133
1134        let mut e = world.spawn_empty();
1135        e.set::<R>(test.center);
1136        e.despawn();
1137
1138        test.assert_unchanged(&world);
1139        assert!(!is_participant::<R>(&world, test.center));
1140    }
1141
1142    #[test]
1143    fn recursive_out_despawned() {
1144        #[derive(Relation)]
1145        #[aery(Recursive)]
1146        struct R;
1147
1148        let mut world = World::new();
1149
1150        let test = Test::new(&mut world);
1151
1152        let e = world.spawn_empty().id();
1153        world.entity_mut(test.center).set::<R>(e);
1154        world.entity_mut(e).despawn();
1155
1156        test.assert_cleaned(&world);
1157    }
1158
1159    #[test]
1160    fn total_in_despawned() {
1161        #[derive(Relation)]
1162        #[aery(Total)]
1163        struct R;
1164
1165        let mut world = World::new();
1166
1167        let test = Test::new(&mut world);
1168
1169        let mut e = world.spawn_empty();
1170        e.set::<R>(test.center);
1171        e.despawn();
1172
1173        test.assert_cleaned(&world);
1174    }
1175
1176    #[test]
1177    fn total_out_despawned() {
1178        #[derive(Relation)]
1179        #[aery(Total)]
1180        struct R;
1181
1182        let mut world = World::new();
1183
1184        let test = Test::new(&mut world);
1185
1186        let e = world.spawn_empty().id();
1187        world.entity_mut(test.center).set::<R>(e);
1188        world.entity_mut(e).despawn();
1189
1190        test.assert_cleaned(&world);
1191    }
1192
1193    #[test]
1194    fn orphan_in_unset() {
1195        #[derive(Relation)]
1196        struct R;
1197
1198        let mut world = World::new();
1199
1200        let test = Test::new(&mut world);
1201
1202        world
1203            .spawn_empty()
1204            .set::<R>(test.center)
1205            .unset::<R>(test.center);
1206
1207        test.assert_unchanged(&world);
1208        assert!(!is_participant::<R>(&world, test.center));
1209    }
1210
1211    #[test]
1212    fn orphan_out_unset() {
1213        #[derive(Relation)]
1214        struct R;
1215
1216        let mut world = World::new();
1217
1218        let test = Test::new(&mut world);
1219        let e = world.spawn_empty().id();
1220        world.entity_mut(test.center).set::<R>(e).unset::<R>(e);
1221
1222        test.assert_unchanged(&world);
1223        assert!(!is_participant::<R>(&world, test.center));
1224    }
1225
1226    #[test]
1227    fn counted_in_unset() {
1228        #[derive(Relation)]
1229        #[aery(Counted)]
1230        struct R;
1231
1232        let mut world = World::new();
1233
1234        let test = Test::new(&mut world);
1235
1236        world
1237            .spawn_empty()
1238            .set::<R>(test.center)
1239            .unset::<R>(test.center);
1240
1241        test.assert_cleaned(&world);
1242    }
1243
1244    #[test]
1245    fn counted_out_unset() {
1246        #[derive(Relation)]
1247        #[aery(Counted)]
1248        struct R;
1249
1250        let mut world = World::new();
1251
1252        let test = Test::new(&mut world);
1253
1254        let e = world.spawn_empty().id();
1255
1256        world.entity_mut(test.center).set::<R>(e).unset::<R>(e);
1257
1258        test.assert_unchanged(&world);
1259        assert!(!is_participant::<R>(&world, test.center));
1260    }
1261
1262    #[test]
1263    fn recursive_in_unset() {
1264        #[derive(Relation)]
1265        #[aery(Recursive)]
1266        struct R;
1267
1268        let mut world = World::new();
1269
1270        let test = Test::new(&mut world);
1271
1272        world
1273            .spawn_empty()
1274            .set::<R>(test.center)
1275            .unset::<R>(test.center);
1276
1277        test.assert_unchanged(&world);
1278        assert!(!is_participant::<R>(&world, test.center));
1279    }
1280
1281    #[test]
1282    #[should_panic]
1283    fn recursive_out_unset() {
1284        #[derive(Relation)]
1285        #[aery(Recursive)]
1286        struct R;
1287
1288        let mut world = World::new();
1289
1290        let test = Test::new(&mut world);
1291        let e = world.spawn_empty().id();
1292        world.entity_mut(test.center).set::<R>(e).unset::<R>(e);
1293
1294        test.assert_cleaned(&world);
1295    }
1296
1297    #[test]
1298    fn total_in_unset() {
1299        #[derive(Relation)]
1300        #[aery(Total)]
1301        struct R;
1302
1303        let mut world = World::new();
1304
1305        let test = Test::new(&mut world);
1306
1307        world
1308            .spawn_empty()
1309            .set::<R>(test.center)
1310            .unset::<R>(test.center);
1311
1312        test.assert_cleaned(&world);
1313    }
1314
1315    #[test]
1316    #[should_panic]
1317    fn total_out_unset() {
1318        #[derive(Relation)]
1319        #[aery(Total)]
1320        struct R;
1321
1322        let mut world = World::new();
1323
1324        let test = Test::new(&mut world);
1325        let e = world.spawn_empty().id();
1326        world.entity_mut(test.center).set::<R>(e).unset::<R>(e);
1327
1328        test.assert_cleaned(&world);
1329    }
1330    #[derive(Component)]
1331    struct EventCounter(i32);
1332
1333    #[derive(Relation)]
1334    struct AsymmetricRelation;
1335
1336    #[derive(Relation)]
1337    #[aery(Symmetric)]
1338    struct SymmetricRelation;
1339
1340    #[derive(Relation)]
1341    #[aery(Poly)]
1342    struct PolyRelation;
1343
1344    #[derive(Relation)]
1345    #[aery(Poly, Symmetric)]
1346    struct PolySymmetricRelation;
1347
1348    enum RelationType {
1349        Asymmetric,
1350        Symmetric,
1351        Poly,
1352        PolySymmetric,
1353    }
1354
1355    fn test_unset_event<R: Relation>(
1356        world: &mut World,
1357        relation_name: &str,
1358        set_both_ways: bool,
1359        expected_counter_a: i32,
1360        expected_counter_b: i32,
1361    ) {
1362        // Spawn two entities with EventCounter and observe UnsetEvent<R>
1363        let entity_a = world
1364            .spawn(EventCounter(0))
1365            .observe(
1366                |trigger: Trigger<UnsetEvent<R>>, mut counters: Query<&mut EventCounter>| {
1367                    counters.get_mut(trigger.entity()).unwrap().0 += 1;
1368                },
1369            )
1370            .id();
1371
1372        let entity_b = world
1373            .spawn(EventCounter(0))
1374            .observe(
1375                |trigger: Trigger<UnsetEvent<R>>, mut counters: Query<&mut EventCounter>| {
1376                    counters.get_mut(trigger.entity()).unwrap().0 += 1;
1377                },
1378            )
1379            .id();
1380
1381        world.flush();
1382
1383        // Set the relation(s)
1384        world.entity_mut(entity_a).set::<R>(entity_b);
1385        if set_both_ways {
1386            world.entity_mut(entity_b).set::<R>(entity_a);
1387        }
1388
1389        world.flush();
1390
1391        // Unset the relation from entity_a to entity_b
1392        world.entity_mut(entity_a).unset::<R>(entity_b);
1393        world.flush();
1394
1395        // Check counters
1396        let counter_a = world.get::<EventCounter>(entity_a).unwrap().0;
1397        let counter_b = world.get::<EventCounter>(entity_b).unwrap().0;
1398
1399        assert_eq!(
1400            counter_a, expected_counter_a,
1401            "{}: Unexpected counter value for entity_a",
1402            relation_name
1403        );
1404        assert_eq!(
1405            counter_b, expected_counter_b,
1406            "{}: Unexpected counter value for entity_b",
1407            relation_name
1408        );
1409    }
1410
1411    #[test]
1412    fn test_unset_events_for_relations() {
1413        let mut world = World::new();
1414
1415        // Register relations
1416        world.register_relation::<AsymmetricRelation>();
1417        world.register_relation::<SymmetricRelation>();
1418        world.register_relation::<PolyRelation>();
1419        world.register_relation::<PolySymmetricRelation>();
1420
1421        // Test cases: (RelationType, set_both_ways, expected counters after unset)
1422        let test_cases = vec![
1423            (RelationType::Asymmetric, false, 1, 0),
1424            (RelationType::Symmetric, false, 1, 1),
1425            (RelationType::Poly, true, 1, 1),
1426            (RelationType::PolySymmetric, true, 1, 1),
1427        ];
1428
1429        for (relation_type, set_both_ways, expected_a, expected_b) in test_cases {
1430            match relation_type {
1431                RelationType::Asymmetric => test_unset_event::<AsymmetricRelation>(
1432                    &mut world,
1433                    "AsymmetricRelation",
1434                    set_both_ways,
1435                    expected_a,
1436                    expected_b,
1437                ),
1438                RelationType::Symmetric => test_unset_event::<SymmetricRelation>(
1439                    &mut world,
1440                    "SymmetricRelation",
1441                    set_both_ways,
1442                    expected_a,
1443                    expected_b,
1444                ),
1445                RelationType::Poly => test_unset_event::<PolyRelation>(
1446                    &mut world,
1447                    "PolyRelation",
1448                    set_both_ways,
1449                    expected_a,
1450                    expected_b,
1451                ),
1452                RelationType::PolySymmetric => test_unset_event::<PolySymmetricRelation>(
1453                    &mut world,
1454                    "PolySymmetricRelation",
1455                    set_both_ways,
1456                    expected_a,
1457                    expected_b,
1458                ),
1459            }
1460        }
1461    }
1462    fn test_set_event<R: Relation>(
1463        world: &mut World,
1464        relation_name: &str,
1465        set_both_ways: bool,
1466        expected_counter_a: i32,
1467        expected_counter_b: i32,
1468    ) {
1469        // Spawn two entities with EventCounter and observe SetEvent<R>
1470        let entity_a = world
1471            .spawn(EventCounter(0))
1472            .observe(
1473                |trigger: Trigger<SetEvent<R>>, mut counters: Query<&mut EventCounter>| {
1474                    counters.get_mut(trigger.entity()).unwrap().0 += 1;
1475                },
1476            )
1477            .id();
1478
1479        let entity_b = world
1480            .spawn(EventCounter(0))
1481            .observe(
1482                |trigger: Trigger<SetEvent<R>>, mut counters: Query<&mut EventCounter>| {
1483                    counters.get_mut(trigger.entity()).unwrap().0 += 1;
1484                },
1485            )
1486            .id();
1487
1488        world.flush();
1489
1490        // Set the relation(s)
1491        world.entity_mut(entity_a).set::<R>(entity_b);
1492        if set_both_ways {
1493            world.entity_mut(entity_b).set::<R>(entity_a);
1494        }
1495
1496        world.flush();
1497
1498        // Check counters
1499        let counter_a = world.get::<EventCounter>(entity_a).unwrap().0;
1500        let counter_b = world.get::<EventCounter>(entity_b).unwrap().0;
1501
1502        assert_eq!(
1503            counter_a, expected_counter_a,
1504            "{}: Unexpected counter value for entity_a",
1505            relation_name
1506        );
1507        assert_eq!(
1508            counter_b, expected_counter_b,
1509            "{}: Unexpected counter value for entity_b",
1510            relation_name
1511        );
1512    }
1513
1514    #[test]
1515    fn test_set_events_for_relations() {
1516        // Create a new world for each test case to avoid state carry-over
1517        let mut world = World::new();
1518
1519        // Register relations
1520        world.register_relation::<AsymmetricRelation>();
1521        world.register_relation::<SymmetricRelation>();
1522        world.register_relation::<PolyRelation>();
1523        world.register_relation::<PolySymmetricRelation>();
1524
1525        // Test cases: (RelationType, set_both_ways, expected_counter_a, expected_counter_b)
1526        let test_cases = vec![
1527            (RelationType::Asymmetric, false, 1, 0),
1528            (RelationType::Symmetric, false, 1, 1),
1529            (RelationType::Poly, true, 1, 1),
1530            (RelationType::PolySymmetric, true, 1, 1),
1531        ];
1532
1533        for (relation_type, set_both_ways, expected_a, expected_b) in test_cases {
1534            match relation_type {
1535                RelationType::Asymmetric => test_set_event::<AsymmetricRelation>(
1536                    &mut world,
1537                    "AsymmetricRelation",
1538                    set_both_ways,
1539                    expected_a,
1540                    expected_b,
1541                ),
1542                RelationType::Symmetric => test_set_event::<SymmetricRelation>(
1543                    &mut world,
1544                    "SymmetricRelation",
1545                    set_both_ways,
1546                    expected_a,
1547                    expected_b,
1548                ),
1549                RelationType::Poly => test_set_event::<PolyRelation>(
1550                    &mut world,
1551                    "PolyRelation",
1552                    set_both_ways,
1553                    expected_a,
1554                    expected_b,
1555                ),
1556                RelationType::PolySymmetric => test_set_event::<PolySymmetricRelation>(
1557                    &mut world,
1558                    "PolySymmetricRelation",
1559                    set_both_ways,
1560                    expected_a,
1561                    expected_b,
1562                ),
1563            }
1564        }
1565    }
1566}