Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a method to run read-only systems using &World #8849

Merged
merged 4 commits into from Jun 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/bevy_ecs/src/lib.rs
Expand Up @@ -48,7 +48,7 @@ pub mod prelude {
adapter as system_adapter,
adapter::{dbg, error, ignore, info, unwrap, warn},
Commands, Deferred, In, IntoSystem, Local, NonSend, NonSendMut, ParallelCommands,
ParamSet, Query, Res, ResMut, Resource, System, SystemParamFunction,
ParamSet, Query, ReadOnlySystem, Res, ResMut, Resource, System, SystemParamFunction,
},
world::{FromWorld, World},
};
Expand Down
34 changes: 32 additions & 2 deletions crates/bevy_ecs/src/system/system.rs
Expand Up @@ -52,7 +52,12 @@ pub trait System: Send + Sync + 'static {
/// point before this one, with the same exact [`World`]. If `update_archetype_component_access`
/// panics (or otherwise does not return for any reason), this method must not be called.
unsafe fn run_unsafe(&mut self, input: Self::In, world: UnsafeWorldCell) -> Self::Out;

/// Runs the system with the given input in the world.
///
/// For [read-only](ReadOnlySystem) systems, see [`run_readonly`], which can be called using `&World`.
///
/// [`run_readonly`]: ReadOnlySystem::run_readonly
fn run(&mut self, input: Self::In, world: &mut World) -> Self::Out {
let world = world.as_unsafe_world_cell();
self.update_archetype_component_access(world);
Expand All @@ -61,29 +66,36 @@ pub trait System: Send + Sync + 'static {
// - `update_archetype_component_access` has been called.
unsafe { self.run_unsafe(input, world) }
}

/// Applies any [`Deferred`](crate::system::Deferred) system parameters (or other system buffers) of this system to the world.
///
/// This is where [`Commands`](crate::system::Commands) get applied.
fn apply_deferred(&mut self, world: &mut World);

/// Initialize the system.
fn initialize(&mut self, _world: &mut World);

/// Update the system's archetype component [`Access`].
///
/// ## Note for implementors
/// `world` may only be used to access metadata. This can be done in safe code
/// via functions such as [`UnsafeWorldCell::archetypes`].
fn update_archetype_component_access(&mut self, world: UnsafeWorldCell);

/// Checks any [`Tick`]s stored on this system and wraps their value if they get too old.
///
/// This method must be called periodically to ensure that change detection behaves correctly.
/// When using bevy's default configuration, this will be called for you as needed.
fn check_change_tick(&mut self, change_tick: Tick);

/// Returns the system's default [system sets](crate::schedule::SystemSet).
fn default_system_sets(&self) -> Vec<Box<dyn crate::schedule::SystemSet>> {
Vec::new()
}

/// Gets the tick indicating the last time this system ran.
fn get_last_run(&self) -> Tick;

/// Overwrites the tick indicating the last time this system ran.
///
/// # Warning
Expand All @@ -96,12 +108,30 @@ pub trait System: Send + Sync + 'static {
/// [`System`] types that do not modify the [`World`] when run.
/// This is implemented for any systems whose parameters all implement [`ReadOnlySystemParam`].
///
/// Note that systems which perform [deferred](System::apply_deferred) mutations (such as with [`Commands`])
/// may implement this trait.
///
/// [`ReadOnlySystemParam`]: crate::system::ReadOnlySystemParam
/// [`Commands`]: crate::system::Commands
///
/// # Safety
///
/// This must only be implemented for system types which do not mutate the `World`.
pub unsafe trait ReadOnlySystem: System {}
/// This must only be implemented for system types which do not mutate the `World`
/// when [`System::run_unsafe`] is called.
pub unsafe trait ReadOnlySystem: System {
/// Runs this system with the given input in the world.
///
/// Unlike [`System::run`], this can be called with a shared reference to the world,
/// since this system is known not to modify the world.
fn run_readonly(&mut self, input: Self::In, world: &World) -> Self::Out {
let world = world.as_unsafe_world_cell_readonly();
self.update_archetype_component_access(world);
// SAFETY:
// - We have read-only access to the entire world.
// - `update_archetype_component_access` has been called.
unsafe { self.run_unsafe(input, world) }
}
}

/// A convenience type alias for a boxed [`System`] trait object.
pub type BoxedSystem<In = (), Out = ()> = Box<dyn System<In = In, Out = Out>>;
Expand Down