bevy_ecs/schedule/executor/
single_threaded.rs1#[cfg(feature = "trace")]
2use bevy_utils::tracing::info_span;
3use fixedbitset::FixedBitSet;
4use std::panic::AssertUnwindSafe;
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 #[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 let system = &mut schedule.systems[system_index];
99 if is_apply_deferred(system) {
100 self.apply_deferred(schedule, world);
101 continue;
102 }
103
104 let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
105 if system.is_exclusive() {
106 __rust_begin_short_backtrace::run(&mut **system, world);
107 } else {
108 let world = world.as_unsafe_world_cell();
110 system.update_archetype_component_access(world);
111 unsafe { __rust_begin_short_backtrace::run_unsafe(&mut **system, world) };
114 }
115 }));
116 if let Err(payload) = res {
117 eprintln!("Encountered a panic in system `{}`!", &*system.name());
118 std::panic::resume_unwind(payload);
119 }
120 self.unapplied_systems.insert(system_index);
121 }
122
123 if self.apply_final_deferred {
124 self.apply_deferred(schedule, world);
125 }
126 self.evaluated_sets.clear();
127 self.completed_systems.clear();
128 }
129
130 fn set_apply_final_deferred(&mut self, apply_final_deferred: bool) {
131 self.apply_final_deferred = apply_final_deferred;
132 }
133}
134
135impl SingleThreadedExecutor {
136 pub const fn new() -> Self {
140 Self {
141 evaluated_sets: FixedBitSet::new(),
142 completed_systems: FixedBitSet::new(),
143 unapplied_systems: FixedBitSet::new(),
144 apply_final_deferred: true,
145 }
146 }
147
148 fn apply_deferred(&mut self, schedule: &mut SystemSchedule, world: &mut World) {
149 for system_index in self.unapplied_systems.ones() {
150 let system = &mut schedule.systems[system_index];
151 system.apply_deferred(world);
152 }
153
154 self.unapplied_systems.clear();
155 }
156}
157
158fn evaluate_and_fold_conditions(conditions: &mut [BoxedCondition], world: &mut World) -> bool {
159 #[allow(clippy::unnecessary_fold)]
161 conditions
162 .iter_mut()
163 .map(|condition| __rust_begin_short_backtrace::readonly_run(&mut **condition, world))
164 .fold(true, |acc, res| acc && res)
165}