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#[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
57pub(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
82pub(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#[derive(QueryData)]
230pub struct HierarchyEdges(pub(crate) AnyOf<(&'static Children, &'static Parent)>);
231
232#[derive(QueryData)]
234pub struct Edges<R: Relation>(pub(crate) AnyOf<(&'static Hosts<R>, &'static Targets<R>)>);
235
236pub trait EdgeInfo {
238 fn hosts(&self) -> &[Entity];
240 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
276impl<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#[derive(QueryFilter)]
298pub struct Root<R: Relation>((With<Hosts<R>>, Without<Targets<R>>));
299
300#[derive(QueryFilter)]
303pub struct Branch<R: Relation>((With<Hosts<R>>, With<Targets<R>>));
304
305#[derive(QueryFilter)]
310pub struct Leaf<R: Relation>((Without<Hosts<R>>, With<Targets<R>>));
311
312#[derive(QueryFilter)]
315pub struct Participates<R: Relation>(Or<(With<Hosts<R>>, With<Targets<R>>)>);
316
317#[derive(QueryFilter)]
320pub struct Abstains<R: Relation>((Without<Hosts<R>>, Without<Targets<R>>));
321
322#[derive(QueryFilter)]
324pub struct EdgeChanged<R: Relation>(Or<(Changed<Hosts<R>>, Changed<Targets<R>>)>);
325
326#[derive(Event, Clone, Copy, Debug)]
328pub struct SetEvent<R: Relation> {
329 pub target: Entity,
331 _phantom: PhantomData<R>,
332}
333
334#[derive(Event, Clone, Copy, Debug)]
336pub struct UnsetEvent<R: Relation> {
337 pub target: Entity,
339 _phantom: PhantomData<R>,
340}
341
342pub 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 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 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 if target_hosts.vec.vec.contains(&self.host) {
430 return;
431 } else {
432 target_hosts.vec.add(self.host);
433 }
434 } else {
435 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 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
469pub 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 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 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
609pub 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
650pub 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
691pub trait RelationCommands {
693 fn set<R: Relation>(&mut self, target: Entity) -> &mut Self;
695 fn unset<R: Relation>(&mut self, target: Entity) -> &mut Self;
697 fn unset_all<R: Relation>(&mut self) -> &mut Self;
699 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 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 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 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 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 world.entity_mut(entity_a).unset::<R>(entity_b);
1393 world.flush();
1394
1395 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 world.register_relation::<AsymmetricRelation>();
1417 world.register_relation::<SymmetricRelation>();
1418 world.register_relation::<PolyRelation>();
1419 world.register_relation::<PolySymmetricRelation>();
1420
1421 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 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 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 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 let mut world = World::new();
1518
1519 world.register_relation::<AsymmetricRelation>();
1521 world.register_relation::<SymmetricRelation>();
1522 world.register_relation::<PolyRelation>();
1523 world.register_relation::<PolySymmetricRelation>();
1524
1525 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}