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