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 system::{ReadOnlySystem, RunSystemError, ScheduleSystem, System, SystemStateFlags},
27 world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World},
28};
29
30pub(crate) struct SystemNode {
32 pub(crate) inner: Option<SystemWithAccess>,
33}
34
35pub struct SystemWithAccess {
37 pub(crate) system: ScheduleSystem,
39 pub(crate) access: FilteredAccessSet,
42}
43
44impl SystemWithAccess {
45 pub fn new(system: ScheduleSystem) -> Self {
48 Self {
49 system,
50 access: FilteredAccessSet::new(),
51 }
52 }
53
54 pub fn system(&self) -> &ScheduleSystem {
56 &self.system
57 }
58}
59
60impl System for SystemWithAccess {
61 type In = ();
62 type Out = ();
63
64 #[inline]
65 fn name(&self) -> DebugName {
66 self.system.name()
67 }
68
69 #[inline]
70 fn system_type(&self) -> TypeId {
71 self.system.system_type()
72 }
73
74 #[inline]
75 fn flags(&self) -> SystemStateFlags {
76 self.system.flags()
77 }
78
79 #[inline]
80 unsafe fn run_unsafe(
81 &mut self,
82 input: SystemIn<'_, Self>,
83 world: UnsafeWorldCell,
84 ) -> Result<Self::Out, RunSystemError> {
85 unsafe { self.system.run_unsafe(input, world) }
87 }
88
89 #[cfg(feature = "hotpatching")]
90 #[inline]
91 fn refresh_hotpatch(&mut self) {
92 self.system.refresh_hotpatch();
93 }
94
95 #[inline]
96 fn apply_deferred(&mut self, world: &mut World) {
97 self.system.apply_deferred(world);
98 }
99
100 #[inline]
101 fn queue_deferred(&mut self, world: DeferredWorld) {
102 self.system.queue_deferred(world);
103 }
104
105 #[inline]
106 fn initialize(&mut self, world: &mut World) -> FilteredAccessSet {
107 self.system.initialize(world)
108 }
109
110 #[inline]
111 fn check_change_tick(&mut self, check: CheckChangeTicks) {
112 self.system.check_change_tick(check);
113 }
114
115 #[inline]
116 fn default_system_sets(&self) -> Vec<InternedSystemSet> {
117 self.system.default_system_sets()
118 }
119
120 #[inline]
121 fn get_last_run(&self) -> Tick {
122 self.system.get_last_run()
123 }
124
125 #[inline]
126 fn set_last_run(&mut self, last_run: Tick) {
127 self.system.set_last_run(last_run);
128 }
129}
130
131pub struct ConditionWithAccess {
133 pub condition: BoxedCondition,
135 pub access: FilteredAccessSet,
138}
139
140impl ConditionWithAccess {
141 pub const fn new(condition: BoxedCondition) -> Self {
144 Self {
145 condition,
146 access: FilteredAccessSet::new(),
147 }
148 }
149}
150
151impl System for ConditionWithAccess {
152 type In = ();
153 type Out = bool;
154
155 #[inline]
156 fn name(&self) -> DebugName {
157 self.condition.name()
158 }
159
160 #[inline]
161 fn system_type(&self) -> TypeId {
162 self.condition.system_type()
163 }
164
165 #[inline]
166 fn flags(&self) -> SystemStateFlags {
167 self.condition.flags()
168 }
169
170 #[inline]
171 unsafe fn run_unsafe(
172 &mut self,
173 input: SystemIn<'_, Self>,
174 world: UnsafeWorldCell,
175 ) -> Result<Self::Out, RunSystemError> {
176 unsafe { self.condition.run_unsafe(input, world) }
178 }
179
180 #[cfg(feature = "hotpatching")]
181 #[inline]
182 fn refresh_hotpatch(&mut self) {
183 self.condition.refresh_hotpatch();
184 }
185
186 #[inline]
187 fn apply_deferred(&mut self, world: &mut World) {
188 self.condition.apply_deferred(world);
189 }
190
191 #[inline]
192 fn queue_deferred(&mut self, world: DeferredWorld) {
193 self.condition.queue_deferred(world);
194 }
195
196 #[inline]
197 fn initialize(&mut self, world: &mut World) -> FilteredAccessSet {
198 self.condition.initialize(world)
199 }
200
201 #[inline]
202 fn check_change_tick(&mut self, check: CheckChangeTicks) {
203 self.condition.check_change_tick(check);
204 }
205
206 #[inline]
207 fn default_system_sets(&self) -> Vec<InternedSystemSet> {
208 self.condition.default_system_sets()
209 }
210
211 #[inline]
212 fn get_last_run(&self) -> Tick {
213 self.condition.get_last_run()
214 }
215
216 #[inline]
217 fn set_last_run(&mut self, last_run: Tick) {
218 self.condition.set_last_run(last_run);
219 }
220}
221
222impl SystemNode {
223 pub fn new(system: ScheduleSystem) -> Self {
225 Self {
226 inner: Some(SystemWithAccess::new(system)),
227 }
228 }
229
230 pub fn get(&self) -> Option<&SystemWithAccess> {
232 self.inner.as_ref()
233 }
234
235 pub fn get_mut(&mut self) -> Option<&mut SystemWithAccess> {
237 self.inner.as_mut()
238 }
239}
240
241new_key_type! {
242 pub struct SystemKey;
244 pub struct SystemSetKey;
246}
247
248impl GraphNodeId for SystemKey {
249 type Adjacent = (SystemKey, Direction);
250 type Edge = (SystemKey, SystemKey);
251
252 fn kind(&self) -> &'static str {
253 "system"
254 }
255}
256
257impl GraphNodeId for SystemSetKey {
258 type Adjacent = (SystemSetKey, Direction);
259 type Edge = (SystemSetKey, SystemSetKey);
260
261 fn kind(&self) -> &'static str {
262 "system set"
263 }
264}
265
266impl TryFrom<NodeId> for SystemKey {
267 type Error = SystemSetKey;
268
269 fn try_from(value: NodeId) -> Result<Self, Self::Error> {
270 match value {
271 NodeId::System(key) => Ok(key),
272 NodeId::Set(key) => Err(key),
273 }
274 }
275}
276
277impl TryFrom<NodeId> for SystemSetKey {
278 type Error = SystemKey;
279
280 fn try_from(value: NodeId) -> Result<Self, Self::Error> {
281 match value {
282 NodeId::System(key) => Err(key),
283 NodeId::Set(key) => Ok(key),
284 }
285 }
286}
287
288#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
292pub enum NodeId {
293 System(SystemKey),
295 Set(SystemSetKey),
297}
298
299impl NodeId {
300 pub const fn is_system(&self) -> bool {
302 matches!(self, NodeId::System(_))
303 }
304
305 pub const fn is_set(&self) -> bool {
307 matches!(self, NodeId::Set(_))
308 }
309
310 pub const fn as_system(&self) -> Option<SystemKey> {
312 match self {
313 NodeId::System(system) => Some(*system),
314 NodeId::Set(_) => None,
315 }
316 }
317
318 pub const fn as_set(&self) -> Option<SystemSetKey> {
320 match self {
321 NodeId::System(_) => None,
322 NodeId::Set(set) => Some(*set),
323 }
324 }
325}
326
327impl GraphNodeId for NodeId {
328 type Adjacent = CompactNodeIdAndDirection;
329 type Edge = CompactNodeIdPair;
330
331 fn kind(&self) -> &'static str {
332 match self {
333 NodeId::System(n) => n.kind(),
334 NodeId::Set(n) => n.kind(),
335 }
336 }
337}
338
339impl From<SystemKey> for NodeId {
340 fn from(system: SystemKey) -> Self {
341 NodeId::System(system)
342 }
343}
344
345impl From<SystemSetKey> for NodeId {
346 fn from(set: SystemSetKey) -> Self {
347 NodeId::Set(set)
348 }
349}
350
351#[derive(Clone, Copy)]
353pub struct CompactNodeIdAndDirection {
354 key: KeyData,
355 is_system: bool,
356 direction: Direction,
357}
358
359impl Debug for CompactNodeIdAndDirection {
360 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
361 let tuple: (_, _) = (*self).into();
362 tuple.fmt(f)
363 }
364}
365
366impl From<(NodeId, Direction)> for CompactNodeIdAndDirection {
367 fn from((id, direction): (NodeId, Direction)) -> Self {
368 let key = match id {
369 NodeId::System(key) => key.data(),
370 NodeId::Set(key) => key.data(),
371 };
372 let is_system = id.is_system();
373
374 Self {
375 key,
376 is_system,
377 direction,
378 }
379 }
380}
381
382impl From<CompactNodeIdAndDirection> for (NodeId, Direction) {
383 fn from(value: CompactNodeIdAndDirection) -> Self {
384 let node = match value.is_system {
385 true => NodeId::System(value.key.into()),
386 false => NodeId::Set(value.key.into()),
387 };
388
389 (node, value.direction)
390 }
391}
392
393#[derive(Clone, Copy, Hash, PartialEq, Eq)]
395pub struct CompactNodeIdPair {
396 key_a: KeyData,
397 key_b: KeyData,
398 is_system_a: bool,
399 is_system_b: bool,
400}
401
402impl Debug for CompactNodeIdPair {
403 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
404 let tuple: (_, _) = (*self).into();
405 tuple.fmt(f)
406 }
407}
408
409impl From<(NodeId, NodeId)> for CompactNodeIdPair {
410 fn from((a, b): (NodeId, NodeId)) -> Self {
411 let key_a = match a {
412 NodeId::System(index) => index.data(),
413 NodeId::Set(index) => index.data(),
414 };
415 let is_system_a = a.is_system();
416
417 let key_b = match b {
418 NodeId::System(index) => index.data(),
419 NodeId::Set(index) => index.data(),
420 };
421 let is_system_b = b.is_system();
422
423 Self {
424 key_a,
425 key_b,
426 is_system_a,
427 is_system_b,
428 }
429 }
430}
431
432impl From<CompactNodeIdPair> for (NodeId, NodeId) {
433 fn from(value: CompactNodeIdPair) -> Self {
434 let a = match value.is_system_a {
435 true => NodeId::System(value.key_a.into()),
436 false => NodeId::Set(value.key_a.into()),
437 };
438
439 let b = match value.is_system_b {
440 true => NodeId::System(value.key_b.into()),
441 false => NodeId::Set(value.key_b.into()),
442 };
443
444 (a, b)
445 }
446}
447
448#[derive(Default)]
450pub struct Systems {
451 nodes: SlotMap<SystemKey, SystemNode>,
453 conditions: SecondaryMap<SystemKey, Vec<ConditionWithAccess>>,
455 uninit: Vec<SystemKey>,
457}
458
459impl Systems {
460 pub fn len(&self) -> usize {
462 self.nodes.len()
463 }
464
465 pub fn is_empty(&self) -> bool {
467 self.nodes.is_empty()
468 }
469
470 pub fn get(&self, key: SystemKey) -> Option<&SystemWithAccess> {
472 self.nodes.get(key).and_then(|node| node.get())
473 }
474
475 pub fn get_mut(&mut self, key: SystemKey) -> Option<&mut SystemWithAccess> {
477 self.nodes.get_mut(key).and_then(|node| node.get_mut())
478 }
479
480 pub(crate) fn node_mut(&mut self, key: SystemKey) -> Option<&mut SystemNode> {
483 self.nodes.get_mut(key)
484 }
485
486 pub fn has_conditions(&self, key: SystemKey) -> bool {
488 self.conditions
489 .get(key)
490 .is_some_and(|conditions| !conditions.is_empty())
491 }
492
493 pub fn get_conditions(&self, key: SystemKey) -> Option<&[ConditionWithAccess]> {
495 self.conditions.get(key).map(Vec::as_slice)
496 }
497
498 pub fn get_conditions_mut(&mut self, key: SystemKey) -> Option<&mut Vec<ConditionWithAccess>> {
500 self.conditions.get_mut(key)
501 }
502
503 pub fn iter(
506 &self,
507 ) -> impl Iterator<Item = (SystemKey, &ScheduleSystem, &[ConditionWithAccess])> + '_ {
508 self.nodes.iter().filter_map(|(key, node)| {
509 let system = &node.get()?.system;
510 let conditions = self
511 .conditions
512 .get(key)
513 .map(Vec::as_slice)
514 .unwrap_or_default();
515 Some((key, system, conditions))
516 })
517 }
518
519 pub fn insert(
527 &mut self,
528 system: ScheduleSystem,
529 conditions: Vec<Box<dyn ReadOnlySystem<In = (), Out = bool>>>,
530 ) -> SystemKey {
531 let key = self.nodes.insert(SystemNode::new(system));
532 self.conditions.insert(
533 key,
534 conditions
535 .into_iter()
536 .map(ConditionWithAccess::new)
537 .collect(),
538 );
539 self.uninit.push(key);
540 key
541 }
542
543 pub(crate) fn remove(&mut self, key: SystemKey) -> bool {
545 let mut found = false;
546 if self.nodes.remove(key).is_some() {
547 found = true;
548 }
549
550 if self.conditions.remove(key).is_some() {
551 found = true;
552 }
553
554 if let Some(index) = self.uninit.iter().position(|value| *value == key) {
555 self.uninit.remove(index);
556 found = true;
557 }
558
559 found
560 }
561
562 pub fn is_initialized(&self) -> bool {
564 self.uninit.is_empty()
565 }
566
567 pub fn initialize(&mut self, world: &mut World) {
570 for key in self.uninit.drain(..) {
571 let Some(system) = self.nodes.get_mut(key).and_then(|node| node.get_mut()) else {
572 continue;
573 };
574 system.access = system.system.initialize(world);
575 let Some(conditions) = self.conditions.get_mut(key) else {
576 continue;
577 };
578 for condition in conditions {
579 condition.access = condition.condition.initialize(world);
580 }
581 }
582 }
583
584 pub fn get_conflicting_systems(
591 &self,
592 flat_dependency_analysis: &DagAnalysis<SystemKey>,
593 flat_ambiguous_with: &UnGraph<SystemKey>,
594 ambiguous_with_all: &HashSet<NodeId>,
595 ignored_ambiguities: &BTreeSet<ComponentId>,
596 ) -> ConflictingSystems {
597 let mut conflicting_systems: Vec<(_, _, Box<[_]>)> = Vec::new();
598 for &(a, b) in flat_dependency_analysis.disconnected() {
599 if flat_ambiguous_with.contains_edge(a, b)
600 || ambiguous_with_all.contains(&NodeId::System(a))
601 || ambiguous_with_all.contains(&NodeId::System(b))
602 {
603 continue;
604 }
605
606 let system_a = &self[a];
607 let system_b = &self[b];
608 if system_a.is_exclusive() || system_b.is_exclusive() {
609 conflicting_systems.push((a, b, Box::new([])));
610 } else {
611 let access_a = &system_a.access;
612 let access_b = &system_b.access;
613 if !access_a.is_compatible(access_b) {
614 match access_a.get_conflicts(access_b) {
615 AccessConflicts::Individual(conflicts) => {
616 let conflicts: Box<[_]> = conflicts
617 .iter()
618 .filter(|id| !ignored_ambiguities.contains(id))
619 .collect();
620 if !conflicts.is_empty() {
621 conflicting_systems.push((a, b, conflicts));
622 }
623 }
624 AccessConflicts::All => {
625 conflicting_systems.push((a, b, Box::new([])));
628 }
629 }
630 }
631 }
632 }
633
634 ConflictingSystems(conflicting_systems)
635 }
636}
637
638impl Index<SystemKey> for Systems {
639 type Output = SystemWithAccess;
640
641 #[track_caller]
642 fn index(&self, key: SystemKey) -> &Self::Output {
643 self.get(key)
644 .unwrap_or_else(|| panic!("System with key {:?} does not exist in the schedule", key))
645 }
646}
647
648impl IndexMut<SystemKey> for Systems {
649 #[track_caller]
650 fn index_mut(&mut self, key: SystemKey) -> &mut Self::Output {
651 self.get_mut(key)
652 .unwrap_or_else(|| panic!("System with key {:?} does not exist in the schedule", key))
653 }
654}
655
656#[derive(Clone, Debug, Default)]
661pub struct ConflictingSystems(pub Vec<(SystemKey, SystemKey, Box<[ComponentId]>)>);
662
663impl ConflictingSystems {
664 pub fn check_if_not_empty(&self) -> Result<(), AmbiguousSystemConflictsWarning> {
667 if self.0.is_empty() {
668 Ok(())
669 } else {
670 Err(AmbiguousSystemConflictsWarning(self.clone()))
671 }
672 }
673
674 pub fn to_string(
677 &self,
678 graph: &ScheduleGraph,
679 components: &Components,
680 ) -> impl Iterator<Item = (String, String, Box<[DebugName]>)> {
681 self.iter().map(move |(system_a, system_b, conflicts)| {
682 let name_a = graph.get_node_name(&NodeId::System(*system_a));
683 let name_b = graph.get_node_name(&NodeId::System(*system_b));
684
685 let conflict_names: Box<[_]> = conflicts
686 .iter()
687 .map(|id| components.get_name(*id).unwrap())
688 .collect();
689
690 (name_a, name_b, conflict_names)
691 })
692 }
693}
694
695impl Deref for ConflictingSystems {
696 type Target = Vec<(SystemKey, SystemKey, Box<[ComponentId]>)>;
697
698 fn deref(&self) -> &Self::Target {
699 &self.0
700 }
701}
702
703#[derive(Error, Debug)]
705#[error("Systems with conflicting access have indeterminate run order: {:?}", .0.0)]
706pub struct AmbiguousSystemConflictsWarning(pub ConflictingSystems);
707
708#[derive(Default)]
710pub struct SystemSets {
711 sets: SlotMap<SystemSetKey, InternedSystemSet>,
713 conditions: SecondaryMap<SystemSetKey, Vec<ConditionWithAccess>>,
715 ids: HashMap<InternedSystemSet, SystemSetKey>,
717 uninit: Vec<UninitializedSet>,
719}
720
721struct UninitializedSet {
723 key: SystemSetKey,
724 uninitialized_conditions: Range<usize>,
736}
737
738impl SystemSets {
739 pub fn len(&self) -> usize {
741 self.sets.len()
742 }
743
744 pub fn is_empty(&self) -> bool {
746 self.sets.is_empty()
747 }
748
749 pub fn contains(&self, set: impl SystemSet) -> bool {
751 self.ids.contains_key(&set.intern())
752 }
753
754 pub fn get(&self, key: SystemSetKey) -> Option<&dyn SystemSet> {
756 self.sets.get(key).map(|set| &**set)
757 }
758
759 pub fn get_key(&self, set: InternedSystemSet) -> Option<SystemSetKey> {
761 self.ids.get(&set).copied()
762 }
763
764 pub fn get_key_or_insert(&mut self, set: InternedSystemSet) -> SystemSetKey {
767 *self.ids.entry(set).or_insert_with(|| {
768 let key = self.sets.insert(set);
769 self.conditions.insert(key, Vec::new());
770 key
771 })
772 }
773
774 pub fn has_conditions(&self, key: SystemSetKey) -> bool {
776 self.conditions
777 .get(key)
778 .is_some_and(|conditions| !conditions.is_empty())
779 }
780
781 pub fn get_conditions(&self, key: SystemSetKey) -> Option<&[ConditionWithAccess]> {
784 self.conditions.get(key).map(Vec::as_slice)
785 }
786
787 pub fn get_conditions_mut(
790 &mut self,
791 key: SystemSetKey,
792 ) -> Option<&mut Vec<ConditionWithAccess>> {
793 self.conditions.get_mut(key)
794 }
795
796 pub fn iter(
799 &self,
800 ) -> impl Iterator<Item = (SystemSetKey, &dyn SystemSet, &[ConditionWithAccess])> {
801 self.sets.iter().filter_map(|(key, set)| {
802 let conditions = self.conditions.get(key)?.as_slice();
803 Some((key, &**set, conditions))
804 })
805 }
806
807 pub fn insert(
817 &mut self,
818 set: InternedSystemSet,
819 new_conditions: Vec<Box<dyn ReadOnlySystem<In = (), Out = bool>>>,
820 ) -> SystemSetKey {
821 let key = self.get_key_or_insert(set);
822 if !new_conditions.is_empty() {
823 let current_conditions = &mut self.conditions[key];
824 let start = current_conditions.len();
825 self.uninit.push(UninitializedSet {
826 key,
827 uninitialized_conditions: start..(start + new_conditions.len()),
828 });
829 current_conditions.extend(new_conditions.into_iter().map(ConditionWithAccess::new));
830 }
831 key
832 }
833
834 pub(crate) fn remove(&mut self, key: SystemSetKey) -> bool {
836 self.sets.remove(key);
837 self.conditions.remove(key);
838 self.uninit.retain(|uninit| uninit.key != key);
839 true
840 }
841
842 pub fn is_initialized(&self) -> bool {
845 self.uninit.is_empty()
846 }
847
848 pub fn initialize(&mut self, world: &mut World) {
853 for uninit in self.uninit.drain(..) {
854 let Some(conditions) = self.conditions.get_mut(uninit.key) else {
855 continue;
856 };
857 for condition in &mut conditions[uninit.uninitialized_conditions] {
858 condition.access = condition.initialize(world);
859 }
860 }
861 }
862
863 pub fn check_type_set_ambiguity(
866 &self,
867 set_systems: &DagGroups<SystemSetKey, SystemKey>,
868 ambiguous_with: &UnGraph<NodeId>,
869 dependency: &DiGraph<NodeId>,
870 ) -> Result<(), SystemTypeSetAmbiguityError> {
871 for (&key, systems) in set_systems.iter() {
872 let set = &self[key];
873 if set.system_type().is_some() {
874 let instances = systems.len();
875 let ambiguous_with = ambiguous_with.edges(NodeId::Set(key));
876 let before = dependency.edges_directed(NodeId::Set(key), Incoming);
877 let after = dependency.edges_directed(NodeId::Set(key), Outgoing);
878 let relations = before.count() + after.count() + ambiguous_with.count();
879 if instances > 1 && relations > 0 {
880 return Err(SystemTypeSetAmbiguityError(key));
881 }
882 }
883 }
884 Ok(())
885 }
886}
887
888impl Index<SystemSetKey> for SystemSets {
889 type Output = dyn SystemSet;
890
891 #[track_caller]
892 fn index(&self, key: SystemSetKey) -> &Self::Output {
893 self.get(key).unwrap_or_else(|| {
894 panic!(
895 "System set with key {:?} does not exist in the schedule",
896 key
897 )
898 })
899 }
900}
901
902#[derive(Error, Debug)]
904#[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.")]
905pub struct SystemTypeSetAmbiguityError(pub SystemSetKey);
906
907#[cfg(test)]
908mod tests {
909 use alloc::{boxed::Box, vec};
910
911 use crate::{
912 prelude::SystemSet,
913 schedule::{SystemSets, Systems},
914 system::IntoSystem,
915 world::World,
916 };
917
918 #[derive(SystemSet, Clone, Copy, PartialEq, Eq, Debug, Hash)]
919 pub struct TestSet;
920
921 #[test]
922 fn systems() {
923 fn empty_system() {}
924
925 let mut systems = Systems::default();
926 assert!(systems.is_empty());
927 assert_eq!(systems.len(), 0);
928
929 let system = Box::new(IntoSystem::into_system(empty_system));
930 let key = systems.insert(system, vec![]);
931
932 assert!(!systems.is_empty());
933 assert_eq!(systems.len(), 1);
934 assert!(systems.get(key).is_some());
935 assert!(systems.get_conditions(key).is_some());
936 assert!(systems.get_conditions(key).unwrap().is_empty());
937 assert!(systems.get_mut(key).is_some());
938 assert!(!systems.is_initialized());
939 assert!(systems.iter().next().is_some());
940
941 let mut world = World::new();
942 systems.initialize(&mut world);
943 assert!(systems.is_initialized());
944 }
945
946 #[test]
947 fn system_sets() {
948 fn always_true() -> bool {
949 true
950 }
951
952 let mut sets = SystemSets::default();
953 assert!(sets.is_empty());
954 assert_eq!(sets.len(), 0);
955
956 let condition = Box::new(IntoSystem::into_system(always_true));
957 let key = sets.insert(TestSet.intern(), vec![condition]);
958
959 assert!(!sets.is_empty());
960 assert_eq!(sets.len(), 1);
961 assert!(sets.get(key).is_some());
962 assert!(sets.get_conditions(key).is_some());
963 assert!(!sets.get_conditions(key).unwrap().is_empty());
964 assert!(!sets.is_initialized());
965 assert!(sets.iter().next().is_some());
966
967 let mut world = World::new();
968 sets.initialize(&mut world);
969 assert!(sets.is_initialized());
970 }
971}