1use alloc::{boxed::Box, collections::BTreeSet, string::String, vec::Vec};
2use core::{
3 any::TypeId,
4 fmt::{self, Debug},
5 ops::{Deref, Index, IndexMut, Range},
6};
7
8use bevy_platform::collections::{HashMap, HashSet};
9use bevy_utils::prelude::DebugName;
10use slotmap::{new_key_type, Key, KeyData, SecondaryMap, SlotMap};
11use thiserror::Error;
12
13use crate::{
14 change_detection::{CheckChangeTicks, Tick},
15 component::{ComponentId, Components},
16 prelude::{SystemIn, SystemSet},
17 query::{AccessConflicts, FilteredAccessSet},
18 schedule::{
19 graph::{
20 DagAnalysis, DagGroups, DiGraph,
21 Direction::{self, Incoming, Outgoing},
22 GraphNodeId, UnGraph,
23 },
24 BoxedCondition, InternedSystemSet, ScheduleGraph,
25 },
26 storage::SparseSetIndex,
27 system::{
28 ReadOnlySystem, RunSystemError, ScheduleSystem, System, SystemParamValidationError,
29 SystemStateFlags,
30 },
31 world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World},
32};
33
34pub(crate) struct SystemNode {
36 pub(crate) inner: Option<SystemWithAccess>,
37}
38
39pub struct SystemWithAccess {
41 pub system: ScheduleSystem,
43 pub access: FilteredAccessSet,
46}
47
48impl SystemWithAccess {
49 pub fn new(system: ScheduleSystem) -> Self {
52 Self {
53 system,
54 access: FilteredAccessSet::new(),
55 }
56 }
57}
58
59impl System for SystemWithAccess {
60 type In = ();
61 type Out = ();
62
63 #[inline]
64 fn name(&self) -> DebugName {
65 self.system.name()
66 }
67
68 #[inline]
69 fn type_id(&self) -> TypeId {
70 self.system.type_id()
71 }
72
73 #[inline]
74 fn flags(&self) -> SystemStateFlags {
75 self.system.flags()
76 }
77
78 #[inline]
79 unsafe fn run_unsafe(
80 &mut self,
81 input: SystemIn<'_, Self>,
82 world: UnsafeWorldCell,
83 ) -> Result<Self::Out, RunSystemError> {
84 unsafe { self.system.run_unsafe(input, world) }
86 }
87
88 #[cfg(feature = "hotpatching")]
89 #[inline]
90 fn refresh_hotpatch(&mut self) {
91 self.system.refresh_hotpatch();
92 }
93
94 #[inline]
95 fn apply_deferred(&mut self, world: &mut World) {
96 self.system.apply_deferred(world);
97 }
98
99 #[inline]
100 fn queue_deferred(&mut self, world: DeferredWorld) {
101 self.system.queue_deferred(world);
102 }
103
104 #[inline]
105 unsafe fn validate_param_unsafe(
106 &mut self,
107 world: UnsafeWorldCell,
108 ) -> Result<(), SystemParamValidationError> {
109 unsafe { self.system.validate_param_unsafe(world) }
111 }
112
113 #[inline]
114 fn initialize(&mut self, world: &mut World) -> FilteredAccessSet {
115 self.system.initialize(world)
116 }
117
118 #[inline]
119 fn check_change_tick(&mut self, check: CheckChangeTicks) {
120 self.system.check_change_tick(check);
121 }
122
123 #[inline]
124 fn default_system_sets(&self) -> Vec<InternedSystemSet> {
125 self.system.default_system_sets()
126 }
127
128 #[inline]
129 fn get_last_run(&self) -> Tick {
130 self.system.get_last_run()
131 }
132
133 #[inline]
134 fn set_last_run(&mut self, last_run: Tick) {
135 self.system.set_last_run(last_run);
136 }
137}
138
139pub struct ConditionWithAccess {
141 pub condition: BoxedCondition,
143 pub access: FilteredAccessSet,
146}
147
148impl ConditionWithAccess {
149 pub const fn new(condition: BoxedCondition) -> Self {
152 Self {
153 condition,
154 access: FilteredAccessSet::new(),
155 }
156 }
157}
158
159impl System for ConditionWithAccess {
160 type In = ();
161 type Out = bool;
162
163 #[inline]
164 fn name(&self) -> DebugName {
165 self.condition.name()
166 }
167
168 #[inline]
169 fn type_id(&self) -> TypeId {
170 self.condition.type_id()
171 }
172
173 #[inline]
174 fn flags(&self) -> SystemStateFlags {
175 self.condition.flags()
176 }
177
178 #[inline]
179 unsafe fn run_unsafe(
180 &mut self,
181 input: SystemIn<'_, Self>,
182 world: UnsafeWorldCell,
183 ) -> Result<Self::Out, RunSystemError> {
184 unsafe { self.condition.run_unsafe(input, world) }
186 }
187
188 #[cfg(feature = "hotpatching")]
189 #[inline]
190 fn refresh_hotpatch(&mut self) {
191 self.condition.refresh_hotpatch();
192 }
193
194 #[inline]
195 fn apply_deferred(&mut self, world: &mut World) {
196 self.condition.apply_deferred(world);
197 }
198
199 #[inline]
200 fn queue_deferred(&mut self, world: DeferredWorld) {
201 self.condition.queue_deferred(world);
202 }
203
204 #[inline]
205 unsafe fn validate_param_unsafe(
206 &mut self,
207 world: UnsafeWorldCell,
208 ) -> Result<(), SystemParamValidationError> {
209 unsafe { self.condition.validate_param_unsafe(world) }
211 }
212
213 #[inline]
214 fn initialize(&mut self, world: &mut World) -> FilteredAccessSet {
215 self.condition.initialize(world)
216 }
217
218 #[inline]
219 fn check_change_tick(&mut self, check: CheckChangeTicks) {
220 self.condition.check_change_tick(check);
221 }
222
223 #[inline]
224 fn default_system_sets(&self) -> Vec<InternedSystemSet> {
225 self.condition.default_system_sets()
226 }
227
228 #[inline]
229 fn get_last_run(&self) -> Tick {
230 self.condition.get_last_run()
231 }
232
233 #[inline]
234 fn set_last_run(&mut self, last_run: Tick) {
235 self.condition.set_last_run(last_run);
236 }
237}
238
239impl SystemNode {
240 pub fn new(system: ScheduleSystem) -> Self {
242 Self {
243 inner: Some(SystemWithAccess::new(system)),
244 }
245 }
246
247 pub fn get(&self) -> Option<&SystemWithAccess> {
249 self.inner.as_ref()
250 }
251
252 pub fn get_mut(&mut self) -> Option<&mut SystemWithAccess> {
254 self.inner.as_mut()
255 }
256}
257
258new_key_type! {
259 pub struct SystemKey;
261 pub struct SystemSetKey;
263}
264
265impl GraphNodeId for SystemKey {
266 type Adjacent = (SystemKey, Direction);
267 type Edge = (SystemKey, SystemKey);
268
269 fn kind(&self) -> &'static str {
270 "system"
271 }
272}
273
274impl GraphNodeId for SystemSetKey {
275 type Adjacent = (SystemSetKey, Direction);
276 type Edge = (SystemSetKey, SystemSetKey);
277
278 fn kind(&self) -> &'static str {
279 "system set"
280 }
281}
282
283impl TryFrom<NodeId> for SystemKey {
284 type Error = SystemSetKey;
285
286 fn try_from(value: NodeId) -> Result<Self, Self::Error> {
287 match value {
288 NodeId::System(key) => Ok(key),
289 NodeId::Set(key) => Err(key),
290 }
291 }
292}
293
294impl TryFrom<NodeId> for SystemSetKey {
295 type Error = SystemKey;
296
297 fn try_from(value: NodeId) -> Result<Self, Self::Error> {
298 match value {
299 NodeId::System(key) => Err(key),
300 NodeId::Set(key) => Ok(key),
301 }
302 }
303}
304
305#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
309pub enum NodeId {
310 System(SystemKey),
312 Set(SystemSetKey),
314}
315
316impl NodeId {
317 pub const fn is_system(&self) -> bool {
319 matches!(self, NodeId::System(_))
320 }
321
322 pub const fn is_set(&self) -> bool {
324 matches!(self, NodeId::Set(_))
325 }
326
327 pub const fn as_system(&self) -> Option<SystemKey> {
329 match self {
330 NodeId::System(system) => Some(*system),
331 NodeId::Set(_) => None,
332 }
333 }
334
335 pub const fn as_set(&self) -> Option<SystemSetKey> {
337 match self {
338 NodeId::System(_) => None,
339 NodeId::Set(set) => Some(*set),
340 }
341 }
342}
343
344impl GraphNodeId for NodeId {
345 type Adjacent = CompactNodeIdAndDirection;
346 type Edge = CompactNodeIdPair;
347
348 fn kind(&self) -> &'static str {
349 match self {
350 NodeId::System(n) => n.kind(),
351 NodeId::Set(n) => n.kind(),
352 }
353 }
354}
355
356impl From<SystemKey> for NodeId {
357 fn from(system: SystemKey) -> Self {
358 NodeId::System(system)
359 }
360}
361
362impl From<SystemSetKey> for NodeId {
363 fn from(set: SystemSetKey) -> Self {
364 NodeId::Set(set)
365 }
366}
367
368#[derive(Clone, Copy)]
370pub struct CompactNodeIdAndDirection {
371 key: KeyData,
372 is_system: bool,
373 direction: Direction,
374}
375
376impl Debug for CompactNodeIdAndDirection {
377 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
378 let tuple: (_, _) = (*self).into();
379 tuple.fmt(f)
380 }
381}
382
383impl From<(NodeId, Direction)> for CompactNodeIdAndDirection {
384 fn from((id, direction): (NodeId, Direction)) -> Self {
385 let key = match id {
386 NodeId::System(key) => key.data(),
387 NodeId::Set(key) => key.data(),
388 };
389 let is_system = id.is_system();
390
391 Self {
392 key,
393 is_system,
394 direction,
395 }
396 }
397}
398
399impl From<CompactNodeIdAndDirection> for (NodeId, Direction) {
400 fn from(value: CompactNodeIdAndDirection) -> Self {
401 let node = match value.is_system {
402 true => NodeId::System(value.key.into()),
403 false => NodeId::Set(value.key.into()),
404 };
405
406 (node, value.direction)
407 }
408}
409
410#[derive(Clone, Copy, Hash, PartialEq, Eq)]
412pub struct CompactNodeIdPair {
413 key_a: KeyData,
414 key_b: KeyData,
415 is_system_a: bool,
416 is_system_b: bool,
417}
418
419impl Debug for CompactNodeIdPair {
420 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
421 let tuple: (_, _) = (*self).into();
422 tuple.fmt(f)
423 }
424}
425
426impl From<(NodeId, NodeId)> for CompactNodeIdPair {
427 fn from((a, b): (NodeId, NodeId)) -> Self {
428 let key_a = match a {
429 NodeId::System(index) => index.data(),
430 NodeId::Set(index) => index.data(),
431 };
432 let is_system_a = a.is_system();
433
434 let key_b = match b {
435 NodeId::System(index) => index.data(),
436 NodeId::Set(index) => index.data(),
437 };
438 let is_system_b = b.is_system();
439
440 Self {
441 key_a,
442 key_b,
443 is_system_a,
444 is_system_b,
445 }
446 }
447}
448
449impl From<CompactNodeIdPair> for (NodeId, NodeId) {
450 fn from(value: CompactNodeIdPair) -> Self {
451 let a = match value.is_system_a {
452 true => NodeId::System(value.key_a.into()),
453 false => NodeId::Set(value.key_a.into()),
454 };
455
456 let b = match value.is_system_b {
457 true => NodeId::System(value.key_b.into()),
458 false => NodeId::Set(value.key_b.into()),
459 };
460
461 (a, b)
462 }
463}
464
465#[derive(Default)]
467pub struct Systems {
468 nodes: SlotMap<SystemKey, SystemNode>,
470 conditions: SecondaryMap<SystemKey, Vec<ConditionWithAccess>>,
472 uninit: Vec<SystemKey>,
474}
475
476impl Systems {
477 pub fn len(&self) -> usize {
479 self.nodes.len()
480 }
481
482 pub fn is_empty(&self) -> bool {
484 self.nodes.is_empty()
485 }
486
487 pub fn get(&self, key: SystemKey) -> Option<&SystemWithAccess> {
489 self.nodes.get(key).and_then(|node| node.get())
490 }
491
492 pub fn get_mut(&mut self, key: SystemKey) -> Option<&mut SystemWithAccess> {
494 self.nodes.get_mut(key).and_then(|node| node.get_mut())
495 }
496
497 pub(crate) fn node_mut(&mut self, key: SystemKey) -> Option<&mut SystemNode> {
500 self.nodes.get_mut(key)
501 }
502
503 pub fn has_conditions(&self, key: SystemKey) -> bool {
505 self.conditions
506 .get(key)
507 .is_some_and(|conditions| !conditions.is_empty())
508 }
509
510 pub fn get_conditions(&self, key: SystemKey) -> Option<&[ConditionWithAccess]> {
512 self.conditions.get(key).map(Vec::as_slice)
513 }
514
515 pub fn get_conditions_mut(&mut self, key: SystemKey) -> Option<&mut Vec<ConditionWithAccess>> {
517 self.conditions.get_mut(key)
518 }
519
520 pub fn iter(
523 &self,
524 ) -> impl Iterator<Item = (SystemKey, &ScheduleSystem, &[ConditionWithAccess])> + '_ {
525 self.nodes.iter().filter_map(|(key, node)| {
526 let system = &node.get()?.system;
527 let conditions = self
528 .conditions
529 .get(key)
530 .map(Vec::as_slice)
531 .unwrap_or_default();
532 Some((key, system, conditions))
533 })
534 }
535
536 pub fn insert(
544 &mut self,
545 system: ScheduleSystem,
546 conditions: Vec<Box<dyn ReadOnlySystem<In = (), Out = bool>>>,
547 ) -> SystemKey {
548 let key = self.nodes.insert(SystemNode::new(system));
549 self.conditions.insert(
550 key,
551 conditions
552 .into_iter()
553 .map(ConditionWithAccess::new)
554 .collect(),
555 );
556 self.uninit.push(key);
557 key
558 }
559
560 pub(crate) fn remove(&mut self, key: SystemKey) -> bool {
562 let mut found = false;
563 if self.nodes.remove(key).is_some() {
564 found = true;
565 }
566
567 if self.conditions.remove(key).is_some() {
568 found = true;
569 }
570
571 if let Some(index) = self.uninit.iter().position(|value| *value == key) {
572 self.uninit.remove(index);
573 found = true;
574 }
575
576 found
577 }
578
579 pub fn is_initialized(&self) -> bool {
581 self.uninit.is_empty()
582 }
583
584 pub fn initialize(&mut self, world: &mut World) {
587 for key in self.uninit.drain(..) {
588 let Some(system) = self.nodes.get_mut(key).and_then(|node| node.get_mut()) else {
589 continue;
590 };
591 system.access = system.system.initialize(world);
592 let Some(conditions) = self.conditions.get_mut(key) else {
593 continue;
594 };
595 for condition in conditions {
596 condition.access = condition.condition.initialize(world);
597 }
598 }
599 }
600
601 pub fn get_conflicting_systems(
608 &self,
609 flat_dependency_analysis: &DagAnalysis<SystemKey>,
610 flat_ambiguous_with: &UnGraph<SystemKey>,
611 ambiguous_with_all: &HashSet<NodeId>,
612 ignored_ambiguities: &BTreeSet<ComponentId>,
613 ) -> ConflictingSystems {
614 let mut conflicting_systems: Vec<(_, _, Box<[_]>)> = Vec::new();
615 for &(a, b) in flat_dependency_analysis.disconnected() {
616 if flat_ambiguous_with.contains_edge(a, b)
617 || ambiguous_with_all.contains(&NodeId::System(a))
618 || ambiguous_with_all.contains(&NodeId::System(b))
619 {
620 continue;
621 }
622
623 let system_a = &self[a];
624 let system_b = &self[b];
625 if system_a.is_exclusive() || system_b.is_exclusive() {
626 conflicting_systems.push((a, b, Box::new([])));
627 } else {
628 let access_a = &system_a.access;
629 let access_b = &system_b.access;
630 if !access_a.is_compatible(access_b) {
631 match access_a.get_conflicts(access_b) {
632 AccessConflicts::Individual(conflicts) => {
633 let conflicts: Box<[_]> = conflicts
634 .ones()
635 .map(ComponentId::get_sparse_set_index)
636 .filter(|id| !ignored_ambiguities.contains(id))
637 .collect();
638 if !conflicts.is_empty() {
639 conflicting_systems.push((a, b, conflicts));
640 }
641 }
642 AccessConflicts::All => {
643 conflicting_systems.push((a, b, Box::new([])));
646 }
647 }
648 }
649 }
650 }
651
652 ConflictingSystems(conflicting_systems)
653 }
654}
655
656impl Index<SystemKey> for Systems {
657 type Output = SystemWithAccess;
658
659 #[track_caller]
660 fn index(&self, key: SystemKey) -> &Self::Output {
661 self.get(key)
662 .unwrap_or_else(|| panic!("System with key {:?} does not exist in the schedule", key))
663 }
664}
665
666impl IndexMut<SystemKey> for Systems {
667 #[track_caller]
668 fn index_mut(&mut self, key: SystemKey) -> &mut Self::Output {
669 self.get_mut(key)
670 .unwrap_or_else(|| panic!("System with key {:?} does not exist in the schedule", key))
671 }
672}
673
674#[derive(Clone, Debug, Default)]
679pub struct ConflictingSystems(pub Vec<(SystemKey, SystemKey, Box<[ComponentId]>)>);
680
681impl ConflictingSystems {
682 pub fn check_if_not_empty(&self) -> Result<(), AmbiguousSystemConflictsWarning> {
685 if self.0.is_empty() {
686 Ok(())
687 } else {
688 Err(AmbiguousSystemConflictsWarning(self.clone()))
689 }
690 }
691
692 pub fn to_string(
695 &self,
696 graph: &ScheduleGraph,
697 components: &Components,
698 ) -> impl Iterator<Item = (String, String, Box<[DebugName]>)> {
699 self.iter().map(move |(system_a, system_b, conflicts)| {
700 let name_a = graph.get_node_name(&NodeId::System(*system_a));
701 let name_b = graph.get_node_name(&NodeId::System(*system_b));
702
703 let conflict_names: Box<[_]> = conflicts
704 .iter()
705 .map(|id| components.get_name(*id).unwrap())
706 .collect();
707
708 (name_a, name_b, conflict_names)
709 })
710 }
711}
712
713impl Deref for ConflictingSystems {
714 type Target = Vec<(SystemKey, SystemKey, Box<[ComponentId]>)>;
715
716 fn deref(&self) -> &Self::Target {
717 &self.0
718 }
719}
720
721#[derive(Error, Debug)]
723#[error("Systems with conflicting access have indeterminate run order: {:?}", .0.0)]
724pub struct AmbiguousSystemConflictsWarning(pub ConflictingSystems);
725
726#[derive(Default)]
728pub struct SystemSets {
729 sets: SlotMap<SystemSetKey, InternedSystemSet>,
731 conditions: SecondaryMap<SystemSetKey, Vec<ConditionWithAccess>>,
733 ids: HashMap<InternedSystemSet, SystemSetKey>,
735 uninit: Vec<UninitializedSet>,
737}
738
739struct UninitializedSet {
741 key: SystemSetKey,
742 uninitialized_conditions: Range<usize>,
754}
755
756impl SystemSets {
757 pub fn len(&self) -> usize {
759 self.sets.len()
760 }
761
762 pub fn is_empty(&self) -> bool {
764 self.sets.is_empty()
765 }
766
767 pub fn contains(&self, set: impl SystemSet) -> bool {
769 self.ids.contains_key(&set.intern())
770 }
771
772 pub fn get(&self, key: SystemSetKey) -> Option<&dyn SystemSet> {
774 self.sets.get(key).map(|set| &**set)
775 }
776
777 pub fn get_key(&self, set: InternedSystemSet) -> Option<SystemSetKey> {
779 self.ids.get(&set).copied()
780 }
781
782 pub fn get_key_or_insert(&mut self, set: InternedSystemSet) -> SystemSetKey {
785 *self.ids.entry(set).or_insert_with(|| {
786 let key = self.sets.insert(set);
787 self.conditions.insert(key, Vec::new());
788 key
789 })
790 }
791
792 pub fn has_conditions(&self, key: SystemSetKey) -> bool {
794 self.conditions
795 .get(key)
796 .is_some_and(|conditions| !conditions.is_empty())
797 }
798
799 pub fn get_conditions(&self, key: SystemSetKey) -> Option<&[ConditionWithAccess]> {
802 self.conditions.get(key).map(Vec::as_slice)
803 }
804
805 pub fn get_conditions_mut(
808 &mut self,
809 key: SystemSetKey,
810 ) -> Option<&mut Vec<ConditionWithAccess>> {
811 self.conditions.get_mut(key)
812 }
813
814 pub fn iter(
817 &self,
818 ) -> impl Iterator<Item = (SystemSetKey, &dyn SystemSet, &[ConditionWithAccess])> {
819 self.sets.iter().filter_map(|(key, set)| {
820 let conditions = self.conditions.get(key)?.as_slice();
821 Some((key, &**set, conditions))
822 })
823 }
824
825 pub fn insert(
835 &mut self,
836 set: InternedSystemSet,
837 new_conditions: Vec<Box<dyn ReadOnlySystem<In = (), Out = bool>>>,
838 ) -> SystemSetKey {
839 let key = self.get_key_or_insert(set);
840 if !new_conditions.is_empty() {
841 let current_conditions = &mut self.conditions[key];
842 let start = current_conditions.len();
843 self.uninit.push(UninitializedSet {
844 key,
845 uninitialized_conditions: start..(start + new_conditions.len()),
846 });
847 current_conditions.extend(new_conditions.into_iter().map(ConditionWithAccess::new));
848 }
849 key
850 }
851
852 pub(crate) fn remove(&mut self, key: SystemSetKey) -> bool {
854 self.sets.remove(key);
855 self.conditions.remove(key);
856 self.uninit.retain(|uninit| uninit.key != key);
857 true
858 }
859
860 pub fn is_initialized(&self) -> bool {
863 self.uninit.is_empty()
864 }
865
866 pub fn initialize(&mut self, world: &mut World) {
871 for uninit in self.uninit.drain(..) {
872 let Some(conditions) = self.conditions.get_mut(uninit.key) else {
873 continue;
874 };
875 for condition in &mut conditions[uninit.uninitialized_conditions] {
876 condition.access = condition.initialize(world);
877 }
878 }
879 }
880
881 pub fn check_type_set_ambiguity(
884 &self,
885 set_systems: &DagGroups<SystemSetKey, SystemKey>,
886 ambiguous_with: &UnGraph<NodeId>,
887 dependency: &DiGraph<NodeId>,
888 ) -> Result<(), SystemTypeSetAmbiguityError> {
889 for (&key, systems) in set_systems.iter() {
890 let set = &self[key];
891 if set.system_type().is_some() {
892 let instances = systems.len();
893 let ambiguous_with = ambiguous_with.edges(NodeId::Set(key));
894 let before = dependency.edges_directed(NodeId::Set(key), Incoming);
895 let after = dependency.edges_directed(NodeId::Set(key), Outgoing);
896 let relations = before.count() + after.count() + ambiguous_with.count();
897 if instances > 1 && relations > 0 {
898 return Err(SystemTypeSetAmbiguityError(key));
899 }
900 }
901 }
902 Ok(())
903 }
904}
905
906impl Index<SystemSetKey> for SystemSets {
907 type Output = dyn SystemSet;
908
909 #[track_caller]
910 fn index(&self, key: SystemSetKey) -> &Self::Output {
911 self.get(key).unwrap_or_else(|| {
912 panic!(
913 "System set with key {:?} does not exist in the schedule",
914 key
915 )
916 })
917 }
918}
919
920#[derive(Error, Debug)]
922#[error("Tried to order against `{0:?}` in a schedule that has more than one `{0:?}` instance. `{0:?}` is a `SystemTypeSet` and cannot be used for ordering if ambiguous. Use a different set without this restriction.")]
923pub struct SystemTypeSetAmbiguityError(pub SystemSetKey);
924
925#[cfg(test)]
926mod tests {
927 use alloc::{boxed::Box, vec};
928
929 use crate::{
930 prelude::SystemSet,
931 schedule::{SystemSets, Systems},
932 system::IntoSystem,
933 world::World,
934 };
935
936 #[derive(SystemSet, Clone, Copy, PartialEq, Eq, Debug, Hash)]
937 pub struct TestSet;
938
939 #[test]
940 fn systems() {
941 fn empty_system() {}
942
943 let mut systems = Systems::default();
944 assert!(systems.is_empty());
945 assert_eq!(systems.len(), 0);
946
947 let system = Box::new(IntoSystem::into_system(empty_system));
948 let key = systems.insert(system, vec![]);
949
950 assert!(!systems.is_empty());
951 assert_eq!(systems.len(), 1);
952 assert!(systems.get(key).is_some());
953 assert!(systems.get_conditions(key).is_some());
954 assert!(systems.get_conditions(key).unwrap().is_empty());
955 assert!(systems.get_mut(key).is_some());
956 assert!(!systems.is_initialized());
957 assert!(systems.iter().next().is_some());
958
959 let mut world = World::new();
960 systems.initialize(&mut world);
961 assert!(systems.is_initialized());
962 }
963
964 #[test]
965 fn system_sets() {
966 fn always_true() -> bool {
967 true
968 }
969
970 let mut sets = SystemSets::default();
971 assert!(sets.is_empty());
972 assert_eq!(sets.len(), 0);
973
974 let condition = Box::new(IntoSystem::into_system(always_true));
975 let key = sets.insert(TestSet.intern(), vec![condition]);
976
977 assert!(!sets.is_empty());
978 assert_eq!(sets.len(), 1);
979 assert!(sets.get(key).is_some());
980 assert!(sets.get_conditions(key).is_some());
981 assert!(!sets.get_conditions(key).unwrap().is_empty());
982 assert!(!sets.is_initialized());
983 assert!(sets.iter().next().is_some());
984
985 let mut world = World::new();
986 sets.initialize(&mut world);
987 assert!(sets.is_initialized());
988 }
989}