Files
bevy/examples/ecs/custom_executor.rs
Mike 984f7203e3 Make an unsafe accessor for SystemSchedule::systems (#23443)
# Objective

- #23414 made `SystemSchedule::systems` pub, but this can lead to
breaking invariants that `Schedule` expects. For example this allows
mutating the access which is used to prevent race conditions in the
multithreaded executor. This could also allow replacing systems, but
without initializing the access as the `Schedule` is meant to keep track
of which systems are unitialized.

## Solution

- Make the fields of `SystemWithAccess` private to make it harder to
modify the access. This is potentially a breaking change as
`SystemWithAccess` is pub, but the type is not exposed in our public
api's for `Schedule` in 0.18.
- Make an unsafe accessor for the `systems` field and make the field
private again.

## Testing

- Only checked that this compiles
2026-03-22 19:04:45 +00:00

57 lines
1.3 KiB
Rust

//! Demonstrates how to make a custom [`SystemExecutor`].
use bevy::{
ecs::{
error::{BevyError, ErrorContext},
schedule::{FixedBitSet, SystemExecutor, SystemSchedule},
},
prelude::*,
};
#[derive(Default)]
struct CustomExecutor;
impl SystemExecutor for CustomExecutor {
fn init(&mut self, _schedule: &SystemSchedule) {}
fn run(
&mut self,
schedule: &mut SystemSchedule,
world: &mut World,
_skip_systems: Option<&FixedBitSet>,
_error_handler: fn(BevyError, ErrorContext),
) {
#[expect(unsafe_code, reason = "CustomExecutor's require unsafe")]
// SAFETY: `run` is a trait method on `System`
for entry in unsafe { schedule.systems_mut().iter_mut() } {
let _ = entry.run((), world);
}
}
fn set_apply_final_deferred(&mut self, _value: bool) {}
}
#[derive(Resource, Default)]
struct Counter(u32);
fn increment(mut counter: ResMut<Counter>) {
counter.0 += 1;
}
fn print_counter(counter: Res<Counter>) {
println!("Counter: {}", counter.0);
}
fn main() {
let mut world = World::new();
world.init_resource::<Counter>();
let mut schedule = Schedule::default();
schedule.set_executor(CustomExecutor);
schedule.add_systems((increment, print_counter).chain());
for _ in 0..5 {
schedule.run(&mut world);
}
}