1use core::any::TypeId;
2use fixedbitset::FixedBitSet;
3use std::collections::HashMap;
4
5use crate::{
6 schedule::{InternedScheduleLabel, NodeId, Schedule, ScheduleLabel},
7 system::{IntoSystem, ResMut, Resource},
8};
9use bevy_utils::{
10 tracing::{info, warn},
11 TypeIdMap,
12};
13use derive_more::derive::{Display, Error};
14
15#[cfg(not(feature = "bevy_debug_stepping"))]
16use bevy_utils::tracing::error;
17
18#[cfg(test)]
19use bevy_utils::tracing::debug;
20
21use crate as bevy_ecs;
22
23#[derive(Debug, Default, PartialEq, Eq, Copy, Clone)]
24enum Action {
25 #[default]
27 RunAll,
28
29 Waiting,
31
32 Continue,
36
37 Step,
39}
40
41#[derive(Debug, Copy, Clone)]
42enum SystemBehavior {
43 AlwaysRun,
45
46 NeverRun,
48
49 Break,
54
55 Continue,
59}
60
61#[derive(Debug, Default, Clone, Copy)]
63struct Cursor {
64 pub schedule: usize,
66 pub system: usize,
68}
69
70enum SystemIdentifier {
72 Type(TypeId),
73 Node(NodeId),
74}
75
76enum Update {
79 SetAction(Action),
81 AddSchedule(InternedScheduleLabel),
83 RemoveSchedule(InternedScheduleLabel),
85 ClearSchedule(InternedScheduleLabel),
87 SetBehavior(InternedScheduleLabel, SystemIdentifier, SystemBehavior),
89 ClearBehavior(InternedScheduleLabel, SystemIdentifier),
91}
92
93#[derive(Error, Display, Debug)]
94#[display("not available until all configured schedules have been run; try again next frame")]
95pub struct NotReady;
96
97#[derive(Resource, Default)]
98pub struct Stepping {
100 schedule_states: HashMap<InternedScheduleLabel, ScheduleState>,
102
103 schedule_order: Vec<InternedScheduleLabel>,
105
106 cursor: Cursor,
108
109 previous_schedule: Option<usize>,
111
112 action: Action,
114
115 updates: Vec<Update>,
117}
118
119impl core::fmt::Debug for Stepping {
120 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
121 write!(
122 f,
123 "Stepping {{ action: {:?}, schedules: {:?}, order: {:?}",
124 self.action,
125 self.schedule_states.keys(),
126 self.schedule_order
127 )?;
128 if self.action != Action::RunAll {
129 let Cursor { schedule, system } = self.cursor;
130 match self.schedule_order.get(schedule) {
131 Some(label) => write!(f, "cursor: {:?}[{}], ", label, system)?,
132 None => write!(f, "cursor: None, ")?,
133 };
134 }
135 write!(f, "}}")
136 }
137}
138
139impl Stepping {
140 pub fn new() -> Self {
142 Stepping::default()
143 }
144
145 pub fn begin_frame(stepping: Option<ResMut<Self>>) {
149 if let Some(mut stepping) = stepping {
150 stepping.next_frame();
151 }
152 }
153
154 pub fn schedules(&self) -> Result<&Vec<InternedScheduleLabel>, NotReady> {
157 if self.schedule_order.len() == self.schedule_states.len() {
158 Ok(&self.schedule_order)
159 } else {
160 Err(NotReady)
161 }
162 }
163
164 pub fn cursor(&self) -> Option<(InternedScheduleLabel, NodeId)> {
171 if self.action == Action::RunAll {
172 return None;
173 }
174 let label = match self.schedule_order.get(self.cursor.schedule) {
175 None => return None,
176 Some(label) => label,
177 };
178 let state = match self.schedule_states.get(label) {
179 None => return None,
180 Some(state) => state,
181 };
182 state
183 .node_ids
184 .get(self.cursor.system)
185 .map(|node_id| (*label, *node_id))
186 }
187
188 pub fn add_schedule(&mut self, schedule: impl ScheduleLabel) -> &mut Self {
190 self.updates.push(Update::AddSchedule(schedule.intern()));
191 self
192 }
193
194 pub fn remove_schedule(&mut self, schedule: impl ScheduleLabel) -> &mut Self {
199 self.updates.push(Update::RemoveSchedule(schedule.intern()));
200 self
201 }
202
203 pub fn clear_schedule(&mut self, schedule: impl ScheduleLabel) -> &mut Self {
205 self.updates.push(Update::ClearSchedule(schedule.intern()));
206 self
207 }
208
209 pub fn enable(&mut self) -> &mut Self {
211 #[cfg(feature = "bevy_debug_stepping")]
212 self.updates.push(Update::SetAction(Action::Waiting));
213 #[cfg(not(feature = "bevy_debug_stepping"))]
214 error!(
215 "Stepping cannot be enabled; \
216 bevy was compiled without the bevy_debug_stepping feature"
217 );
218 self
219 }
220
221 pub fn disable(&mut self) -> &mut Self {
223 self.updates.push(Update::SetAction(Action::RunAll));
224 self
225 }
226
227 pub fn is_enabled(&self) -> bool {
229 self.action != Action::RunAll
230 }
231
232 pub fn step_frame(&mut self) -> &mut Self {
236 self.updates.push(Update::SetAction(Action::Step));
237 self
238 }
239
240 pub fn continue_frame(&mut self) -> &mut Self {
245 self.updates.push(Update::SetAction(Action::Continue));
246 self
247 }
248
249 pub fn always_run<Marker>(
254 &mut self,
255 schedule: impl ScheduleLabel,
256 system: impl IntoSystem<(), (), Marker>,
257 ) -> &mut Self {
258 let type_id = system.system_type_id();
259 self.updates.push(Update::SetBehavior(
260 schedule.intern(),
261 SystemIdentifier::Type(type_id),
262 SystemBehavior::AlwaysRun,
263 ));
264
265 self
266 }
267
268 pub fn always_run_node(&mut self, schedule: impl ScheduleLabel, node: NodeId) -> &mut Self {
270 self.updates.push(Update::SetBehavior(
271 schedule.intern(),
272 SystemIdentifier::Node(node),
273 SystemBehavior::AlwaysRun,
274 ));
275 self
276 }
277
278 pub fn never_run<Marker>(
280 &mut self,
281 schedule: impl ScheduleLabel,
282 system: impl IntoSystem<(), (), Marker>,
283 ) -> &mut Self {
284 let type_id = system.system_type_id();
285 self.updates.push(Update::SetBehavior(
286 schedule.intern(),
287 SystemIdentifier::Type(type_id),
288 SystemBehavior::NeverRun,
289 ));
290
291 self
292 }
293
294 pub fn never_run_node(&mut self, schedule: impl ScheduleLabel, node: NodeId) -> &mut Self {
296 self.updates.push(Update::SetBehavior(
297 schedule.intern(),
298 SystemIdentifier::Node(node),
299 SystemBehavior::NeverRun,
300 ));
301 self
302 }
303
304 pub fn set_breakpoint<Marker>(
306 &mut self,
307 schedule: impl ScheduleLabel,
308 system: impl IntoSystem<(), (), Marker>,
309 ) -> &mut Self {
310 let type_id = system.system_type_id();
311 self.updates.push(Update::SetBehavior(
312 schedule.intern(),
313 SystemIdentifier::Type(type_id),
314 SystemBehavior::Break,
315 ));
316
317 self
318 }
319
320 pub fn set_breakpoint_node(&mut self, schedule: impl ScheduleLabel, node: NodeId) -> &mut Self {
322 self.updates.push(Update::SetBehavior(
323 schedule.intern(),
324 SystemIdentifier::Node(node),
325 SystemBehavior::Break,
326 ));
327 self
328 }
329
330 pub fn clear_breakpoint<Marker>(
332 &mut self,
333 schedule: impl ScheduleLabel,
334 system: impl IntoSystem<(), (), Marker>,
335 ) -> &mut Self {
336 self.clear_system(schedule, system);
337
338 self
339 }
340
341 pub fn clear_breakpoint_node(
343 &mut self,
344 schedule: impl ScheduleLabel,
345 node: NodeId,
346 ) -> &mut Self {
347 self.clear_node(schedule, node);
348 self
349 }
350
351 pub fn clear_system<Marker>(
353 &mut self,
354 schedule: impl ScheduleLabel,
355 system: impl IntoSystem<(), (), Marker>,
356 ) -> &mut Self {
357 let type_id = system.system_type_id();
358 self.updates.push(Update::ClearBehavior(
359 schedule.intern(),
360 SystemIdentifier::Type(type_id),
361 ));
362
363 self
364 }
365
366 pub fn clear_node(&mut self, schedule: impl ScheduleLabel, node: NodeId) -> &mut Self {
368 self.updates.push(Update::ClearBehavior(
369 schedule.intern(),
370 SystemIdentifier::Node(node),
371 ));
372 self
373 }
374
375 fn first_system_index_for_schedule(&self, index: usize) -> usize {
377 let label = match self.schedule_order.get(index) {
378 None => return 0,
379 Some(label) => label,
380 };
381 let state = match self.schedule_states.get(label) {
382 None => return 0,
383 Some(state) => state,
384 };
385 state.first.unwrap_or(0)
386 }
387
388 fn reset_cursor(&mut self) {
390 self.cursor = Cursor {
391 schedule: 0,
392 system: self.first_system_index_for_schedule(0),
393 };
394 }
395
396 fn next_frame(&mut self) {
398 if self.action != Action::RunAll {
401 self.action = Action::Waiting;
402 self.previous_schedule = None;
403
404 if self.cursor.schedule >= self.schedule_order.len() {
406 self.reset_cursor();
407 }
408 }
409
410 if self.updates.is_empty() {
411 return;
412 }
413
414 let mut reset_cursor = false;
415 for update in self.updates.drain(..) {
416 match update {
417 Update::SetAction(Action::RunAll) => {
418 self.action = Action::RunAll;
419 reset_cursor = true;
420 }
421 Update::SetAction(action) => {
422 match (self.action, action) {
427 (Action::RunAll, Action::RunAll)
430 | (Action::Waiting, Action::Waiting)
431 | (Action::Continue, Action::Continue)
432 | (Action::Step, Action::Step)
433 | (Action::Continue, Action::Waiting)
434 | (Action::Step, Action::Waiting) => continue,
435
436 (Action::RunAll, Action::Waiting) => info!("enabled stepping"),
438 (Action::RunAll, _) => {
439 warn!(
440 "stepping not enabled; call Stepping::enable() \
441 before step_frame() or continue_frame()"
442 );
443 continue;
444 }
445
446 (Action::Waiting, Action::RunAll) => info!("disabled stepping"),
448 (Action::Waiting, Action::Continue) => info!("continue frame"),
449 (Action::Waiting, Action::Step) => info!("step frame"),
450
451 (Action::Continue, Action::RunAll) => info!("disabled stepping"),
453 (Action::Continue, Action::Step) => {
454 warn!("ignoring step_frame(); already continuing next frame");
455 continue;
456 }
457
458 (Action::Step, Action::RunAll) => info!("disabled stepping"),
460 (Action::Step, Action::Continue) => {
461 warn!("ignoring continue_frame(); already stepping next frame");
462 continue;
463 }
464 }
465
466 self.action = action;
468 }
469 Update::AddSchedule(l) => {
470 self.schedule_states.insert(l, ScheduleState::default());
471 }
472 Update::RemoveSchedule(label) => {
473 self.schedule_states.remove(&label);
474 if let Some(index) = self.schedule_order.iter().position(|l| l == &label) {
475 self.schedule_order.remove(index);
476 }
477 reset_cursor = true;
478 }
479 Update::ClearSchedule(label) => match self.schedule_states.get_mut(&label) {
480 Some(state) => state.clear_behaviors(),
481 None => {
482 warn!(
483 "stepping is not enabled for schedule {:?}; \
484 use `.add_stepping({:?})` to enable stepping",
485 label, label
486 );
487 }
488 },
489 Update::SetBehavior(label, system, behavior) => {
490 match self.schedule_states.get_mut(&label) {
491 Some(state) => state.set_behavior(system, behavior),
492 None => {
493 warn!(
494 "stepping is not enabled for schedule {:?}; \
495 use `.add_stepping({:?})` to enable stepping",
496 label, label
497 );
498 }
499 }
500 }
501 Update::ClearBehavior(label, system) => {
502 match self.schedule_states.get_mut(&label) {
503 Some(state) => state.clear_behavior(system),
504 None => {
505 warn!(
506 "stepping is not enabled for schedule {:?}; \
507 use `.add_stepping({:?})` to enable stepping",
508 label, label
509 );
510 }
511 }
512 }
513 }
514 }
515
516 if reset_cursor {
517 self.reset_cursor();
518 }
519 }
520
521 pub fn skipped_systems(&mut self, schedule: &Schedule) -> Option<FixedBitSet> {
524 if self.action == Action::RunAll {
525 return None;
526 }
527
528 let label = schedule.label();
530 let state = self.schedule_states.get_mut(&label)?;
531
532 let index = self.schedule_order.iter().position(|l| *l == label);
541 let index = match (index, self.previous_schedule) {
542 (Some(index), _) => index,
543 (None, None) => {
544 self.schedule_order.insert(0, label);
545 0
546 }
547 (None, Some(last)) => {
548 self.schedule_order.insert(last + 1, label);
549 last + 1
550 }
551 };
552 self.previous_schedule = Some(index);
555
556 #[cfg(test)]
557 debug!(
558 "cursor {:?}, index {}, label {:?}",
559 self.cursor, index, label
560 );
561
562 let cursor = self.cursor;
566 let (skip_list, next_system) = if index == cursor.schedule {
567 let (skip_list, next_system) =
568 state.skipped_systems(schedule, cursor.system, self.action);
569
570 if self.action == Action::Step {
573 self.action = Action::Waiting;
574 }
575 (skip_list, next_system)
576 } else {
577 let (skip_list, _) = state.skipped_systems(schedule, 0, Action::Waiting);
580 (skip_list, Some(cursor.system))
581 };
582
583 match next_system {
590 Some(i) => self.cursor.system = i,
591 None => {
592 let index = cursor.schedule + 1;
593 self.cursor = Cursor {
594 schedule: index,
595 system: self.first_system_index_for_schedule(index),
596 };
597
598 #[cfg(test)]
599 debug!("advanced schedule index: {} -> {}", cursor.schedule, index);
600 }
601 }
602
603 Some(skip_list)
604 }
605}
606
607#[derive(Default)]
608struct ScheduleState {
609 behaviors: HashMap<NodeId, SystemBehavior>,
611
612 node_ids: Vec<NodeId>,
618
619 behavior_updates: TypeIdMap<Option<SystemBehavior>>,
622
623 first: Option<usize>,
625}
626
627impl ScheduleState {
628 fn set_behavior(&mut self, system: SystemIdentifier, behavior: SystemBehavior) {
630 self.first = None;
631 match system {
632 SystemIdentifier::Node(node_id) => {
633 self.behaviors.insert(node_id, behavior);
634 }
635 SystemIdentifier::Type(type_id) => {
639 self.behavior_updates.insert(type_id, Some(behavior));
640 }
641 }
642 }
643
644 fn clear_behavior(&mut self, system: SystemIdentifier) {
646 self.first = None;
647 match system {
648 SystemIdentifier::Node(node_id) => {
649 self.behaviors.remove(&node_id);
650 }
651 SystemIdentifier::Type(type_id) => {
653 self.behavior_updates.insert(type_id, None);
654 }
655 }
656 }
657
658 fn clear_behaviors(&mut self) {
660 self.behaviors.clear();
661 self.behavior_updates.clear();
662 self.first = None;
663 }
664
665 fn apply_behavior_updates(&mut self, schedule: &Schedule) {
668 for (node_id, system) in schedule.systems().unwrap() {
674 let behavior = self.behavior_updates.get(&system.type_id());
675 match behavior {
676 None => continue,
677 Some(None) => {
678 self.behaviors.remove(&node_id);
679 }
680 Some(Some(behavior)) => {
681 self.behaviors.insert(node_id, *behavior);
682 }
683 }
684 }
685 self.behavior_updates.clear();
686
687 #[cfg(test)]
688 debug!("apply_updates(): {:?}", self.behaviors);
689 }
690
691 fn skipped_systems(
692 &mut self,
693 schedule: &Schedule,
694 start: usize,
695 mut action: Action,
696 ) -> (FixedBitSet, Option<usize>) {
697 use core::cmp::Ordering;
698
699 if self.node_ids.len() != schedule.systems_len() {
702 self.node_ids.clone_from(&schedule.executable().system_ids);
703 }
704
705 if !self.behavior_updates.is_empty() {
709 self.apply_behavior_updates(schedule);
710 }
711
712 if self.first.is_none() {
714 for (i, (node_id, _)) in schedule.systems().unwrap().enumerate() {
715 match self.behaviors.get(&node_id) {
716 Some(SystemBehavior::AlwaysRun | SystemBehavior::NeverRun) => continue,
717 Some(_) | None => {
718 self.first = Some(i);
719 break;
720 }
721 }
722 }
723 }
724
725 let mut skip = FixedBitSet::with_capacity(schedule.systems_len());
726 let mut pos = start;
727
728 for (i, (node_id, _system)) in schedule.systems().unwrap().enumerate() {
729 let behavior = self
730 .behaviors
731 .get(&node_id)
732 .unwrap_or(&SystemBehavior::Continue);
733
734 #[cfg(test)]
735 debug!(
736 "skipped_systems(): systems[{}], pos {}, Action::{:?}, Behavior::{:?}, {}",
737 i,
738 pos,
739 action,
740 behavior,
741 _system.name()
742 );
743
744 match (action, behavior) {
745 (_, SystemBehavior::NeverRun) => {
750 skip.insert(i);
751 if i == pos {
752 pos += 1;
753 }
754 }
755 (_, SystemBehavior::AlwaysRun) => {
760 if i == pos {
761 pos += 1;
762 }
763 }
764 (Action::Waiting, _) => skip.insert(i),
767
768 (Action::Step, _) => match i.cmp(&pos) {
774 Ordering::Less => skip.insert(i),
775 Ordering::Equal => {
776 pos += 1;
777 action = Action::Waiting;
778 }
779 Ordering::Greater => unreachable!(),
780 },
781 (Action::Continue, SystemBehavior::Continue) => {
785 if i < start {
786 skip.insert(i);
787 }
788 }
789 (Action::Continue, SystemBehavior::Break) => {
798 if i != start {
799 skip.insert(i);
800
801 if i > start {
804 action = Action::Waiting;
805 }
806 }
807 }
808 (Action::RunAll, _) => unreachable!(),
811 }
812
813 if i == pos && action != Action::Waiting {
816 pos += 1;
817 }
818 }
819
820 if pos >= schedule.systems_len() {
823 (skip, None)
824 } else {
825 (skip, Some(pos))
826 }
827 }
828}
829
830#[cfg(all(test, feature = "bevy_debug_stepping"))]
831mod tests {
832 use super::*;
833 use crate::{prelude::*, schedule::ScheduleLabel};
834
835 pub use crate as bevy_ecs;
836
837 #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
838 struct TestSchedule;
839
840 #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
841 struct TestScheduleA;
842
843 #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
844 struct TestScheduleB;
845
846 #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
847 struct TestScheduleC;
848
849 #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
850 struct TestScheduleD;
851
852 fn first_system() {}
853 fn second_system() {}
854 fn third_system() {}
855
856 fn setup() -> (Schedule, World) {
857 let mut world = World::new();
858 let mut schedule = Schedule::new(TestSchedule);
859 schedule.add_systems((first_system, second_system).chain());
860 schedule.initialize(&mut world).unwrap();
861 (schedule, world)
862 }
863
864 macro_rules! assert_skip_list_eq {
867 ($actual:expr, $expected:expr, $system_names:expr) => {
868 let actual = $actual;
869 let expected = $expected;
870 let systems: &Vec<&str> = $system_names;
871
872 if (actual != expected) {
873 use core::fmt::Write as _;
874
875 let mut msg = format!(
878 "Schedule:\n {:9} {:16}{:6} {:6} {:6}\n",
879 "index", "name", "expect", "actual", "result"
880 );
881 for (i, name) in systems.iter().enumerate() {
882 let _ = write!(msg, " system[{:1}] {:16}", i, name);
883 match (expected.contains(i), actual.contains(i)) {
884 (true, true) => msg.push_str("skip skip pass\n"),
885 (true, false) => {
886 msg.push_str("skip run FAILED; system should not have run\n")
887 }
888 (false, true) => {
889 msg.push_str("run skip FAILED; system should have run\n")
890 }
891 (false, false) => msg.push_str("run run pass\n"),
892 }
893 }
894 assert_eq!(actual, expected, "{}", msg);
895 }
896 };
897 }
898
899 macro_rules! assert_systems_run {
902 ($schedule:expr, $skipped_systems:expr, $($system:expr),*) => {
903 let systems: Vec<(TypeId, alloc::borrow::Cow<'static, str>)> = $schedule.systems().unwrap()
906 .map(|(_, system)| {
907 (system.type_id(), system.name())
908 })
909 .collect();
910
911 let mut expected = FixedBitSet::with_capacity(systems.len());
913 $(
914 let sys = IntoSystem::into_system($system);
915 for (i, (type_id, _)) in systems.iter().enumerate() {
916 if sys.type_id() == *type_id {
917 expected.insert(i);
918 }
919 }
920 )*
921
922 expected.toggle_range(..);
924
925 let actual = match $skipped_systems {
927 None => FixedBitSet::with_capacity(systems.len()),
928 Some(b) => b,
929 };
930 let system_names: Vec<&str> = systems
931 .iter()
932 .map(|(_,n)| n.rsplit_once("::").unwrap().1)
933 .collect();
934
935 assert_skip_list_eq!(actual, expected, &system_names);
936 };
937 }
938
939 macro_rules! assert_schedule_runs {
946 ($schedule:expr, $stepping:expr, $($system:expr),*) => {
947 $stepping.next_frame();
950 assert_systems_run!($schedule, $stepping.skipped_systems($schedule), $($system),*);
951 };
952 }
953
954 #[test]
955 fn stepping_disabled() {
956 let (schedule, _world) = setup();
957
958 let mut stepping = Stepping::new();
959 stepping.add_schedule(TestSchedule).disable().next_frame();
960
961 assert!(stepping.skipped_systems(&schedule).is_none());
962 assert!(stepping.cursor().is_none());
963 }
964
965 #[test]
966 fn unknown_schedule() {
967 let (schedule, _world) = setup();
968
969 let mut stepping = Stepping::new();
970 stepping.enable().next_frame();
971
972 assert!(stepping.skipped_systems(&schedule).is_none());
973 }
974
975 #[test]
976 fn disabled_always_run() {
977 let (schedule, _world) = setup();
978
979 let mut stepping = Stepping::new();
980 stepping
981 .add_schedule(TestSchedule)
982 .disable()
983 .always_run(TestSchedule, first_system);
984
985 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
986 }
987
988 #[test]
989 fn waiting_always_run() {
990 let (schedule, _world) = setup();
991
992 let mut stepping = Stepping::new();
993 stepping
994 .add_schedule(TestSchedule)
995 .enable()
996 .always_run(TestSchedule, first_system);
997
998 assert_schedule_runs!(&schedule, &mut stepping, first_system);
999 }
1000
1001 #[test]
1002 fn step_always_run() {
1003 let (schedule, _world) = setup();
1004
1005 let mut stepping = Stepping::new();
1006 stepping
1007 .add_schedule(TestSchedule)
1008 .enable()
1009 .always_run(TestSchedule, first_system)
1010 .step_frame();
1011
1012 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1013 }
1014
1015 #[test]
1016 fn continue_always_run() {
1017 let (schedule, _world) = setup();
1018
1019 let mut stepping = Stepping::new();
1020 stepping
1021 .add_schedule(TestSchedule)
1022 .enable()
1023 .always_run(TestSchedule, first_system)
1024 .continue_frame();
1025
1026 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1027 }
1028
1029 #[test]
1030 fn disabled_never_run() {
1031 let (schedule, _world) = setup();
1032
1033 let mut stepping = Stepping::new();
1034 stepping
1035 .add_schedule(TestSchedule)
1036 .never_run(TestSchedule, first_system)
1037 .disable();
1038 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1039 }
1040
1041 #[test]
1042 fn waiting_never_run() {
1043 let (schedule, _world) = setup();
1044
1045 let mut stepping = Stepping::new();
1046 stepping
1047 .add_schedule(TestSchedule)
1048 .enable()
1049 .never_run(TestSchedule, first_system);
1050
1051 assert_schedule_runs!(&schedule, &mut stepping,);
1052 }
1053
1054 #[test]
1055 fn step_never_run() {
1056 let (schedule, _world) = setup();
1057
1058 let mut stepping = Stepping::new();
1059 stepping
1060 .add_schedule(TestSchedule)
1061 .enable()
1062 .never_run(TestSchedule, first_system)
1063 .step_frame();
1064
1065 assert_schedule_runs!(&schedule, &mut stepping, second_system);
1066 }
1067
1068 #[test]
1069 fn continue_never_run() {
1070 let (schedule, _world) = setup();
1071
1072 let mut stepping = Stepping::new();
1073 stepping
1074 .add_schedule(TestSchedule)
1075 .enable()
1076 .never_run(TestSchedule, first_system)
1077 .continue_frame();
1078
1079 assert_schedule_runs!(&schedule, &mut stepping, second_system);
1080 }
1081
1082 #[test]
1083 fn disabled_breakpoint() {
1084 let (schedule, _world) = setup();
1085
1086 let mut stepping = Stepping::new();
1087 stepping
1088 .add_schedule(TestSchedule)
1089 .disable()
1090 .set_breakpoint(TestSchedule, second_system);
1091
1092 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1093 }
1094
1095 #[test]
1096 fn waiting_breakpoint() {
1097 let (schedule, _world) = setup();
1098
1099 let mut stepping = Stepping::new();
1100 stepping
1101 .add_schedule(TestSchedule)
1102 .enable()
1103 .set_breakpoint(TestSchedule, second_system);
1104
1105 assert_schedule_runs!(&schedule, &mut stepping,);
1106 }
1107
1108 #[test]
1109 fn step_breakpoint() {
1110 let (schedule, _world) = setup();
1111
1112 let mut stepping = Stepping::new();
1113 stepping
1114 .add_schedule(TestSchedule)
1115 .enable()
1116 .set_breakpoint(TestSchedule, second_system)
1117 .step_frame();
1118
1119 assert_schedule_runs!(&schedule, &mut stepping, first_system);
1122 stepping.step_frame();
1123 assert_schedule_runs!(&schedule, &mut stepping, second_system);
1124
1125 stepping.step_frame();
1128 assert_schedule_runs!(&schedule, &mut stepping, first_system);
1129
1130 assert_schedule_runs!(&schedule, &mut stepping,);
1132 }
1133
1134 #[test]
1135 fn continue_breakpoint() {
1136 let (schedule, _world) = setup();
1137
1138 let mut stepping = Stepping::new();
1139 stepping
1140 .add_schedule(TestSchedule)
1141 .enable()
1142 .set_breakpoint(TestSchedule, second_system)
1143 .continue_frame();
1144
1145 assert_schedule_runs!(&schedule, &mut stepping, first_system);
1146 stepping.continue_frame();
1147 assert_schedule_runs!(&schedule, &mut stepping, second_system);
1148 stepping.continue_frame();
1149 assert_schedule_runs!(&schedule, &mut stepping, first_system);
1150 }
1151
1152 #[test]
1155 fn continue_step_continue_with_breakpoint() {
1156 let mut world = World::new();
1157 let mut schedule = Schedule::new(TestSchedule);
1158 schedule.add_systems((first_system, second_system, third_system).chain());
1159 schedule.initialize(&mut world).unwrap();
1160
1161 let mut stepping = Stepping::new();
1162 stepping
1163 .add_schedule(TestSchedule)
1164 .enable()
1165 .set_breakpoint(TestSchedule, second_system);
1166
1167 stepping.continue_frame();
1168 assert_schedule_runs!(&schedule, &mut stepping, first_system);
1169
1170 stepping.step_frame();
1171 assert_schedule_runs!(&schedule, &mut stepping, second_system);
1172
1173 stepping.continue_frame();
1174 assert_schedule_runs!(&schedule, &mut stepping, third_system);
1175 }
1176
1177 #[test]
1178 fn clear_breakpoint() {
1179 let (schedule, _world) = setup();
1180
1181 let mut stepping = Stepping::new();
1182 stepping
1183 .add_schedule(TestSchedule)
1184 .enable()
1185 .set_breakpoint(TestSchedule, second_system)
1186 .continue_frame();
1187
1188 assert_schedule_runs!(&schedule, &mut stepping, first_system);
1189 stepping.continue_frame();
1190 assert_schedule_runs!(&schedule, &mut stepping, second_system);
1191
1192 stepping.clear_breakpoint(TestSchedule, second_system);
1193 stepping.continue_frame();
1194 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1195 }
1196
1197 #[test]
1198 fn clear_system() {
1199 let (schedule, _world) = setup();
1200
1201 let mut stepping = Stepping::new();
1202 stepping
1203 .add_schedule(TestSchedule)
1204 .enable()
1205 .never_run(TestSchedule, second_system)
1206 .continue_frame();
1207 assert_schedule_runs!(&schedule, &mut stepping, first_system);
1208
1209 stepping.clear_system(TestSchedule, second_system);
1210 stepping.continue_frame();
1211 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1212 }
1213
1214 #[test]
1215 fn clear_schedule() {
1216 let (schedule, _world) = setup();
1217
1218 let mut stepping = Stepping::new();
1219 stepping
1220 .add_schedule(TestSchedule)
1221 .enable()
1222 .never_run(TestSchedule, first_system)
1223 .never_run(TestSchedule, second_system)
1224 .continue_frame();
1225 assert_schedule_runs!(&schedule, &mut stepping,);
1226
1227 stepping.clear_schedule(TestSchedule);
1228 stepping.continue_frame();
1229 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1230 }
1231
1232 #[test]
1235 fn set_behavior_then_clear_schedule() {
1236 let (schedule, _world) = setup();
1237
1238 let mut stepping = Stepping::new();
1239 stepping
1240 .add_schedule(TestSchedule)
1241 .enable()
1242 .continue_frame();
1243 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1244
1245 stepping.never_run(TestSchedule, first_system);
1246 stepping.clear_schedule(TestSchedule);
1247 stepping.continue_frame();
1248 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1249 }
1250
1251 #[test]
1254 fn clear_schedule_then_set_behavior() {
1255 let (schedule, _world) = setup();
1256
1257 let mut stepping = Stepping::new();
1258 stepping
1259 .add_schedule(TestSchedule)
1260 .enable()
1261 .continue_frame();
1262 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1263
1264 stepping.clear_schedule(TestSchedule);
1265 stepping.never_run(TestSchedule, first_system);
1266 stepping.continue_frame();
1267 assert_schedule_runs!(&schedule, &mut stepping, second_system);
1268 }
1269
1270 #[test]
1274 fn multiple_calls_per_frame_continue() {
1275 let (schedule, _world) = setup();
1276
1277 let mut stepping = Stepping::new();
1278 stepping
1279 .add_schedule(TestSchedule)
1280 .enable()
1281 .always_run(TestSchedule, second_system)
1282 .continue_frame();
1283
1284 stepping.next_frame();
1287 assert_systems_run!(
1288 &schedule,
1289 stepping.skipped_systems(&schedule),
1290 first_system,
1291 second_system
1292 );
1293 assert_systems_run!(
1294 &schedule,
1295 stepping.skipped_systems(&schedule),
1296 second_system
1297 );
1298 }
1299 #[test]
1300 fn multiple_calls_per_frame_step() {
1301 let (schedule, _world) = setup();
1302
1303 let mut stepping = Stepping::new();
1304 stepping.add_schedule(TestSchedule).enable().step_frame();
1305
1306 stepping.next_frame();
1309 assert_systems_run!(&schedule, stepping.skipped_systems(&schedule), first_system);
1310 assert_systems_run!(&schedule, stepping.skipped_systems(&schedule),);
1311 }
1312
1313 #[test]
1314 fn step_duplicate_systems() {
1315 let mut world = World::new();
1316 let mut schedule = Schedule::new(TestSchedule);
1317 schedule.add_systems((first_system, first_system, second_system).chain());
1318 schedule.initialize(&mut world).unwrap();
1319
1320 let mut stepping = Stepping::new();
1321 stepping.add_schedule(TestSchedule).enable();
1322
1323 let system_names = vec!["first_system", "first_system", "second_system"];
1325 for system_index in 0..3 {
1328 let mut expected = FixedBitSet::with_capacity(3);
1331 expected.set_range(.., true);
1332 expected.set(system_index, false);
1333
1334 stepping.step_frame();
1336 stepping.next_frame();
1337 let skip_list = stepping
1338 .skipped_systems(&schedule)
1339 .expect("TestSchedule has been added to Stepping");
1340
1341 assert_skip_list_eq!(skip_list, expected, &system_names);
1342 }
1343 }
1344
1345 #[test]
1346 fn step_run_if_false() {
1347 let mut world = World::new();
1348 let mut schedule = Schedule::new(TestSchedule);
1349
1350 let first_system = move || panic!("first_system should not be run");
1357
1358 #[derive(Resource)]
1362 struct RunCount(usize);
1363 world.insert_resource(RunCount(0));
1364 let second_system = |mut run_count: ResMut<RunCount>| {
1365 println!("I have run!");
1366 run_count.0 += 1;
1367 };
1368
1369 schedule.add_systems((first_system.run_if(|| false), second_system).chain());
1372 schedule.initialize(&mut world).unwrap();
1373
1374 let mut stepping = Stepping::new();
1376 stepping.add_schedule(TestSchedule).enable();
1377 world.insert_resource(stepping);
1378
1379 let mut stepping = world.resource_mut::<Stepping>();
1383 stepping.step_frame();
1384 stepping.next_frame();
1385 schedule.run(&mut world);
1386 assert_eq!(
1387 world.resource::<RunCount>().0,
1388 0,
1389 "second_system should not have run"
1390 );
1391
1392 let mut stepping = world.resource_mut::<Stepping>();
1394 stepping.step_frame();
1395 stepping.next_frame();
1396 schedule.run(&mut world);
1397 assert_eq!(
1398 world.resource::<RunCount>().0,
1399 1,
1400 "second_system should have run"
1401 );
1402 }
1403
1404 #[test]
1405 fn remove_schedule() {
1406 let (schedule, _world) = setup();
1407 let mut stepping = Stepping::new();
1408 stepping.add_schedule(TestSchedule).enable();
1409
1410 assert_schedule_runs!(&schedule, &mut stepping,);
1412 assert!(!stepping.schedules().unwrap().is_empty());
1413
1414 stepping.remove_schedule(TestSchedule);
1416 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1417 assert!(stepping.schedules().unwrap().is_empty());
1418 }
1419
1420 #[test]
1422 fn schedules() {
1423 let mut world = World::new();
1424
1425 let mut schedule_a = Schedule::new(TestScheduleA);
1427 schedule_a.initialize(&mut world).unwrap();
1428 let mut schedule_b = Schedule::new(TestScheduleB);
1429 schedule_b.initialize(&mut world).unwrap();
1430 let mut schedule_c = Schedule::new(TestScheduleC);
1431 schedule_c.initialize(&mut world).unwrap();
1432 let mut schedule_d = Schedule::new(TestScheduleD);
1433 schedule_d.initialize(&mut world).unwrap();
1434
1435 let mut stepping = Stepping::new();
1437 stepping
1438 .add_schedule(TestScheduleA)
1439 .add_schedule(TestScheduleB)
1440 .add_schedule(TestScheduleC)
1441 .add_schedule(TestScheduleD)
1442 .enable()
1443 .next_frame();
1444
1445 assert!(stepping.schedules().is_err());
1446
1447 stepping.skipped_systems(&schedule_b);
1448 assert!(stepping.schedules().is_err());
1449 stepping.skipped_systems(&schedule_a);
1450 assert!(stepping.schedules().is_err());
1451 stepping.skipped_systems(&schedule_c);
1452 assert!(stepping.schedules().is_err());
1453
1454 stepping.skipped_systems(&schedule_d);
1457 assert!(stepping.schedules().is_ok());
1458
1459 assert_eq!(
1460 *stepping.schedules().unwrap(),
1461 vec![
1462 TestScheduleB.intern(),
1463 TestScheduleA.intern(),
1464 TestScheduleC.intern(),
1465 TestScheduleD.intern(),
1466 ]
1467 );
1468 }
1469
1470 #[test]
1471 fn verify_cursor() {
1472 fn cursor(schedule: &Schedule, index: usize) -> (InternedScheduleLabel, NodeId) {
1474 let node_id = schedule.executable().system_ids[index];
1475 (schedule.label(), node_id)
1476 }
1477
1478 let mut world = World::new();
1479
1480 let mut schedule_a = Schedule::new(TestScheduleA);
1482 schedule_a.add_systems((|| {}, || {}, || {}, || {}).chain());
1483 schedule_a.initialize(&mut world).unwrap();
1484 let mut schedule_b = Schedule::new(TestScheduleB);
1485 schedule_b.add_systems((|| {}, || {}, || {}, || {}).chain());
1486 schedule_b.initialize(&mut world).unwrap();
1487
1488 let mut stepping = Stepping::new();
1490 stepping
1491 .add_schedule(TestScheduleA)
1492 .add_schedule(TestScheduleB)
1493 .enable();
1494
1495 assert!(stepping.cursor().is_none());
1496
1497 let mut cursors = Vec::new();
1500 for _ in 0..9 {
1501 stepping.step_frame().next_frame();
1502 cursors.push(stepping.cursor());
1503 stepping.skipped_systems(&schedule_a);
1504 stepping.skipped_systems(&schedule_b);
1505 cursors.push(stepping.cursor());
1506 }
1507
1508 #[rustfmt::skip]
1509 assert_eq!(
1510 cursors,
1511 vec![
1512 None, Some(cursor(&schedule_a, 1)),
1514 Some(cursor(&schedule_a, 1)), Some(cursor(&schedule_a, 2)),
1515 Some(cursor(&schedule_a, 2)), Some(cursor(&schedule_a, 3)),
1516 Some(cursor(&schedule_a, 3)), Some(cursor(&schedule_b, 0)),
1517 Some(cursor(&schedule_b, 0)), Some(cursor(&schedule_b, 1)),
1518 Some(cursor(&schedule_b, 1)), Some(cursor(&schedule_b, 2)),
1519 Some(cursor(&schedule_b, 2)), Some(cursor(&schedule_b, 3)),
1520 Some(cursor(&schedule_b, 3)), None,
1521 Some(cursor(&schedule_a, 0)), Some(cursor(&schedule_a, 1)),
1522 ]
1523 );
1524
1525 stepping
1529 .disable()
1531 .enable()
1532 .set_breakpoint_node(TestScheduleA, NodeId::System(1))
1533 .always_run_node(TestScheduleA, NodeId::System(3))
1534 .never_run_node(TestScheduleB, NodeId::System(0));
1535
1536 let mut cursors = Vec::new();
1537 for _ in 0..9 {
1538 stepping.step_frame().next_frame();
1539 cursors.push(stepping.cursor());
1540 stepping.skipped_systems(&schedule_a);
1541 stepping.skipped_systems(&schedule_b);
1542 cursors.push(stepping.cursor());
1543 }
1544
1545 #[rustfmt::skip]
1546 assert_eq!(
1547 cursors,
1548 vec![
1549 Some(cursor(&schedule_a, 0)), Some(cursor(&schedule_a, 1)),
1551 Some(cursor(&schedule_a, 1)), Some(cursor(&schedule_a, 2)),
1552 Some(cursor(&schedule_a, 2)), Some(cursor(&schedule_b, 1)),
1553 Some(cursor(&schedule_b, 1)), Some(cursor(&schedule_b, 2)),
1554 Some(cursor(&schedule_b, 2)), Some(cursor(&schedule_b, 3)),
1555 Some(cursor(&schedule_b, 3)), None,
1556 Some(cursor(&schedule_a, 0)), Some(cursor(&schedule_a, 1)),
1557 Some(cursor(&schedule_a, 1)), Some(cursor(&schedule_a, 2)),
1558 Some(cursor(&schedule_a, 2)), Some(cursor(&schedule_b, 1)),
1559 ]
1560 );
1561 }
1562}