1use fixedbitset::FixedBitSet;
2use std::any::TypeId;
3use std::collections::HashMap;
4
5use crate::{
6 schedule::{InternedScheduleLabel, NodeId, Schedule, ScheduleLabel},
7 system::{IntoSystem, ResMut, Resource},
8};
9use bevy_utils::{
10 tracing::{error, info, warn},
11 TypeIdMap,
12};
13use thiserror::Error;
14
15#[cfg(test)]
16use bevy_utils::tracing::debug;
17
18use crate as bevy_ecs;
19
20#[derive(Debug, Default, PartialEq, Eq, Copy, Clone)]
21enum Action {
22 #[default]
24 RunAll,
25
26 Waiting,
28
29 Continue,
33
34 Step,
36}
37
38#[derive(Debug, Copy, Clone)]
39enum SystemBehavior {
40 AlwaysRun,
42
43 NeverRun,
45
46 Break,
51
52 Continue,
56}
57
58#[derive(Debug, Default, Clone, Copy)]
60struct Cursor {
61 pub schedule: usize,
63 pub system: usize,
65}
66
67enum SystemIdentifier {
69 Type(TypeId),
70 Node(NodeId),
71}
72
73enum Update {
76 SetAction(Action),
78 AddSchedule(InternedScheduleLabel),
80 RemoveSchedule(InternedScheduleLabel),
82 ClearSchedule(InternedScheduleLabel),
84 SetBehavior(InternedScheduleLabel, SystemIdentifier, SystemBehavior),
86 ClearBehavior(InternedScheduleLabel, SystemIdentifier),
88}
89
90#[derive(Error, Debug)]
91#[error("not available until all configured schedules have been run; try again next frame")]
92pub struct NotReady;
93
94#[derive(Resource, Default)]
95pub struct Stepping {
97 schedule_states: HashMap<InternedScheduleLabel, ScheduleState>,
99
100 schedule_order: Vec<InternedScheduleLabel>,
102
103 cursor: Cursor,
105
106 previous_schedule: Option<usize>,
108
109 action: Action,
111
112 updates: Vec<Update>,
114}
115
116impl std::fmt::Debug for Stepping {
117 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118 write!(
119 f,
120 "Stepping {{ action: {:?}, schedules: {:?}, order: {:?}",
121 self.action,
122 self.schedule_states.keys(),
123 self.schedule_order
124 )?;
125 if self.action != Action::RunAll {
126 let Cursor { schedule, system } = self.cursor;
127 match self.schedule_order.get(schedule) {
128 Some(label) => write!(f, "cursor: {:?}[{}], ", label, system)?,
129 None => write!(f, "cursor: None, ")?,
130 };
131 }
132 write!(f, "}}")
133 }
134}
135
136impl Stepping {
137 pub fn new() -> Self {
139 Stepping::default()
140 }
141
142 pub fn begin_frame(stepping: Option<ResMut<Self>>) {
146 if let Some(mut stepping) = stepping {
147 stepping.next_frame();
148 }
149 }
150
151 pub fn schedules(&self) -> Result<&Vec<InternedScheduleLabel>, NotReady> {
154 if self.schedule_order.len() == self.schedule_states.len() {
155 Ok(&self.schedule_order)
156 } else {
157 Err(NotReady)
158 }
159 }
160
161 pub fn cursor(&self) -> Option<(InternedScheduleLabel, NodeId)> {
168 if self.action == Action::RunAll {
169 return None;
170 }
171 let label = match self.schedule_order.get(self.cursor.schedule) {
172 None => return None,
173 Some(label) => label,
174 };
175 let state = match self.schedule_states.get(label) {
176 None => return None,
177 Some(state) => state,
178 };
179 state
180 .node_ids
181 .get(self.cursor.system)
182 .map(|node_id| (*label, *node_id))
183 }
184
185 pub fn add_schedule(&mut self, schedule: impl ScheduleLabel) -> &mut Self {
187 self.updates.push(Update::AddSchedule(schedule.intern()));
188 self
189 }
190
191 pub fn remove_schedule(&mut self, schedule: impl ScheduleLabel) -> &mut Self {
196 self.updates.push(Update::RemoveSchedule(schedule.intern()));
197 self
198 }
199
200 pub fn clear_schedule(&mut self, schedule: impl ScheduleLabel) -> &mut Self {
202 self.updates.push(Update::ClearSchedule(schedule.intern()));
203 self
204 }
205
206 pub fn enable(&mut self) -> &mut Self {
208 #[cfg(feature = "bevy_debug_stepping")]
209 self.updates.push(Update::SetAction(Action::Waiting));
210 #[cfg(not(feature = "bevy_debug_stepping"))]
211 error!(
212 "Stepping cannot be enabled; \
213 bevy was compiled without the bevy_debug_stepping feature"
214 );
215 self
216 }
217
218 pub fn disable(&mut self) -> &mut Self {
220 self.updates.push(Update::SetAction(Action::RunAll));
221 self
222 }
223
224 pub fn is_enabled(&self) -> bool {
226 self.action != Action::RunAll
227 }
228
229 pub fn step_frame(&mut self) -> &mut Self {
233 self.updates.push(Update::SetAction(Action::Step));
234 self
235 }
236
237 pub fn continue_frame(&mut self) -> &mut Self {
242 self.updates.push(Update::SetAction(Action::Continue));
243 self
244 }
245
246 pub fn always_run<Marker>(
251 &mut self,
252 schedule: impl ScheduleLabel,
253 system: impl IntoSystem<(), (), Marker>,
254 ) -> &mut Self {
255 let type_id = system.system_type_id();
256 self.updates.push(Update::SetBehavior(
257 schedule.intern(),
258 SystemIdentifier::Type(type_id),
259 SystemBehavior::AlwaysRun,
260 ));
261
262 self
263 }
264
265 pub fn always_run_node(&mut self, schedule: impl ScheduleLabel, node: NodeId) -> &mut Self {
267 self.updates.push(Update::SetBehavior(
268 schedule.intern(),
269 SystemIdentifier::Node(node),
270 SystemBehavior::AlwaysRun,
271 ));
272 self
273 }
274
275 pub fn never_run<Marker>(
277 &mut self,
278 schedule: impl ScheduleLabel,
279 system: impl IntoSystem<(), (), Marker>,
280 ) -> &mut Self {
281 let type_id = system.system_type_id();
282 self.updates.push(Update::SetBehavior(
283 schedule.intern(),
284 SystemIdentifier::Type(type_id),
285 SystemBehavior::NeverRun,
286 ));
287
288 self
289 }
290
291 pub fn never_run_node(&mut self, schedule: impl ScheduleLabel, node: NodeId) -> &mut Self {
293 self.updates.push(Update::SetBehavior(
294 schedule.intern(),
295 SystemIdentifier::Node(node),
296 SystemBehavior::NeverRun,
297 ));
298 self
299 }
300
301 pub fn set_breakpoint<Marker>(
303 &mut self,
304 schedule: impl ScheduleLabel,
305 system: impl IntoSystem<(), (), Marker>,
306 ) -> &mut Self {
307 let type_id = system.system_type_id();
308 self.updates.push(Update::SetBehavior(
309 schedule.intern(),
310 SystemIdentifier::Type(type_id),
311 SystemBehavior::Break,
312 ));
313
314 self
315 }
316
317 pub fn set_breakpoint_node(&mut self, schedule: impl ScheduleLabel, node: NodeId) -> &mut Self {
319 self.updates.push(Update::SetBehavior(
320 schedule.intern(),
321 SystemIdentifier::Node(node),
322 SystemBehavior::Break,
323 ));
324 self
325 }
326
327 pub fn clear_breakpoint<Marker>(
329 &mut self,
330 schedule: impl ScheduleLabel,
331 system: impl IntoSystem<(), (), Marker>,
332 ) -> &mut Self {
333 self.clear_system(schedule, system);
334
335 self
336 }
337
338 pub fn clear_breakpoint_node(
340 &mut self,
341 schedule: impl ScheduleLabel,
342 node: NodeId,
343 ) -> &mut Self {
344 self.clear_node(schedule, node);
345 self
346 }
347
348 pub fn clear_system<Marker>(
350 &mut self,
351 schedule: impl ScheduleLabel,
352 system: impl IntoSystem<(), (), Marker>,
353 ) -> &mut Self {
354 let type_id = system.system_type_id();
355 self.updates.push(Update::ClearBehavior(
356 schedule.intern(),
357 SystemIdentifier::Type(type_id),
358 ));
359
360 self
361 }
362
363 pub fn clear_node(&mut self, schedule: impl ScheduleLabel, node: NodeId) -> &mut Self {
365 self.updates.push(Update::ClearBehavior(
366 schedule.intern(),
367 SystemIdentifier::Node(node),
368 ));
369 self
370 }
371
372 fn first_system_index_for_schedule(&self, index: usize) -> usize {
374 let label = match self.schedule_order.get(index) {
375 None => return 0,
376 Some(label) => label,
377 };
378 let state = match self.schedule_states.get(label) {
379 None => return 0,
380 Some(state) => state,
381 };
382 state.first.unwrap_or(0)
383 }
384
385 fn reset_cursor(&mut self) {
387 self.cursor = Cursor {
388 schedule: 0,
389 system: self.first_system_index_for_schedule(0),
390 };
391 }
392
393 fn next_frame(&mut self) {
395 if self.action != Action::RunAll {
398 self.action = Action::Waiting;
399 self.previous_schedule = None;
400
401 if self.cursor.schedule >= self.schedule_order.len() {
403 self.reset_cursor();
404 }
405 }
406
407 if self.updates.is_empty() {
408 return;
409 }
410
411 let mut reset_cursor = false;
412 for update in self.updates.drain(..) {
413 match update {
414 Update::SetAction(Action::RunAll) => {
415 self.action = Action::RunAll;
416 reset_cursor = true;
417 }
418 Update::SetAction(action) => {
419 match (self.action, action) {
424 (Action::RunAll, Action::RunAll)
427 | (Action::Waiting, Action::Waiting)
428 | (Action::Continue, Action::Continue)
429 | (Action::Step, Action::Step)
430 | (Action::Continue, Action::Waiting)
431 | (Action::Step, Action::Waiting) => continue,
432
433 (Action::RunAll, Action::Waiting) => info!("enabled stepping"),
435 (Action::RunAll, _) => {
436 warn!(
437 "stepping not enabled; call Stepping::enable() \
438 before step_frame() or continue_frame()"
439 );
440 continue;
441 }
442
443 (Action::Waiting, Action::RunAll) => info!("disabled stepping"),
445 (Action::Waiting, Action::Continue) => info!("continue frame"),
446 (Action::Waiting, Action::Step) => info!("step frame"),
447
448 (Action::Continue, Action::RunAll) => info!("disabled stepping"),
450 (Action::Continue, Action::Step) => {
451 warn!("ignoring step_frame(); already continuing next frame");
452 continue;
453 }
454
455 (Action::Step, Action::RunAll) => info!("disabled stepping"),
457 (Action::Step, Action::Continue) => {
458 warn!("ignoring continue_frame(); already stepping next frame");
459 continue;
460 }
461 }
462
463 self.action = action;
465 }
466 Update::AddSchedule(l) => {
467 self.schedule_states.insert(l, ScheduleState::default());
468 }
469 Update::RemoveSchedule(label) => {
470 self.schedule_states.remove(&label);
471 if let Some(index) = self.schedule_order.iter().position(|l| l == &label) {
472 self.schedule_order.remove(index);
473 }
474 reset_cursor = true;
475 }
476 Update::ClearSchedule(label) => match self.schedule_states.get_mut(&label) {
477 Some(state) => state.clear_behaviors(),
478 None => {
479 warn!(
480 "stepping is not enabled for schedule {:?}; \
481 use `.add_stepping({:?})` to enable stepping",
482 label, label
483 );
484 }
485 },
486 Update::SetBehavior(label, system, behavior) => {
487 match self.schedule_states.get_mut(&label) {
488 Some(state) => state.set_behavior(system, behavior),
489 None => {
490 warn!(
491 "stepping is not enabled for schedule {:?}; \
492 use `.add_stepping({:?})` to enable stepping",
493 label, label
494 );
495 }
496 }
497 }
498 Update::ClearBehavior(label, system) => {
499 match self.schedule_states.get_mut(&label) {
500 Some(state) => state.clear_behavior(system),
501 None => {
502 warn!(
503 "stepping is not enabled for schedule {:?}; \
504 use `.add_stepping({:?})` to enable stepping",
505 label, label
506 );
507 }
508 }
509 }
510 }
511 }
512
513 if reset_cursor {
514 self.reset_cursor();
515 }
516 }
517
518 pub fn skipped_systems(&mut self, schedule: &Schedule) -> Option<FixedBitSet> {
521 if self.action == Action::RunAll {
522 return None;
523 }
524
525 let label = schedule.label();
527 let state = self.schedule_states.get_mut(&label)?;
528
529 let index = self.schedule_order.iter().position(|l| *l == label);
538 let index = match (index, self.previous_schedule) {
539 (Some(index), _) => index,
540 (None, None) => {
541 self.schedule_order.insert(0, label);
542 0
543 }
544 (None, Some(last)) => {
545 self.schedule_order.insert(last + 1, label);
546 last + 1
547 }
548 };
549 self.previous_schedule = Some(index);
552
553 #[cfg(test)]
554 debug!(
555 "cursor {:?}, index {}, label {:?}",
556 self.cursor, index, label
557 );
558
559 let cursor = self.cursor;
563 let (skip_list, next_system) = if index == cursor.schedule {
564 let (skip_list, next_system) =
565 state.skipped_systems(schedule, cursor.system, self.action);
566
567 if self.action == Action::Step {
570 self.action = Action::Waiting;
571 }
572 (skip_list, next_system)
573 } else {
574 let (skip_list, _) = state.skipped_systems(schedule, 0, Action::Waiting);
577 (skip_list, Some(cursor.system))
578 };
579
580 match next_system {
587 Some(i) => self.cursor.system = i,
588 None => {
589 let index = cursor.schedule + 1;
590 self.cursor = Cursor {
591 schedule: index,
592 system: self.first_system_index_for_schedule(index),
593 };
594
595 #[cfg(test)]
596 debug!("advanced schedule index: {} -> {}", cursor.schedule, index);
597 }
598 }
599
600 Some(skip_list)
601 }
602}
603
604#[derive(Default)]
605struct ScheduleState {
606 behaviors: HashMap<NodeId, SystemBehavior>,
608
609 node_ids: Vec<NodeId>,
615
616 behavior_updates: TypeIdMap<Option<SystemBehavior>>,
619
620 first: Option<usize>,
622}
623
624impl ScheduleState {
625 fn set_behavior(&mut self, system: SystemIdentifier, behavior: SystemBehavior) {
627 self.first = None;
628 match system {
629 SystemIdentifier::Node(node_id) => {
630 self.behaviors.insert(node_id, behavior);
631 }
632 SystemIdentifier::Type(type_id) => {
636 self.behavior_updates.insert(type_id, Some(behavior));
637 }
638 }
639 }
640
641 fn clear_behavior(&mut self, system: SystemIdentifier) {
643 self.first = None;
644 match system {
645 SystemIdentifier::Node(node_id) => {
646 self.behaviors.remove(&node_id);
647 }
648 SystemIdentifier::Type(type_id) => {
650 self.behavior_updates.insert(type_id, None);
651 }
652 }
653 }
654
655 fn clear_behaviors(&mut self) {
657 self.behaviors.clear();
658 self.behavior_updates.clear();
659 self.first = None;
660 }
661
662 fn apply_behavior_updates(&mut self, schedule: &Schedule) {
665 for (node_id, system) in schedule.systems().unwrap() {
671 let behavior = self.behavior_updates.get(&system.type_id());
672 match behavior {
673 None => continue,
674 Some(None) => {
675 self.behaviors.remove(&node_id);
676 }
677 Some(Some(behavior)) => {
678 self.behaviors.insert(node_id, *behavior);
679 }
680 }
681 }
682 self.behavior_updates.clear();
683
684 #[cfg(test)]
685 debug!("apply_updates(): {:?}", self.behaviors);
686 }
687
688 fn skipped_systems(
689 &mut self,
690 schedule: &Schedule,
691 start: usize,
692 mut action: Action,
693 ) -> (FixedBitSet, Option<usize>) {
694 use std::cmp::Ordering;
695
696 if self.node_ids.len() != schedule.systems_len() {
699 self.node_ids.clone_from(&schedule.executable().system_ids);
700 }
701
702 if !self.behavior_updates.is_empty() {
706 self.apply_behavior_updates(schedule);
707 }
708
709 if self.first.is_none() {
711 for (i, (node_id, _)) in schedule.systems().unwrap().enumerate() {
712 match self.behaviors.get(&node_id) {
713 Some(SystemBehavior::AlwaysRun | SystemBehavior::NeverRun) => continue,
714 Some(_) | None => {
715 self.first = Some(i);
716 break;
717 }
718 }
719 }
720 }
721
722 let mut skip = FixedBitSet::with_capacity(schedule.systems_len());
723 let mut pos = start;
724
725 for (i, (node_id, _system)) in schedule.systems().unwrap().enumerate() {
726 let behavior = self
727 .behaviors
728 .get(&node_id)
729 .unwrap_or(&SystemBehavior::Continue);
730
731 #[cfg(test)]
732 debug!(
733 "skipped_systems(): systems[{}], pos {}, Action::{:?}, Behavior::{:?}, {}",
734 i,
735 pos,
736 action,
737 behavior,
738 _system.name()
739 );
740
741 match (action, behavior) {
742 (_, SystemBehavior::NeverRun) => {
747 skip.insert(i);
748 if i == pos {
749 pos += 1;
750 }
751 }
752 (_, SystemBehavior::AlwaysRun) => {
757 if i == pos {
758 pos += 1;
759 }
760 }
761 (Action::Waiting, _) => skip.insert(i),
764
765 (Action::Step, _) => match i.cmp(&pos) {
771 Ordering::Less => skip.insert(i),
772 Ordering::Equal => {
773 pos += 1;
774 action = Action::Waiting;
775 }
776 Ordering::Greater => unreachable!(),
777 },
778 (Action::Continue, SystemBehavior::Continue) => {
782 if i < start {
783 skip.insert(i);
784 }
785 }
786 (Action::Continue, SystemBehavior::Break) => {
795 if i != start {
796 skip.insert(i);
797
798 if i > start {
801 action = Action::Waiting;
802 }
803 }
804 }
805 (Action::RunAll, _) => unreachable!(),
808 }
809
810 if i == pos && action != Action::Waiting {
813 pos += 1;
814 }
815 }
816
817 if pos >= schedule.systems_len() {
820 (skip, None)
821 } else {
822 (skip, Some(pos))
823 }
824 }
825}
826
827#[cfg(all(test, feature = "bevy_debug_stepping"))]
828mod tests {
829 use super::*;
830 use crate::prelude::*;
831 use crate::schedule::ScheduleLabel;
832
833 pub use crate as bevy_ecs;
834
835 #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
836 struct TestSchedule;
837
838 #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
839 struct TestScheduleA;
840
841 #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
842 struct TestScheduleB;
843
844 #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
845 struct TestScheduleC;
846
847 #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
848 struct TestScheduleD;
849
850 fn first_system() {}
851 fn second_system() {}
852 fn third_system() {}
853
854 fn setup() -> (Schedule, World) {
855 let mut world = World::new();
856 let mut schedule = Schedule::new(TestSchedule);
857 schedule.add_systems((first_system, second_system).chain());
858 schedule.initialize(&mut world).unwrap();
859 (schedule, world)
860 }
861
862 macro_rules! assert_skip_list_eq {
865 ($actual:expr, $expected:expr, $system_names:expr) => {
866 let actual = $actual;
867 let expected = $expected;
868 let systems: &Vec<&str> = $system_names;
869
870 if (actual != expected) {
871 use std::fmt::Write as _;
872
873 let mut msg = format!(
876 "Schedule:\n {:9} {:16}{:6} {:6} {:6}\n",
877 "index", "name", "expect", "actual", "result"
878 );
879 for (i, name) in systems.iter().enumerate() {
880 let _ = write!(msg, " system[{:1}] {:16}", i, name);
881 match (expected.contains(i), actual.contains(i)) {
882 (true, true) => msg.push_str("skip skip pass\n"),
883 (true, false) => {
884 msg.push_str("skip run FAILED; system should not have run\n")
885 }
886 (false, true) => {
887 msg.push_str("run skip FAILED; system should have run\n")
888 }
889 (false, false) => msg.push_str("run run pass\n"),
890 }
891 }
892 assert_eq!(actual, expected, "{}", msg);
893 }
894 };
895 }
896
897 macro_rules! assert_systems_run {
900 ($schedule:expr, $skipped_systems:expr, $($system:expr),*) => {
901 let systems: Vec<(TypeId, std::borrow::Cow<'static, str>)> = $schedule.systems().unwrap()
904 .map(|(_, system)| {
905 (system.type_id(), system.name())
906 })
907 .collect();
908
909 let mut expected = FixedBitSet::with_capacity(systems.len());
911 $(
912 let sys = IntoSystem::into_system($system);
913 for (i, (type_id, _)) in systems.iter().enumerate() {
914 if sys.type_id() == *type_id {
915 expected.insert(i);
916 }
917 }
918 )*
919
920 expected.toggle_range(..);
922
923 let actual = match $skipped_systems {
925 None => FixedBitSet::with_capacity(systems.len()),
926 Some(b) => b,
927 };
928 let system_names: Vec<&str> = systems
929 .iter()
930 .map(|(_,n)| n.rsplit_once("::").unwrap().1)
931 .collect();
932
933 assert_skip_list_eq!(actual, expected, &system_names);
934 };
935 }
936
937 macro_rules! assert_schedule_runs {
944 ($schedule:expr, $stepping:expr, $($system:expr),*) => {
945 $stepping.next_frame();
948 assert_systems_run!($schedule, $stepping.skipped_systems($schedule), $($system),*);
949 };
950 }
951
952 #[test]
953 fn stepping_disabled() {
954 let (schedule, _world) = setup();
955
956 let mut stepping = Stepping::new();
957 stepping.add_schedule(TestSchedule).disable().next_frame();
958
959 assert!(stepping.skipped_systems(&schedule).is_none());
960 assert!(stepping.cursor().is_none());
961 }
962
963 #[test]
964 fn unknown_schedule() {
965 let (schedule, _world) = setup();
966
967 let mut stepping = Stepping::new();
968 stepping.enable().next_frame();
969
970 assert!(stepping.skipped_systems(&schedule).is_none());
971 }
972
973 #[test]
974 fn disabled_always_run() {
975 let (schedule, _world) = setup();
976
977 let mut stepping = Stepping::new();
978 stepping
979 .add_schedule(TestSchedule)
980 .disable()
981 .always_run(TestSchedule, first_system);
982
983 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
984 }
985
986 #[test]
987 fn waiting_always_run() {
988 let (schedule, _world) = setup();
989
990 let mut stepping = Stepping::new();
991 stepping
992 .add_schedule(TestSchedule)
993 .enable()
994 .always_run(TestSchedule, first_system);
995
996 assert_schedule_runs!(&schedule, &mut stepping, first_system);
997 }
998
999 #[test]
1000 fn step_always_run() {
1001 let (schedule, _world) = setup();
1002
1003 let mut stepping = Stepping::new();
1004 stepping
1005 .add_schedule(TestSchedule)
1006 .enable()
1007 .always_run(TestSchedule, first_system)
1008 .step_frame();
1009
1010 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1011 }
1012
1013 #[test]
1014 fn continue_always_run() {
1015 let (schedule, _world) = setup();
1016
1017 let mut stepping = Stepping::new();
1018 stepping
1019 .add_schedule(TestSchedule)
1020 .enable()
1021 .always_run(TestSchedule, first_system)
1022 .continue_frame();
1023
1024 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1025 }
1026
1027 #[test]
1028 fn disabled_never_run() {
1029 let (schedule, _world) = setup();
1030
1031 let mut stepping = Stepping::new();
1032 stepping
1033 .add_schedule(TestSchedule)
1034 .never_run(TestSchedule, first_system)
1035 .disable();
1036 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1037 }
1038
1039 #[test]
1040 fn waiting_never_run() {
1041 let (schedule, _world) = setup();
1042
1043 let mut stepping = Stepping::new();
1044 stepping
1045 .add_schedule(TestSchedule)
1046 .enable()
1047 .never_run(TestSchedule, first_system);
1048
1049 assert_schedule_runs!(&schedule, &mut stepping,);
1050 }
1051
1052 #[test]
1053 fn step_never_run() {
1054 let (schedule, _world) = setup();
1055
1056 let mut stepping = Stepping::new();
1057 stepping
1058 .add_schedule(TestSchedule)
1059 .enable()
1060 .never_run(TestSchedule, first_system)
1061 .step_frame();
1062
1063 assert_schedule_runs!(&schedule, &mut stepping, second_system);
1064 }
1065
1066 #[test]
1067 fn continue_never_run() {
1068 let (schedule, _world) = setup();
1069
1070 let mut stepping = Stepping::new();
1071 stepping
1072 .add_schedule(TestSchedule)
1073 .enable()
1074 .never_run(TestSchedule, first_system)
1075 .continue_frame();
1076
1077 assert_schedule_runs!(&schedule, &mut stepping, second_system);
1078 }
1079
1080 #[test]
1081 fn disabled_breakpoint() {
1082 let (schedule, _world) = setup();
1083
1084 let mut stepping = Stepping::new();
1085 stepping
1086 .add_schedule(TestSchedule)
1087 .disable()
1088 .set_breakpoint(TestSchedule, second_system);
1089
1090 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1091 }
1092
1093 #[test]
1094 fn waiting_breakpoint() {
1095 let (schedule, _world) = setup();
1096
1097 let mut stepping = Stepping::new();
1098 stepping
1099 .add_schedule(TestSchedule)
1100 .enable()
1101 .set_breakpoint(TestSchedule, second_system);
1102
1103 assert_schedule_runs!(&schedule, &mut stepping,);
1104 }
1105
1106 #[test]
1107 fn step_breakpoint() {
1108 let (schedule, _world) = setup();
1109
1110 let mut stepping = Stepping::new();
1111 stepping
1112 .add_schedule(TestSchedule)
1113 .enable()
1114 .set_breakpoint(TestSchedule, second_system)
1115 .step_frame();
1116
1117 assert_schedule_runs!(&schedule, &mut stepping, first_system);
1120 stepping.step_frame();
1121 assert_schedule_runs!(&schedule, &mut stepping, second_system);
1122
1123 stepping.step_frame();
1126 assert_schedule_runs!(&schedule, &mut stepping, first_system);
1127
1128 assert_schedule_runs!(&schedule, &mut stepping,);
1130 }
1131
1132 #[test]
1133 fn continue_breakpoint() {
1134 let (schedule, _world) = setup();
1135
1136 let mut stepping = Stepping::new();
1137 stepping
1138 .add_schedule(TestSchedule)
1139 .enable()
1140 .set_breakpoint(TestSchedule, second_system)
1141 .continue_frame();
1142
1143 assert_schedule_runs!(&schedule, &mut stepping, first_system);
1144 stepping.continue_frame();
1145 assert_schedule_runs!(&schedule, &mut stepping, second_system);
1146 stepping.continue_frame();
1147 assert_schedule_runs!(&schedule, &mut stepping, first_system);
1148 }
1149
1150 #[test]
1153 fn continue_step_continue_with_breakpoint() {
1154 let mut world = World::new();
1155 let mut schedule = Schedule::new(TestSchedule);
1156 schedule.add_systems((first_system, second_system, third_system).chain());
1157 schedule.initialize(&mut world).unwrap();
1158
1159 let mut stepping = Stepping::new();
1160 stepping
1161 .add_schedule(TestSchedule)
1162 .enable()
1163 .set_breakpoint(TestSchedule, second_system);
1164
1165 stepping.continue_frame();
1166 assert_schedule_runs!(&schedule, &mut stepping, first_system);
1167
1168 stepping.step_frame();
1169 assert_schedule_runs!(&schedule, &mut stepping, second_system);
1170
1171 stepping.continue_frame();
1172 assert_schedule_runs!(&schedule, &mut stepping, third_system);
1173 }
1174
1175 #[test]
1176 fn clear_breakpoint() {
1177 let (schedule, _world) = setup();
1178
1179 let mut stepping = Stepping::new();
1180 stepping
1181 .add_schedule(TestSchedule)
1182 .enable()
1183 .set_breakpoint(TestSchedule, second_system)
1184 .continue_frame();
1185
1186 assert_schedule_runs!(&schedule, &mut stepping, first_system);
1187 stepping.continue_frame();
1188 assert_schedule_runs!(&schedule, &mut stepping, second_system);
1189
1190 stepping.clear_breakpoint(TestSchedule, second_system);
1191 stepping.continue_frame();
1192 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1193 }
1194
1195 #[test]
1196 fn clear_system() {
1197 let (schedule, _world) = setup();
1198
1199 let mut stepping = Stepping::new();
1200 stepping
1201 .add_schedule(TestSchedule)
1202 .enable()
1203 .never_run(TestSchedule, second_system)
1204 .continue_frame();
1205 assert_schedule_runs!(&schedule, &mut stepping, first_system);
1206
1207 stepping.clear_system(TestSchedule, second_system);
1208 stepping.continue_frame();
1209 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1210 }
1211
1212 #[test]
1213 fn clear_schedule() {
1214 let (schedule, _world) = setup();
1215
1216 let mut stepping = Stepping::new();
1217 stepping
1218 .add_schedule(TestSchedule)
1219 .enable()
1220 .never_run(TestSchedule, first_system)
1221 .never_run(TestSchedule, second_system)
1222 .continue_frame();
1223 assert_schedule_runs!(&schedule, &mut stepping,);
1224
1225 stepping.clear_schedule(TestSchedule);
1226 stepping.continue_frame();
1227 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1228 }
1229
1230 #[test]
1233 fn set_behavior_then_clear_schedule() {
1234 let (schedule, _world) = setup();
1235
1236 let mut stepping = Stepping::new();
1237 stepping
1238 .add_schedule(TestSchedule)
1239 .enable()
1240 .continue_frame();
1241 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1242
1243 stepping.never_run(TestSchedule, first_system);
1244 stepping.clear_schedule(TestSchedule);
1245 stepping.continue_frame();
1246 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1247 }
1248
1249 #[test]
1252 fn clear_schedule_then_set_behavior() {
1253 let (schedule, _world) = setup();
1254
1255 let mut stepping = Stepping::new();
1256 stepping
1257 .add_schedule(TestSchedule)
1258 .enable()
1259 .continue_frame();
1260 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1261
1262 stepping.clear_schedule(TestSchedule);
1263 stepping.never_run(TestSchedule, first_system);
1264 stepping.continue_frame();
1265 assert_schedule_runs!(&schedule, &mut stepping, second_system);
1266 }
1267
1268 #[test]
1272 fn multiple_calls_per_frame_continue() {
1273 let (schedule, _world) = setup();
1274
1275 let mut stepping = Stepping::new();
1276 stepping
1277 .add_schedule(TestSchedule)
1278 .enable()
1279 .always_run(TestSchedule, second_system)
1280 .continue_frame();
1281
1282 stepping.next_frame();
1285 assert_systems_run!(
1286 &schedule,
1287 stepping.skipped_systems(&schedule),
1288 first_system,
1289 second_system
1290 );
1291 assert_systems_run!(
1292 &schedule,
1293 stepping.skipped_systems(&schedule),
1294 second_system
1295 );
1296 }
1297 #[test]
1298 fn multiple_calls_per_frame_step() {
1299 let (schedule, _world) = setup();
1300
1301 let mut stepping = Stepping::new();
1302 stepping.add_schedule(TestSchedule).enable().step_frame();
1303
1304 stepping.next_frame();
1307 assert_systems_run!(&schedule, stepping.skipped_systems(&schedule), first_system);
1308 assert_systems_run!(&schedule, stepping.skipped_systems(&schedule),);
1309 }
1310
1311 #[test]
1312 fn step_duplicate_systems() {
1313 let mut world = World::new();
1314 let mut schedule = Schedule::new(TestSchedule);
1315 schedule.add_systems((first_system, first_system, second_system).chain());
1316 schedule.initialize(&mut world).unwrap();
1317
1318 let mut stepping = Stepping::new();
1319 stepping.add_schedule(TestSchedule).enable();
1320
1321 let system_names = vec!["first_system", "first_system", "second_system"];
1323 for system_index in 0..3 {
1326 let mut expected = FixedBitSet::with_capacity(3);
1329 expected.set_range(.., true);
1330 expected.set(system_index, false);
1331
1332 stepping.step_frame();
1334 stepping.next_frame();
1335 let skip_list = stepping
1336 .skipped_systems(&schedule)
1337 .expect("TestSchedule has been added to Stepping");
1338
1339 assert_skip_list_eq!(skip_list, expected, &system_names);
1340 }
1341 }
1342
1343 #[test]
1344 fn step_run_if_false() {
1345 let mut world = World::new();
1346 let mut schedule = Schedule::new(TestSchedule);
1347
1348 let first_system = move || panic!("first_system should not be run");
1355
1356 #[derive(Resource)]
1360 struct RunCount(usize);
1361 world.insert_resource(RunCount(0));
1362 let second_system = |mut run_count: ResMut<RunCount>| {
1363 println!("I have run!");
1364 run_count.0 += 1;
1365 };
1366
1367 schedule.add_systems((first_system.run_if(|| false), second_system).chain());
1370 schedule.initialize(&mut world).unwrap();
1371
1372 let mut stepping = Stepping::new();
1374 stepping.add_schedule(TestSchedule).enable();
1375 world.insert_resource(stepping);
1376
1377 let mut stepping = world.resource_mut::<Stepping>();
1381 stepping.step_frame();
1382 stepping.next_frame();
1383 schedule.run(&mut world);
1384 assert_eq!(
1385 world.resource::<RunCount>().0,
1386 0,
1387 "second_system should not have run"
1388 );
1389
1390 let mut stepping = world.resource_mut::<Stepping>();
1392 stepping.step_frame();
1393 stepping.next_frame();
1394 schedule.run(&mut world);
1395 assert_eq!(
1396 world.resource::<RunCount>().0,
1397 1,
1398 "second_system should have run"
1399 );
1400 }
1401
1402 #[test]
1403 fn remove_schedule() {
1404 let (schedule, _world) = setup();
1405 let mut stepping = Stepping::new();
1406 stepping.add_schedule(TestSchedule).enable();
1407
1408 assert_schedule_runs!(&schedule, &mut stepping,);
1410 assert!(!stepping.schedules().unwrap().is_empty());
1411
1412 stepping.remove_schedule(TestSchedule);
1414 assert_schedule_runs!(&schedule, &mut stepping, first_system, second_system);
1415 assert!(stepping.schedules().unwrap().is_empty());
1416 }
1417
1418 #[test]
1420 fn schedules() {
1421 let mut world = World::new();
1422
1423 let mut schedule_a = Schedule::new(TestScheduleA);
1425 schedule_a.initialize(&mut world).unwrap();
1426 let mut schedule_b = Schedule::new(TestScheduleB);
1427 schedule_b.initialize(&mut world).unwrap();
1428 let mut schedule_c = Schedule::new(TestScheduleC);
1429 schedule_c.initialize(&mut world).unwrap();
1430 let mut schedule_d = Schedule::new(TestScheduleD);
1431 schedule_d.initialize(&mut world).unwrap();
1432
1433 let mut stepping = Stepping::new();
1435 stepping
1436 .add_schedule(TestScheduleA)
1437 .add_schedule(TestScheduleB)
1438 .add_schedule(TestScheduleC)
1439 .add_schedule(TestScheduleD)
1440 .enable()
1441 .next_frame();
1442
1443 assert!(stepping.schedules().is_err());
1444
1445 stepping.skipped_systems(&schedule_b);
1446 assert!(stepping.schedules().is_err());
1447 stepping.skipped_systems(&schedule_a);
1448 assert!(stepping.schedules().is_err());
1449 stepping.skipped_systems(&schedule_c);
1450 assert!(stepping.schedules().is_err());
1451
1452 stepping.skipped_systems(&schedule_d);
1455 assert!(stepping.schedules().is_ok());
1456
1457 assert_eq!(
1458 *stepping.schedules().unwrap(),
1459 vec![
1460 TestScheduleB.intern(),
1461 TestScheduleA.intern(),
1462 TestScheduleC.intern(),
1463 TestScheduleD.intern(),
1464 ]
1465 );
1466 }
1467
1468 #[test]
1469 fn verify_cursor() {
1470 fn cursor(schedule: &Schedule, index: usize) -> (InternedScheduleLabel, NodeId) {
1472 let node_id = schedule.executable().system_ids[index];
1473 (schedule.label(), node_id)
1474 }
1475
1476 let mut world = World::new();
1477
1478 let mut schedule_a = Schedule::new(TestScheduleA);
1480 schedule_a.add_systems((|| {}, || {}, || {}, || {}).chain());
1481 schedule_a.initialize(&mut world).unwrap();
1482 let mut schedule_b = Schedule::new(TestScheduleB);
1483 schedule_b.add_systems((|| {}, || {}, || {}, || {}).chain());
1484 schedule_b.initialize(&mut world).unwrap();
1485
1486 let mut stepping = Stepping::new();
1488 stepping
1489 .add_schedule(TestScheduleA)
1490 .add_schedule(TestScheduleB)
1491 .enable();
1492
1493 assert!(stepping.cursor().is_none());
1494
1495 let mut cursors = Vec::new();
1498 for _ in 0..9 {
1499 stepping.step_frame().next_frame();
1500 cursors.push(stepping.cursor());
1501 stepping.skipped_systems(&schedule_a);
1502 stepping.skipped_systems(&schedule_b);
1503 cursors.push(stepping.cursor());
1504 }
1505
1506 #[rustfmt::skip]
1507 assert_eq!(
1508 cursors,
1509 vec![
1510 None, Some(cursor(&schedule_a, 1)),
1512 Some(cursor(&schedule_a, 1)), Some(cursor(&schedule_a, 2)),
1513 Some(cursor(&schedule_a, 2)), Some(cursor(&schedule_a, 3)),
1514 Some(cursor(&schedule_a, 3)), Some(cursor(&schedule_b, 0)),
1515 Some(cursor(&schedule_b, 0)), Some(cursor(&schedule_b, 1)),
1516 Some(cursor(&schedule_b, 1)), Some(cursor(&schedule_b, 2)),
1517 Some(cursor(&schedule_b, 2)), Some(cursor(&schedule_b, 3)),
1518 Some(cursor(&schedule_b, 3)), None,
1519 Some(cursor(&schedule_a, 0)), Some(cursor(&schedule_a, 1)),
1520 ]
1521 );
1522
1523 stepping
1527 .disable()
1529 .enable()
1530 .set_breakpoint_node(TestScheduleA, NodeId::System(1))
1531 .always_run_node(TestScheduleA, NodeId::System(3))
1532 .never_run_node(TestScheduleB, NodeId::System(0));
1533
1534 let mut cursors = Vec::new();
1535 for _ in 0..9 {
1536 stepping.step_frame().next_frame();
1537 cursors.push(stepping.cursor());
1538 stepping.skipped_systems(&schedule_a);
1539 stepping.skipped_systems(&schedule_b);
1540 cursors.push(stepping.cursor());
1541 }
1542
1543 #[rustfmt::skip]
1544 assert_eq!(
1545 cursors,
1546 vec![
1547 Some(cursor(&schedule_a, 0)), Some(cursor(&schedule_a, 1)),
1549 Some(cursor(&schedule_a, 1)), Some(cursor(&schedule_a, 2)),
1550 Some(cursor(&schedule_a, 2)), Some(cursor(&schedule_b, 1)),
1551 Some(cursor(&schedule_b, 1)), Some(cursor(&schedule_b, 2)),
1552 Some(cursor(&schedule_b, 2)), Some(cursor(&schedule_b, 3)),
1553 Some(cursor(&schedule_b, 3)), None,
1554 Some(cursor(&schedule_a, 0)), Some(cursor(&schedule_a, 1)),
1555 Some(cursor(&schedule_a, 1)), Some(cursor(&schedule_a, 2)),
1556 Some(cursor(&schedule_a, 2)), Some(cursor(&schedule_b, 1)),
1557 ]
1558 );
1559 }
1560}