bevy_ecs/schedule/executor/
simple.rs1#[cfg(feature = "trace")]
2use bevy_utils::tracing::info_span;
3use core::panic::AssertUnwindSafe;
4use fixedbitset::FixedBitSet;
5
6use crate::{
7 schedule::{
8 executor::is_apply_deferred, BoxedCondition, ExecutorKind, SystemExecutor, SystemSchedule,
9 },
10 world::World,
11};
12
13use super::__rust_begin_short_backtrace;
14
15#[derive(Default)]
18pub struct SimpleExecutor {
19 evaluated_sets: FixedBitSet,
21 completed_systems: FixedBitSet,
23}
24
25impl SystemExecutor for SimpleExecutor {
26 fn kind(&self) -> ExecutorKind {
27 ExecutorKind::Simple
28 }
29
30 fn init(&mut self, schedule: &SystemSchedule) {
31 let sys_count = schedule.system_ids.len();
32 let set_count = schedule.set_ids.len();
33 self.evaluated_sets = FixedBitSet::with_capacity(set_count);
34 self.completed_systems = FixedBitSet::with_capacity(sys_count);
35 }
36
37 fn run(
38 &mut self,
39 schedule: &mut SystemSchedule,
40 world: &mut World,
41 _skip_systems: Option<&FixedBitSet>,
42 ) {
43 #[cfg(feature = "bevy_debug_stepping")]
46 if let Some(skipped_systems) = _skip_systems {
47 self.completed_systems |= skipped_systems;
49 }
50
51 for system_index in 0..schedule.systems.len() {
52 #[cfg(feature = "trace")]
53 let name = schedule.systems[system_index].name();
54 #[cfg(feature = "trace")]
55 let should_run_span = info_span!("check_conditions", name = &*name).entered();
56
57 let mut should_run = !self.completed_systems.contains(system_index);
58 for set_idx in schedule.sets_with_conditions_of_systems[system_index].ones() {
59 if self.evaluated_sets.contains(set_idx) {
60 continue;
61 }
62
63 let set_conditions_met =
65 evaluate_and_fold_conditions(&mut schedule.set_conditions[set_idx], world);
66
67 if !set_conditions_met {
68 self.completed_systems
69 .union_with(&schedule.systems_in_sets_with_conditions[set_idx]);
70 }
71
72 should_run &= set_conditions_met;
73 self.evaluated_sets.insert(set_idx);
74 }
75
76 let system_conditions_met =
78 evaluate_and_fold_conditions(&mut schedule.system_conditions[system_index], world);
79
80 should_run &= system_conditions_met;
81
82 let system = &mut schedule.systems[system_index];
83 if should_run {
84 let valid_params = system.validate_param(world);
85 should_run &= valid_params;
86 }
87
88 #[cfg(feature = "trace")]
89 should_run_span.exit();
90
91 self.completed_systems.insert(system_index);
93
94 if !should_run {
95 continue;
96 }
97
98 if is_apply_deferred(system) {
99 continue;
100 }
101
102 let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
103 __rust_begin_short_backtrace::run(&mut **system, world);
104 }));
105 if let Err(payload) = res {
106 eprintln!("Encountered a panic in system `{}`!", &*system.name());
107 std::panic::resume_unwind(payload);
108 }
109 }
110
111 self.evaluated_sets.clear();
112 self.completed_systems.clear();
113 }
114
115 fn set_apply_final_deferred(&mut self, _: bool) {
116 }
118}
119
120impl SimpleExecutor {
121 pub const fn new() -> Self {
124 Self {
125 evaluated_sets: FixedBitSet::new(),
126 completed_systems: FixedBitSet::new(),
127 }
128 }
129}
130
131fn evaluate_and_fold_conditions(conditions: &mut [BoxedCondition], world: &mut World) -> bool {
132 #[allow(clippy::unnecessary_fold)]
134 conditions
135 .iter_mut()
136 .map(|condition| {
137 if !condition.validate_param(world) {
138 return false;
139 }
140 __rust_begin_short_backtrace::readonly_run(&mut **condition, world)
141 })
142 .fold(true, |acc, res| acc && res)
143}
144
145#[cfg(test)]
146#[test]
147fn skip_automatic_sync_points() {
148 use crate::prelude::*;
151 let mut sched = Schedule::default();
152 sched.set_executor_kind(ExecutorKind::Simple);
153 sched.add_systems((|_: Commands| (), || ()).chain());
154 let mut world = World::new();
155 sched.run(&mut world);
156}