Skip to content

Commit 854934c

Browse files
pematternPaul Mattern
andauthored
one shot system cleanup (#16516)
# Objective - Fixes #16497 - This is my first PR, so I'm still learning to contribute to the project ## Solution - Added struct `UnregisterSystemCached` and function `unregister_system_cached` - renamed `World::run_system_with_input` to `run_system_with` - reordered input parameters for `World::run_system_once_with` ## Testing - Added a crude test which registers a system via `World::register_system_cached`, and removes it via `Command::unregister_system_cached`. ## Migration Guide - Change all occurrences of `World::run_system_with_input` to `World::run_system_with`. - swap the order of input parameters for `World::run_system_once_with` such that the system comes before the input. --------- Co-authored-by: Paul Mattern <[email protected]>
1 parent 3188e5a commit 854934c

File tree

5 files changed

+111
-45
lines changed

5 files changed

+111
-45
lines changed

crates/bevy_ecs/src/system/commands/mod.rs

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use core::{marker::PhantomData, panic::Location};
44

55
use super::{
66
Deferred, IntoObserverSystem, IntoSystem, RegisterSystem, Resource, RunSystemCachedWith,
7-
UnregisterSystem,
7+
UnregisterSystem, UnregisterSystemCached,
88
};
99
use crate::{
1010
self as bevy_ecs,
@@ -15,7 +15,7 @@ use crate::{
1515
event::{Event, SendEvent},
1616
observer::{Observer, TriggerEvent, TriggerTargets},
1717
schedule::ScheduleLabel,
18-
system::{input::SystemInput, RunSystemWithInput, SystemId},
18+
system::{input::SystemInput, RunSystemWith, SystemId},
1919
world::{
2020
command_queue::RawCommandQueue, unsafe_world_cell::UnsafeWorldCell, Command, CommandQueue,
2121
EntityWorldMut, FromWorld, SpawnBatchIter, World,
@@ -810,25 +810,25 @@ impl<'w, 's> Commands<'w, 's> {
810810
///
811811
/// There is no way to get the output of a system when run as a command, because the
812812
/// execution of the system happens later. To get the output of a system, use
813-
/// [`World::run_system`] or [`World::run_system_with_input`] instead of running the system as a command.
813+
/// [`World::run_system`] or [`World::run_system_with`] instead of running the system as a command.
814814
pub fn run_system(&mut self, id: SystemId) {
815-
self.run_system_with_input(id, ());
815+
self.run_system_with(id, ());
816816
}
817817

818818
/// Runs the system corresponding to the given [`SystemId`].
819819
/// Systems are ran in an exclusive and single threaded way.
820820
/// Running slow systems can become a bottleneck.
821821
///
822-
/// Calls [`World::run_system_with_input`](World::run_system_with_input).
822+
/// Calls [`World::run_system_with`](World::run_system_with).
823823
///
824824
/// There is no way to get the output of a system when run as a command, because the
825825
/// execution of the system happens later. To get the output of a system, use
826-
/// [`World::run_system`] or [`World::run_system_with_input`] instead of running the system as a command.
827-
pub fn run_system_with_input<I>(&mut self, id: SystemId<I>, input: I::Inner<'static>)
826+
/// [`World::run_system`] or [`World::run_system_with`] instead of running the system as a command.
827+
pub fn run_system_with<I>(&mut self, id: SystemId<I>, input: I::Inner<'static>)
828828
where
829829
I: SystemInput<Inner<'static>: Send> + 'static,
830830
{
831-
self.queue(RunSystemWithInput::new_with_input(id, input));
831+
self.queue(RunSystemWith::new_with_input(id, input));
832832
}
833833

834834
/// 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> {
904904
self.queue(UnregisterSystem::new(system_id));
905905
}
906906

907+
/// Removes a system previously registered with [`World::register_system_cached`].
908+
///
909+
/// See [`World::unregister_system_cached`] for more information.
910+
pub fn unregister_system_cached<
911+
I: SystemInput + Send + 'static,
912+
O: 'static,
913+
M: 'static,
914+
S: IntoSystem<I, O, M> + Send + 'static,
915+
>(
916+
&mut self,
917+
system: S,
918+
) {
919+
self.queue(UnregisterSystemCached::new(system));
920+
}
921+
907922
/// Similar to [`Self::run_system`], but caching the [`SystemId`] in a
908923
/// [`CachedSystemId`](crate::system::CachedSystemId) resource.
909924
///
@@ -915,7 +930,7 @@ impl<'w, 's> Commands<'w, 's> {
915930
self.run_system_cached_with(system, ());
916931
}
917932

918-
/// Similar to [`Self::run_system_with_input`], but caching the [`SystemId`] in a
933+
/// Similar to [`Self::run_system_with`], but caching the [`SystemId`] in a
919934
/// [`CachedSystemId`](crate::system::CachedSystemId) resource.
920935
///
921936
/// See [`World::register_system_cached`] for more information.
@@ -2617,6 +2632,25 @@ mod tests {
26172632
assert!(world.get::<Z>(e).is_some());
26182633
}
26192634

2635+
#[test]
2636+
fn unregister_system_cached_commands() {
2637+
let mut world = World::default();
2638+
let mut queue = CommandQueue::default();
2639+
2640+
fn nothing() {}
2641+
2642+
assert!(world.iter_resources().count() == 0);
2643+
let id = world.register_system_cached(nothing);
2644+
assert!(world.iter_resources().count() == 1);
2645+
assert!(world.get_entity(id.entity).is_ok());
2646+
2647+
let mut commands = Commands::new(&mut queue, &world);
2648+
commands.unregister_system_cached(nothing);
2649+
queue.apply(&mut world);
2650+
assert!(world.iter_resources().count() == 0);
2651+
assert!(world.get_entity(id.entity).is_err());
2652+
}
2653+
26202654
fn is_send<T: Send>() {}
26212655
fn is_sync<T: Sync>() {}
26222656

crates/bevy_ecs/src/system/system.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -322,14 +322,14 @@ pub trait RunSystemOnce: Sized {
322322
where
323323
T: IntoSystem<(), Out, Marker>,
324324
{
325-
self.run_system_once_with((), system)
325+
self.run_system_once_with(system, ())
326326
}
327327

328328
/// Tries to run a system with given input and apply deferred parameters.
329329
fn run_system_once_with<T, In, Out, Marker>(
330330
self,
331-
input: SystemIn<'_, T::System>,
332331
system: T,
332+
input: SystemIn<'_, T::System>,
333333
) -> Result<Out, RunSystemError>
334334
where
335335
T: IntoSystem<In, Out, Marker>,
@@ -339,8 +339,8 @@ pub trait RunSystemOnce: Sized {
339339
impl RunSystemOnce for &mut World {
340340
fn run_system_once_with<T, In, Out, Marker>(
341341
self,
342-
input: SystemIn<'_, T::System>,
343342
system: T,
343+
input: SystemIn<'_, T::System>,
344344
) -> Result<Out, RunSystemError>
345345
where
346346
T: IntoSystem<In, Out, Marker>,
@@ -392,7 +392,7 @@ mod tests {
392392
}
393393

394394
let mut world = World::default();
395-
let n = world.run_system_once_with(1, system).unwrap();
395+
let n = world.run_system_once_with(system, 1).unwrap();
396396
assert_eq!(n, 2);
397397
assert_eq!(world.resource::<T>().0, 1);
398398
}

crates/bevy_ecs/src/system/system_registry.rs

Lines changed: 60 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ impl World {
201201
/// This is different from [`RunSystemOnce::run_system_once`](crate::system::RunSystemOnce::run_system_once),
202202
/// because it keeps local state between calls and change detection works correctly.
203203
///
204-
/// In order to run a chained system with an input, use [`World::run_system_with_input`] instead.
204+
/// In order to run a chained system with an input, use [`World::run_system_with`] instead.
205205
///
206206
/// # Limitations
207207
///
@@ -286,7 +286,7 @@ impl World {
286286
&mut self,
287287
id: SystemId<(), O>,
288288
) -> Result<O, RegisteredSystemError<(), O>> {
289-
self.run_system_with_input(id, ())
289+
self.run_system_with(id, ())
290290
}
291291

292292
/// Run a stored chained system by its [`SystemId`], providing an input value.
@@ -309,13 +309,13 @@ impl World {
309309
/// let mut world = World::default();
310310
/// let counter_one = world.register_system(increment);
311311
/// let counter_two = world.register_system(increment);
312-
/// assert_eq!(world.run_system_with_input(counter_one, 1).unwrap(), 1);
313-
/// assert_eq!(world.run_system_with_input(counter_one, 20).unwrap(), 21);
314-
/// assert_eq!(world.run_system_with_input(counter_two, 30).unwrap(), 30);
312+
/// assert_eq!(world.run_system_with(counter_one, 1).unwrap(), 1);
313+
/// assert_eq!(world.run_system_with(counter_one, 20).unwrap(), 21);
314+
/// assert_eq!(world.run_system_with(counter_two, 30).unwrap(), 30);
315315
/// ```
316316
///
317317
/// See [`World::run_system`] for more examples.
318-
pub fn run_system_with_input<I, O>(
318+
pub fn run_system_with<I, O>(
319319
&mut self,
320320
id: SystemId<I, O>,
321321
input: I::Inner<'_>,
@@ -451,11 +451,11 @@ impl World {
451451
S: IntoSystem<I, O, M> + 'static,
452452
{
453453
let id = self.register_system_cached(system);
454-
self.run_system_with_input(id, input)
454+
self.run_system_with(id, input)
455455
}
456456
}
457457

458-
/// The [`Command`] type for [`World::run_system`] or [`World::run_system_with_input`].
458+
/// The [`Command`] type for [`World::run_system`] or [`World::run_system_with`].
459459
///
460460
/// This command runs systems in an exclusive and single threaded way.
461461
/// Running slow systems can become a bottleneck.
@@ -465,9 +465,9 @@ impl World {
465465
///
466466
/// There is no way to get the output of a system when run as a command, because the
467467
/// execution of the system happens later. To get the output of a system, use
468-
/// [`World::run_system`] or [`World::run_system_with_input`] instead of running the system as a command.
468+
/// [`World::run_system`] or [`World::run_system_with`] instead of running the system as a command.
469469
#[derive(Debug, Clone)]
470-
pub struct RunSystemWithInput<I: SystemInput + 'static> {
470+
pub struct RunSystemWith<I: SystemInput + 'static> {
471471
system_id: SystemId<I>,
472472
input: I::Inner<'static>,
473473
}
@@ -478,12 +478,12 @@ pub struct RunSystemWithInput<I: SystemInput + 'static> {
478478
/// Running slow systems can become a bottleneck.
479479
///
480480
/// If the system needs an [`In<_>`](crate::system::In) input value to run, use the
481-
/// [`RunSystemWithInput`] type instead.
481+
/// [`RunSystemWith`] type instead.
482482
///
483483
/// There is no way to get the output of a system when run as a command, because the
484484
/// execution of the system happens later. To get the output of a system, use
485-
/// [`World::run_system`] or [`World::run_system_with_input`] instead of running the system as a command.
486-
pub type RunSystem = RunSystemWithInput<()>;
485+
/// [`World::run_system`] or [`World::run_system_with`] instead of running the system as a command.
486+
pub type RunSystem = RunSystemWith<()>;
487487

488488
impl RunSystem {
489489
/// Creates a new [`Command`] struct, which can be added to [`Commands`](crate::system::Commands).
@@ -492,21 +492,21 @@ impl RunSystem {
492492
}
493493
}
494494

495-
impl<I: SystemInput + 'static> RunSystemWithInput<I> {
495+
impl<I: SystemInput + 'static> RunSystemWith<I> {
496496
/// Creates a new [`Command`] struct, which can be added to [`Commands`](crate::system::Commands)
497497
/// in order to run the specified system with the provided [`In<_>`](crate::system::In) input value.
498498
pub fn new_with_input(system_id: SystemId<I>, input: I::Inner<'static>) -> Self {
499499
Self { system_id, input }
500500
}
501501
}
502502

503-
impl<I> Command for RunSystemWithInput<I>
503+
impl<I> Command for RunSystemWith<I>
504504
where
505505
I: SystemInput<Inner<'static>: Send> + 'static,
506506
{
507507
#[inline]
508508
fn apply(self, world: &mut World) {
509-
_ = world.run_system_with_input(self.system_id, self.input);
509+
_ = world.run_system_with(self.system_id, self.input);
510510
}
511511
}
512512

@@ -570,6 +570,42 @@ where
570570
}
571571
}
572572

573+
/// The [`Command`] type for unregistering one-shot systems from [`Commands`](crate::system::Commands).
574+
pub struct UnregisterSystemCached<I, O, M, S>
575+
where
576+
I: SystemInput + 'static,
577+
S: IntoSystem<I, O, M> + Send + 'static,
578+
{
579+
system: S,
580+
_phantom: PhantomData<fn() -> (I, O, M)>,
581+
}
582+
583+
impl<I, O, M, S> UnregisterSystemCached<I, O, M, S>
584+
where
585+
I: SystemInput + 'static,
586+
S: IntoSystem<I, O, M> + Send + 'static,
587+
{
588+
/// Creates a new [`Command`] struct, which can be added to [`Commands`](crate::system::Commands).
589+
pub fn new(system: S) -> Self {
590+
Self {
591+
system,
592+
_phantom: PhantomData,
593+
}
594+
}
595+
}
596+
597+
impl<I, O, M, S> Command for UnregisterSystemCached<I, O, M, S>
598+
where
599+
I: SystemInput + 'static,
600+
O: 'static,
601+
M: 'static,
602+
S: IntoSystem<I, O, M> + Send + 'static,
603+
{
604+
fn apply(self, world: &mut World) {
605+
let _ = world.unregister_system_cached(self.system);
606+
}
607+
}
608+
573609
/// The [`Command`] type for running a cached one-shot system from
574610
/// [`Commands`](crate::system::Commands).
575611
///
@@ -730,22 +766,22 @@ mod tests {
730766
assert_eq!(*world.resource::<Counter>(), Counter(1));
731767

732768
world
733-
.run_system_with_input(id, NonCopy(1))
769+
.run_system_with(id, NonCopy(1))
734770
.expect("system runs successfully");
735771
assert_eq!(*world.resource::<Counter>(), Counter(2));
736772

737773
world
738-
.run_system_with_input(id, NonCopy(1))
774+
.run_system_with(id, NonCopy(1))
739775
.expect("system runs successfully");
740776
assert_eq!(*world.resource::<Counter>(), Counter(3));
741777

742778
world
743-
.run_system_with_input(id, NonCopy(20))
779+
.run_system_with(id, NonCopy(20))
744780
.expect("system runs successfully");
745781
assert_eq!(*world.resource::<Counter>(), Counter(23));
746782

747783
world
748-
.run_system_with_input(id, NonCopy(1))
784+
.run_system_with(id, NonCopy(1))
749785
.expect("system runs successfully");
750786
assert_eq!(*world.resource::<Counter>(), Counter(24));
751787
}
@@ -828,7 +864,7 @@ mod tests {
828864

829865
fn nested(query: Query<&Callback>, mut commands: Commands) {
830866
for callback in query.iter() {
831-
commands.run_system_with_input(callback.0, callback.1);
867+
commands.run_system_with(callback.0, callback.1);
832868
}
833869
}
834870

@@ -922,7 +958,7 @@ mod tests {
922958
world.insert_resource(Counter(0));
923959

924960
let id = world.register_system(with_ref);
925-
world.run_system_with_input(id, &2).unwrap();
961+
world.run_system_with(id, &2).unwrap();
926962
assert_eq!(*world.resource::<Counter>(), Counter(2));
927963
}
928964

@@ -944,15 +980,11 @@ mod tests {
944980
let post_system = world.register_system(post);
945981

946982
let mut event = MyEvent { cancelled: false };
947-
world
948-
.run_system_with_input(post_system, &mut event)
949-
.unwrap();
983+
world.run_system_with(post_system, &mut event).unwrap();
950984
assert!(!event.cancelled);
951985

952986
world.resource_mut::<Counter>().0 = 1;
953-
world
954-
.run_system_with_input(post_system, &mut event)
955-
.unwrap();
987+
world.run_system_with(post_system, &mut event).unwrap();
956988
assert!(event.cancelled);
957989
}
958990

crates/bevy_remote/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -800,7 +800,7 @@ fn process_remote_requests(world: &mut World) {
800800

801801
match handler {
802802
RemoteMethodSystemId::Instant(id) => {
803-
let result = match world.run_system_with_input(id, message.params) {
803+
let result = match world.run_system_with(id, message.params) {
804804
Ok(result) => result,
805805
Err(error) => {
806806
let _ = message.sender.force_send(Err(BrpError {
@@ -850,7 +850,7 @@ fn process_single_ongoing_watching_request(
850850
system_id: &RemoteWatchingMethodSystemId,
851851
) -> BrpResult<Option<Value>> {
852852
world
853-
.run_system_with_input(*system_id, message.params.clone())
853+
.run_system_with(*system_id, message.params.clone())
854854
.map_err(|error| BrpError {
855855
code: error_codes::INTERNAL_ERROR,
856856
message: format!("Failed to run method handler: {error}"),

crates/bevy_ui/src/layout/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -944,7 +944,7 @@ mod tests {
944944
new_pos: Vec2,
945945
expected_camera_entity: &Entity,
946946
) {
947-
world.run_system_once_with(new_pos, move_ui_node).unwrap();
947+
world.run_system_once_with(move_ui_node, new_pos).unwrap();
948948
ui_schedule.run(world);
949949
let (ui_node_entity, TargetCamera(target_camera_entity)) = world
950950
.query_filtered::<(Entity, &TargetCamera), With<MovingUiNode>>()
@@ -1234,11 +1234,11 @@ mod tests {
12341234
}
12351235

12361236
let _ = world.run_system_once_with(
1237+
test_system,
12371238
TestSystemParam {
12381239
camera_entity,
12391240
root_node_entity,
12401241
},
1241-
test_system,
12421242
);
12431243

12441244
let ui_surface = world.resource::<UiSurface>();

0 commit comments

Comments
 (0)