diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index a2cbbea764c37..53731b6cfae86 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -4,7 +4,7 @@ use core::{marker::PhantomData, panic::Location}; use super::{ Deferred, IntoObserverSystem, IntoSystem, RegisterSystem, Resource, RunSystemCachedWith, - UnregisterSystem, + UnregisterSystem, UnregisterSystemCached, }; use crate::{ self as bevy_ecs, @@ -15,7 +15,7 @@ use crate::{ event::{Event, SendEvent}, observer::{Observer, TriggerEvent, TriggerTargets}, schedule::ScheduleLabel, - system::{input::SystemInput, RunSystemWithInput, SystemId}, + system::{input::SystemInput, RunSystemWith, SystemId}, world::{ command_queue::RawCommandQueue, unsafe_world_cell::UnsafeWorldCell, Command, CommandQueue, EntityWorldMut, FromWorld, SpawnBatchIter, World, @@ -810,25 +810,25 @@ impl<'w, 's> Commands<'w, 's> { /// /// There is no way to get the output of a system when run as a command, because the /// execution of the system happens later. To get the output of a system, use - /// [`World::run_system`] or [`World::run_system_with_input`] instead of running the system as a command. + /// [`World::run_system`] or [`World::run_system_with`] instead of running the system as a command. pub fn run_system(&mut self, id: SystemId) { - self.run_system_with_input(id, ()); + self.run_system_with(id, ()); } /// Runs the system corresponding to the given [`SystemId`]. /// Systems are ran in an exclusive and single threaded way. /// Running slow systems can become a bottleneck. /// - /// Calls [`World::run_system_with_input`](World::run_system_with_input). + /// Calls [`World::run_system_with`](World::run_system_with). /// /// There is no way to get the output of a system when run as a command, because the /// execution of the system happens later. To get the output of a system, use - /// [`World::run_system`] or [`World::run_system_with_input`] instead of running the system as a command. - pub fn run_system_with_input(&mut self, id: SystemId, input: I::Inner<'static>) + /// [`World::run_system`] or [`World::run_system_with`] instead of running the system as a command. + pub fn run_system_with(&mut self, id: SystemId, input: I::Inner<'static>) where I: SystemInput: Send> + 'static, { - self.queue(RunSystemWithInput::new_with_input(id, input)); + self.queue(RunSystemWith::new_with_input(id, input)); } /// Registers a system and returns a [`SystemId`] so it can later be called by [`World::run_system`]. @@ -904,6 +904,21 @@ impl<'w, 's> Commands<'w, 's> { self.queue(UnregisterSystem::new(system_id)); } + /// Removes a system previously registered with [`World::register_system_cached`]. + /// + /// See [`World::unregister_system_cached`] for more information. + pub fn unregister_system_cached< + I: SystemInput + Send + 'static, + O: 'static, + M: 'static, + S: IntoSystem + Send + 'static, + >( + &mut self, + system: S, + ) { + self.queue(UnregisterSystemCached::new(system)); + } + /// Similar to [`Self::run_system`], but caching the [`SystemId`] in a /// [`CachedSystemId`](crate::system::CachedSystemId) resource. /// @@ -915,7 +930,7 @@ impl<'w, 's> Commands<'w, 's> { self.run_system_cached_with(system, ()); } - /// Similar to [`Self::run_system_with_input`], but caching the [`SystemId`] in a + /// Similar to [`Self::run_system_with`], but caching the [`SystemId`] in a /// [`CachedSystemId`](crate::system::CachedSystemId) resource. /// /// See [`World::register_system_cached`] for more information. @@ -2617,6 +2632,25 @@ mod tests { assert!(world.get::(e).is_some()); } + #[test] + fn unregister_system_cached_commands() { + let mut world = World::default(); + let mut queue = CommandQueue::default(); + + fn nothing() {} + + assert!(world.iter_resources().count() == 0); + let id = world.register_system_cached(nothing); + assert!(world.iter_resources().count() == 1); + assert!(world.get_entity(id.entity).is_ok()); + + let mut commands = Commands::new(&mut queue, &world); + commands.unregister_system_cached(nothing); + queue.apply(&mut world); + assert!(world.iter_resources().count() == 0); + assert!(world.get_entity(id.entity).is_err()); + } + fn is_send() {} fn is_sync() {} diff --git a/crates/bevy_ecs/src/system/system.rs b/crates/bevy_ecs/src/system/system.rs index c1c628cb2e1aa..2103119b5ff63 100644 --- a/crates/bevy_ecs/src/system/system.rs +++ b/crates/bevy_ecs/src/system/system.rs @@ -322,14 +322,14 @@ pub trait RunSystemOnce: Sized { where T: IntoSystem<(), Out, Marker>, { - self.run_system_once_with((), system) + self.run_system_once_with(system, ()) } /// Tries to run a system with given input and apply deferred parameters. fn run_system_once_with( self, - input: SystemIn<'_, T::System>, system: T, + input: SystemIn<'_, T::System>, ) -> Result where T: IntoSystem, @@ -339,8 +339,8 @@ pub trait RunSystemOnce: Sized { impl RunSystemOnce for &mut World { fn run_system_once_with( self, - input: SystemIn<'_, T::System>, system: T, + input: SystemIn<'_, T::System>, ) -> Result where T: IntoSystem, @@ -392,7 +392,7 @@ mod tests { } let mut world = World::default(); - let n = world.run_system_once_with(1, system).unwrap(); + let n = world.run_system_once_with(system, 1).unwrap(); assert_eq!(n, 2); assert_eq!(world.resource::().0, 1); } diff --git a/crates/bevy_ecs/src/system/system_registry.rs b/crates/bevy_ecs/src/system/system_registry.rs index f00740a1f7942..5d101d43ebad5 100644 --- a/crates/bevy_ecs/src/system/system_registry.rs +++ b/crates/bevy_ecs/src/system/system_registry.rs @@ -201,7 +201,7 @@ impl World { /// This is different from [`RunSystemOnce::run_system_once`](crate::system::RunSystemOnce::run_system_once), /// because it keeps local state between calls and change detection works correctly. /// - /// In order to run a chained system with an input, use [`World::run_system_with_input`] instead. + /// In order to run a chained system with an input, use [`World::run_system_with`] instead. /// /// # Limitations /// @@ -286,7 +286,7 @@ impl World { &mut self, id: SystemId<(), O>, ) -> Result> { - self.run_system_with_input(id, ()) + self.run_system_with(id, ()) } /// Run a stored chained system by its [`SystemId`], providing an input value. @@ -309,13 +309,13 @@ impl World { /// let mut world = World::default(); /// let counter_one = world.register_system(increment); /// let counter_two = world.register_system(increment); - /// assert_eq!(world.run_system_with_input(counter_one, 1).unwrap(), 1); - /// assert_eq!(world.run_system_with_input(counter_one, 20).unwrap(), 21); - /// assert_eq!(world.run_system_with_input(counter_two, 30).unwrap(), 30); + /// assert_eq!(world.run_system_with(counter_one, 1).unwrap(), 1); + /// assert_eq!(world.run_system_with(counter_one, 20).unwrap(), 21); + /// assert_eq!(world.run_system_with(counter_two, 30).unwrap(), 30); /// ``` /// /// See [`World::run_system`] for more examples. - pub fn run_system_with_input( + pub fn run_system_with( &mut self, id: SystemId, input: I::Inner<'_>, @@ -451,11 +451,11 @@ impl World { S: IntoSystem + 'static, { let id = self.register_system_cached(system); - self.run_system_with_input(id, input) + self.run_system_with(id, input) } } -/// The [`Command`] type for [`World::run_system`] or [`World::run_system_with_input`]. +/// The [`Command`] type for [`World::run_system`] or [`World::run_system_with`]. /// /// This command runs systems in an exclusive and single threaded way. /// Running slow systems can become a bottleneck. @@ -465,9 +465,9 @@ impl World { /// /// There is no way to get the output of a system when run as a command, because the /// execution of the system happens later. To get the output of a system, use -/// [`World::run_system`] or [`World::run_system_with_input`] instead of running the system as a command. +/// [`World::run_system`] or [`World::run_system_with`] instead of running the system as a command. #[derive(Debug, Clone)] -pub struct RunSystemWithInput { +pub struct RunSystemWith { system_id: SystemId, input: I::Inner<'static>, } @@ -478,12 +478,12 @@ pub struct RunSystemWithInput { /// Running slow systems can become a bottleneck. /// /// If the system needs an [`In<_>`](crate::system::In) input value to run, use the -/// [`RunSystemWithInput`] type instead. +/// [`RunSystemWith`] type instead. /// /// There is no way to get the output of a system when run as a command, because the /// execution of the system happens later. To get the output of a system, use -/// [`World::run_system`] or [`World::run_system_with_input`] instead of running the system as a command. -pub type RunSystem = RunSystemWithInput<()>; +/// [`World::run_system`] or [`World::run_system_with`] instead of running the system as a command. +pub type RunSystem = RunSystemWith<()>; impl RunSystem { /// Creates a new [`Command`] struct, which can be added to [`Commands`](crate::system::Commands). @@ -492,7 +492,7 @@ impl RunSystem { } } -impl RunSystemWithInput { +impl RunSystemWith { /// Creates a new [`Command`] struct, which can be added to [`Commands`](crate::system::Commands) /// in order to run the specified system with the provided [`In<_>`](crate::system::In) input value. pub fn new_with_input(system_id: SystemId, input: I::Inner<'static>) -> Self { @@ -500,13 +500,13 @@ impl RunSystemWithInput { } } -impl Command for RunSystemWithInput +impl Command for RunSystemWith where I: SystemInput: Send> + 'static, { #[inline] fn apply(self, world: &mut World) { - _ = world.run_system_with_input(self.system_id, self.input); + _ = world.run_system_with(self.system_id, self.input); } } @@ -570,6 +570,42 @@ where } } +/// The [`Command`] type for unregistering one-shot systems from [`Commands`](crate::system::Commands). +pub struct UnregisterSystemCached +where + I: SystemInput + 'static, + S: IntoSystem + Send + 'static, +{ + system: S, + _phantom: PhantomData (I, O, M)>, +} + +impl UnregisterSystemCached +where + I: SystemInput + 'static, + S: IntoSystem + Send + 'static, +{ + /// Creates a new [`Command`] struct, which can be added to [`Commands`](crate::system::Commands). + pub fn new(system: S) -> Self { + Self { + system, + _phantom: PhantomData, + } + } +} + +impl Command for UnregisterSystemCached +where + I: SystemInput + 'static, + O: 'static, + M: 'static, + S: IntoSystem + Send + 'static, +{ + fn apply(self, world: &mut World) { + let _ = world.unregister_system_cached(self.system); + } +} + /// The [`Command`] type for running a cached one-shot system from /// [`Commands`](crate::system::Commands). /// @@ -730,22 +766,22 @@ mod tests { assert_eq!(*world.resource::(), Counter(1)); world - .run_system_with_input(id, NonCopy(1)) + .run_system_with(id, NonCopy(1)) .expect("system runs successfully"); assert_eq!(*world.resource::(), Counter(2)); world - .run_system_with_input(id, NonCopy(1)) + .run_system_with(id, NonCopy(1)) .expect("system runs successfully"); assert_eq!(*world.resource::(), Counter(3)); world - .run_system_with_input(id, NonCopy(20)) + .run_system_with(id, NonCopy(20)) .expect("system runs successfully"); assert_eq!(*world.resource::(), Counter(23)); world - .run_system_with_input(id, NonCopy(1)) + .run_system_with(id, NonCopy(1)) .expect("system runs successfully"); assert_eq!(*world.resource::(), Counter(24)); } @@ -828,7 +864,7 @@ mod tests { fn nested(query: Query<&Callback>, mut commands: Commands) { for callback in query.iter() { - commands.run_system_with_input(callback.0, callback.1); + commands.run_system_with(callback.0, callback.1); } } @@ -922,7 +958,7 @@ mod tests { world.insert_resource(Counter(0)); let id = world.register_system(with_ref); - world.run_system_with_input(id, &2).unwrap(); + world.run_system_with(id, &2).unwrap(); assert_eq!(*world.resource::(), Counter(2)); } @@ -944,15 +980,11 @@ mod tests { let post_system = world.register_system(post); let mut event = MyEvent { cancelled: false }; - world - .run_system_with_input(post_system, &mut event) - .unwrap(); + world.run_system_with(post_system, &mut event).unwrap(); assert!(!event.cancelled); world.resource_mut::().0 = 1; - world - .run_system_with_input(post_system, &mut event) - .unwrap(); + world.run_system_with(post_system, &mut event).unwrap(); assert!(event.cancelled); } diff --git a/crates/bevy_remote/src/lib.rs b/crates/bevy_remote/src/lib.rs index 576ee7dbf18bc..103afb0327174 100644 --- a/crates/bevy_remote/src/lib.rs +++ b/crates/bevy_remote/src/lib.rs @@ -800,7 +800,7 @@ fn process_remote_requests(world: &mut World) { match handler { RemoteMethodSystemId::Instant(id) => { - let result = match world.run_system_with_input(id, message.params) { + let result = match world.run_system_with(id, message.params) { Ok(result) => result, Err(error) => { let _ = message.sender.force_send(Err(BrpError { @@ -850,7 +850,7 @@ fn process_single_ongoing_watching_request( system_id: &RemoteWatchingMethodSystemId, ) -> BrpResult> { world - .run_system_with_input(*system_id, message.params.clone()) + .run_system_with(*system_id, message.params.clone()) .map_err(|error| BrpError { code: error_codes::INTERNAL_ERROR, message: format!("Failed to run method handler: {error}"), diff --git a/crates/bevy_ui/src/layout/mod.rs b/crates/bevy_ui/src/layout/mod.rs index 15e15059852c0..a9d9a768a36c7 100644 --- a/crates/bevy_ui/src/layout/mod.rs +++ b/crates/bevy_ui/src/layout/mod.rs @@ -944,7 +944,7 @@ mod tests { new_pos: Vec2, expected_camera_entity: &Entity, ) { - world.run_system_once_with(new_pos, move_ui_node).unwrap(); + world.run_system_once_with(move_ui_node, new_pos).unwrap(); ui_schedule.run(world); let (ui_node_entity, TargetCamera(target_camera_entity)) = world .query_filtered::<(Entity, &TargetCamera), With>() @@ -1234,11 +1234,11 @@ mod tests { } let _ = world.run_system_once_with( + test_system, TestSystemParam { camera_entity, root_node_entity, }, - test_system, ); let ui_surface = world.resource::();