bevy_ecs/schedule/executor/
mod.rs1mod multi_threaded;
2mod simple;
3mod single_threaded;
4
5pub use self::{
6 multi_threaded::{MainThreadExecutor, MultiThreadedExecutor},
7 simple::SimpleExecutor,
8 single_threaded::SingleThreadedExecutor,
9};
10
11use fixedbitset::FixedBitSet;
12
13use crate::{
14 schedule::{BoxedCondition, NodeId},
15 system::BoxedSystem,
16 world::World,
17};
18
19pub(super) trait SystemExecutor: Send + Sync {
21 fn kind(&self) -> ExecutorKind;
22 fn init(&mut self, schedule: &SystemSchedule);
23 fn run(
24 &mut self,
25 schedule: &mut SystemSchedule,
26 world: &mut World,
27 skip_systems: Option<&FixedBitSet>,
28 );
29 fn set_apply_final_deferred(&mut self, value: bool);
30}
31
32#[derive(PartialEq, Eq, Default, Debug, Copy, Clone)]
38pub enum ExecutorKind {
39 #[cfg_attr(any(target_arch = "wasm32", not(feature = "multi_threaded")), default)]
44 SingleThreaded,
45 Simple,
48 #[cfg_attr(all(not(target_arch = "wasm32"), feature = "multi_threaded"), default)]
50 MultiThreaded,
51}
52
53#[derive(Default)]
59pub struct SystemSchedule {
60 pub(super) system_ids: Vec<NodeId>,
62 pub(super) systems: Vec<BoxedSystem>,
64 pub(super) system_conditions: Vec<Vec<BoxedCondition>>,
66 pub(super) system_dependencies: Vec<usize>,
69 pub(super) system_dependents: Vec<Vec<usize>>,
72 pub(super) sets_with_conditions_of_systems: Vec<FixedBitSet>,
75 pub(super) set_ids: Vec<NodeId>,
77 pub(super) set_conditions: Vec<Vec<BoxedCondition>>,
79 pub(super) systems_in_sets_with_conditions: Vec<FixedBitSet>,
84}
85
86impl SystemSchedule {
87 pub const fn new() -> Self {
89 Self {
90 systems: Vec::new(),
91 system_conditions: Vec::new(),
92 set_conditions: Vec::new(),
93 system_ids: Vec::new(),
94 set_ids: Vec::new(),
95 system_dependencies: Vec::new(),
96 system_dependents: Vec::new(),
97 sets_with_conditions_of_systems: Vec::new(),
98 systems_in_sets_with_conditions: Vec::new(),
99 }
100 }
101}
102
103#[doc(alias = "apply_system_buffers")]
121#[allow(unused_variables)]
122pub fn apply_deferred(world: &mut World) {}
123
124pub(super) fn is_apply_deferred(system: &BoxedSystem) -> bool {
126 use crate::system::IntoSystem;
127 system.as_ref().type_id() == apply_deferred.system_type_id()
129}
130
131mod __rust_begin_short_backtrace {
140 use core::hint::black_box;
141
142 use crate::{
143 system::{ReadOnlySystem, System},
144 world::{unsafe_world_cell::UnsafeWorldCell, World},
145 };
146
147 #[inline(never)]
150 pub(super) unsafe fn run_unsafe(
151 system: &mut dyn System<In = (), Out = ()>,
152 world: UnsafeWorldCell,
153 ) {
154 system.run_unsafe((), world);
155 black_box(());
156 }
157
158 #[inline(never)]
161 pub(super) unsafe fn readonly_run_unsafe<O: 'static>(
162 system: &mut dyn ReadOnlySystem<In = (), Out = O>,
163 world: UnsafeWorldCell,
164 ) -> O {
165 black_box(system.run_unsafe((), world))
166 }
167
168 #[inline(never)]
169 pub(super) fn run(system: &mut dyn System<In = (), Out = ()>, world: &mut World) {
170 system.run((), world);
171 black_box(());
172 }
173
174 #[inline(never)]
175 pub(super) fn readonly_run<O: 'static>(
176 system: &mut dyn ReadOnlySystem<In = (), Out = O>,
177 world: &mut World,
178 ) -> O {
179 black_box(system.run((), world))
180 }
181}
182
183#[cfg(test)]
184mod tests {
185 use crate::{
186 self as bevy_ecs,
187 prelude::{IntoSystemConfigs, IntoSystemSetConfigs, Resource, Schedule, SystemSet},
188 schedule::ExecutorKind,
189 system::{Commands, Res, WithParamWarnPolicy},
190 world::World,
191 };
192
193 #[derive(Resource)]
194 struct R1;
195
196 #[derive(Resource)]
197 struct R2;
198
199 const EXECUTORS: [ExecutorKind; 3] = [
200 ExecutorKind::Simple,
201 ExecutorKind::SingleThreaded,
202 ExecutorKind::MultiThreaded,
203 ];
204
205 #[test]
206 fn invalid_system_param_skips() {
207 for executor in EXECUTORS {
208 invalid_system_param_skips_core(executor);
209 }
210 }
211
212 fn invalid_system_param_skips_core(executor: ExecutorKind) {
213 let mut world = World::new();
214 let mut schedule = Schedule::default();
215 schedule.set_executor_kind(executor);
216 schedule.add_systems(
217 (
218 (|mut commands: Commands| {
220 commands.insert_resource(R2);
221 })
222 .param_warn_once(),
223 )
224 .chain(),
225 );
226 schedule.run(&mut world);
227 assert!(world.get_resource::<R1>().is_none());
228 assert!(world.get_resource::<R2>().is_some());
229 }
230
231 #[derive(SystemSet, Hash, Debug, PartialEq, Eq, Clone)]
232 struct S1;
233
234 #[test]
235 fn invalid_condition_param_skips_system() {
236 for executor in EXECUTORS {
237 invalid_condition_param_skips_system_core(executor);
238 }
239 }
240
241 fn invalid_condition_param_skips_system_core(executor: ExecutorKind) {
242 let mut world = World::new();
243 let mut schedule = Schedule::default();
244 schedule.set_executor_kind(executor);
245 schedule.configure_sets(S1.run_if((|_: Res<R1>| true).param_warn_once()));
246 schedule.add_systems((
247 (|mut commands: Commands| {
249 commands.insert_resource(R1);
250 })
251 .param_warn_once()
252 .in_set(S1),
253 (|mut commands: Commands| {
255 commands.insert_resource(R2);
256 })
257 .param_warn_once()
258 .run_if((|_: Res<R2>| true).param_warn_once()),
259 ));
260 schedule.run(&mut world);
261 assert!(world.get_resource::<R1>().is_none());
262 assert!(world.get_resource::<R2>().is_none());
263 }
264}