bevy_ecs/schedule/executor/
simple.rs1#[cfg(feature = "trace")]
2use bevy_utils::tracing::info_span;
3use fixedbitset::FixedBitSet;
4use std::panic::AssertUnwindSafe;
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 #[cfg(feature = "trace")]
83 should_run_span.exit();
84
85 self.completed_systems.insert(system_index);
87
88 if !should_run {
89 continue;
90 }
91
92 let system = &mut schedule.systems[system_index];
93 if is_apply_deferred(system) {
94 continue;
95 }
96
97 let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
98 __rust_begin_short_backtrace::run(&mut **system, world);
99 }));
100 if let Err(payload) = res {
101 eprintln!("Encountered a panic in system `{}`!", &*system.name());
102 std::panic::resume_unwind(payload);
103 }
104 }
105
106 self.evaluated_sets.clear();
107 self.completed_systems.clear();
108 }
109
110 fn set_apply_final_deferred(&mut self, _: bool) {
111 }
113}
114
115impl SimpleExecutor {
116 pub const fn new() -> Self {
119 Self {
120 evaluated_sets: FixedBitSet::new(),
121 completed_systems: FixedBitSet::new(),
122 }
123 }
124}
125
126fn evaluate_and_fold_conditions(conditions: &mut [BoxedCondition], world: &mut World) -> bool {
127 #[allow(clippy::unnecessary_fold)]
129 conditions
130 .iter_mut()
131 .map(|condition| __rust_begin_short_backtrace::readonly_run(&mut **condition, world))
132 .fold(true, |acc, res| acc && res)
133}
134
135#[cfg(test)]
136#[test]
137fn skip_automatic_sync_points() {
138 use crate::prelude::*;
141 let mut sched = Schedule::default();
142 sched.set_executor_kind(ExecutorKind::Simple);
143 sched.add_systems((|_: Commands| (), || ()).chain());
144 let mut world = World::new();
145 sched.run(&mut world);
146}