bevy_ecs/schedule/executor/
single_threaded.rs1#[cfg(feature = "trace")]
2use bevy_utils::tracing::info_span;
3use core::panic::AssertUnwindSafe;
4use fixedbitset::FixedBitSet;
5
6use crate::{
7 schedule::{is_apply_deferred, BoxedCondition, ExecutorKind, SystemExecutor, SystemSchedule},
8 world::World,
9};
10
11use super::__rust_begin_short_backtrace;
12
13#[derive(Default)]
18pub struct SingleThreadedExecutor {
19 evaluated_sets: FixedBitSet,
21 completed_systems: FixedBitSet,
23 unapplied_systems: FixedBitSet,
25 apply_final_deferred: bool,
27}
28
29impl SystemExecutor for SingleThreadedExecutor {
30 fn kind(&self) -> ExecutorKind {
31 ExecutorKind::SingleThreaded
32 }
33
34 fn init(&mut self, schedule: &SystemSchedule) {
35 let sys_count = schedule.system_ids.len();
37 let set_count = schedule.set_ids.len();
38 self.evaluated_sets = FixedBitSet::with_capacity(set_count);
39 self.completed_systems = FixedBitSet::with_capacity(sys_count);
40 self.unapplied_systems = FixedBitSet::with_capacity(sys_count);
41 }
42
43 fn run(
44 &mut self,
45 schedule: &mut SystemSchedule,
46 world: &mut World,
47 _skip_systems: Option<&FixedBitSet>,
48 ) {
49 #[cfg(feature = "bevy_debug_stepping")]
52 if let Some(skipped_systems) = _skip_systems {
53 self.completed_systems |= skipped_systems;
55 }
56
57 for system_index in 0..schedule.systems.len() {
58 #[cfg(feature = "trace")]
59 let name = schedule.systems[system_index].name();
60 #[cfg(feature = "trace")]
61 let should_run_span = info_span!("check_conditions", name = &*name).entered();
62
63 let mut should_run = !self.completed_systems.contains(system_index);
64 for set_idx in schedule.sets_with_conditions_of_systems[system_index].ones() {
65 if self.evaluated_sets.contains(set_idx) {
66 continue;
67 }
68
69 let set_conditions_met =
71 evaluate_and_fold_conditions(&mut schedule.set_conditions[set_idx], world);
72
73 if !set_conditions_met {
74 self.completed_systems
75 .union_with(&schedule.systems_in_sets_with_conditions[set_idx]);
76 }
77
78 should_run &= set_conditions_met;
79 self.evaluated_sets.insert(set_idx);
80 }
81
82 let system_conditions_met =
84 evaluate_and_fold_conditions(&mut schedule.system_conditions[system_index], world);
85
86 should_run &= system_conditions_met;
87
88 let system = &mut schedule.systems[system_index];
89 if should_run {
90 let valid_params = system.validate_param(world);
91 should_run &= valid_params;
92 }
93
94 #[cfg(feature = "trace")]
95 should_run_span.exit();
96
97 self.completed_systems.insert(system_index);
99
100 if !should_run {
101 continue;
102 }
103
104 if is_apply_deferred(system) {
105 self.apply_deferred(schedule, world);
106 continue;
107 }
108
109 let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
110 if system.is_exclusive() {
111 __rust_begin_short_backtrace::run(&mut **system, world);
112 } else {
113 let world = world.as_unsafe_world_cell();
115 system.update_archetype_component_access(world);
116 unsafe { __rust_begin_short_backtrace::run_unsafe(&mut **system, world) };
119 }
120 }));
121 if let Err(payload) = res {
122 eprintln!("Encountered a panic in system `{}`!", &*system.name());
123 std::panic::resume_unwind(payload);
124 }
125 self.unapplied_systems.insert(system_index);
126 }
127
128 if self.apply_final_deferred {
129 self.apply_deferred(schedule, world);
130 }
131 self.evaluated_sets.clear();
132 self.completed_systems.clear();
133 }
134
135 fn set_apply_final_deferred(&mut self, apply_final_deferred: bool) {
136 self.apply_final_deferred = apply_final_deferred;
137 }
138}
139
140impl SingleThreadedExecutor {
141 pub const fn new() -> Self {
145 Self {
146 evaluated_sets: FixedBitSet::new(),
147 completed_systems: FixedBitSet::new(),
148 unapplied_systems: FixedBitSet::new(),
149 apply_final_deferred: true,
150 }
151 }
152
153 fn apply_deferred(&mut self, schedule: &mut SystemSchedule, world: &mut World) {
154 for system_index in self.unapplied_systems.ones() {
155 let system = &mut schedule.systems[system_index];
156 system.apply_deferred(world);
157 }
158
159 self.unapplied_systems.clear();
160 }
161}
162
163fn evaluate_and_fold_conditions(conditions: &mut [BoxedCondition], world: &mut World) -> bool {
164 #[allow(clippy::unnecessary_fold)]
166 conditions
167 .iter_mut()
168 .map(|condition| {
169 if !condition.validate_param(world) {
170 return false;
171 }
172 __rust_begin_short_backtrace::readonly_run(&mut **condition, world)
173 })
174 .fold(true, |acc, res| acc && res)
175}