mirror of
https://github.com/bevyengine/bevy.git
synced 2026-05-06 06:06:42 -04:00
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
This commit is contained in:
@@ -75,7 +75,7 @@ pub struct SystemSchedule {
|
||||
/// List of system node ids.
|
||||
pub(super) system_ids: Vec<SystemKey>,
|
||||
/// Indexed by system node id.
|
||||
pub systems: Vec<SystemWithAccess>,
|
||||
pub(super) systems: Vec<SystemWithAccess>,
|
||||
/// Indexed by system node id.
|
||||
pub(super) system_conditions: Vec<Vec<ConditionWithAccess>>,
|
||||
/// Indexed by system node id.
|
||||
@@ -121,6 +121,15 @@ impl SystemSchedule {
|
||||
systems_in_sets_with_conditions: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Accessor to allow running systems from a custom executor
|
||||
///
|
||||
/// # Safety
|
||||
/// - The only allowed mutations are from calling methods on the [`System`] trait. Replacing
|
||||
/// systems in the returned [`Vec`] should be considered undefined behavior.
|
||||
pub unsafe fn systems_mut(&mut self) -> &mut Vec<SystemWithAccess> {
|
||||
&mut self.systems
|
||||
}
|
||||
}
|
||||
|
||||
/// A special [`System`] that instructs the executor to call
|
||||
|
||||
@@ -35,10 +35,10 @@ pub(crate) struct SystemNode {
|
||||
/// A [`ScheduleSystem`] stored alongside the access returned from [`System::initialize`].
|
||||
pub struct SystemWithAccess {
|
||||
/// The system itself.
|
||||
pub system: ScheduleSystem,
|
||||
pub(crate) system: ScheduleSystem,
|
||||
/// The access returned by [`System::initialize`].
|
||||
/// This will be empty if the system has not been initialized yet.
|
||||
pub access: FilteredAccessSet,
|
||||
pub(crate) access: FilteredAccessSet,
|
||||
}
|
||||
|
||||
impl SystemWithAccess {
|
||||
|
||||
@@ -21,8 +21,10 @@ impl SystemExecutor for CustomExecutor {
|
||||
_skip_systems: Option<&FixedBitSet>,
|
||||
_error_handler: fn(BevyError, ErrorContext),
|
||||
) {
|
||||
for entry in schedule.systems.iter_mut() {
|
||||
let _ = entry.system.run((), world);
|
||||
#[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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user