From 7f639e212ace1299372e5250317fa9df43545861 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Mon, 16 Jan 2023 18:39:09 -0500 Subject: [PATCH 01/16] implement `Command` for `FunctionSystem` --- crates/bevy_ecs/src/system/commands/mod.rs | 4 +++- crates/bevy_ecs/src/system/function_system.rs | 18 +++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index ed2d469b9b2f5..fd8031d53f695 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -11,7 +11,7 @@ pub use command_queue::CommandQueue; pub use parallel_scope::*; use std::marker::PhantomData; -use super::Resource; +use super::{Resource, SystemParam}; /// A [`World`] mutation. /// @@ -44,6 +44,8 @@ pub trait Command: Send + 'static { fn write(self, world: &mut World); } +pub trait CommandParam: SystemParam {} + /// A [`Command`] queue to perform impactful changes to the [`World`]. /// /// Since each command requires exclusive access to the `World`, diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index 7ec7c24489380..b78ab2dfc2cf3 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -5,7 +5,10 @@ use crate::{ prelude::FromWorld, query::{Access, FilteredAccessSet}, schedule::{SystemLabel, SystemLabelId}, - system::{check_system_change_tick, ReadOnlySystemParam, System, SystemParam, SystemParamItem}, + system::{ + check_system_change_tick, Command, CommandParam, ReadOnlySystemParam, System, SystemParam, + SystemParamItem, + }, world::{World, WorldId}, }; use bevy_ecs_macros::all_tuples; @@ -458,6 +461,19 @@ where } } +impl Command for FunctionSystem<(), (), Param, Marker, F> +where + Param: CommandParam + 'static, + Marker: 'static, + F: SystemParamFunction<(), (), Param, Marker> + Send + Sync + 'static, +{ + fn write(mut self, world: &mut World) { + self.initialize(world); + self.run((), world); + self.apply_buffers(world); + } +} + /// A [`SystemLabel`] that was automatically generated for a system on the basis of its `TypeId`. pub struct SystemTypeIdLabel(pub(crate) PhantomData T>); From 1205dfa1631d01cb296466ce197fc236515f7d00 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Mon, 16 Jan 2023 18:57:40 -0500 Subject: [PATCH 02/16] add the `IntoCommand` trait --- crates/bevy_ecs/src/system/commands/mod.rs | 30 +++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index fd8031d53f695..55fdc21ae21c6 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -11,7 +11,7 @@ pub use command_queue::CommandQueue; pub use parallel_scope::*; use std::marker::PhantomData; -use super::{Resource, SystemParam}; +use super::{IntoSystem, Resource, SystemParam}; /// A [`World`] mutation. /// @@ -46,6 +46,30 @@ pub trait Command: Send + 'static { pub trait CommandParam: SystemParam {} +pub trait IntoCommand { + type Command: Command; + fn into_command(self) -> Self::Command; +} + +impl IntoCommand<()> for T { + type Command = Self; + fn into_command(self) -> Self::Command { + self + } +} + +pub struct IsSystemCommand; + +impl> IntoCommand<(IsSystemCommand, Marker)> for T +where + T::System: Command, +{ + type Command = T::System; + fn into_command(self) -> Self::Command { + IntoSystem::into_system(self) + } +} + /// A [`Command`] queue to perform impactful changes to the [`World`]. /// /// Since each command requires exclusive access to the `World`, @@ -524,8 +548,8 @@ impl<'w, 's> Commands<'w, 's> { /// # bevy_ecs::system::assert_is_system(add_three_to_counter_system); /// # bevy_ecs::system::assert_is_system(add_twenty_five_to_counter_system); /// ``` - pub fn add(&mut self, command: C) { - self.queue.push(command); + pub fn add>(&mut self, command: C) { + self.queue.push(command.into_command()); } } From 922bfb77be94acc0af617722eec57c21c9512273 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Mon, 16 Jan 2023 19:31:46 -0500 Subject: [PATCH 03/16] implement `CommandParam` for types --- crates/bevy_ecs/macros/src/lib.rs | 3 ++ crates/bevy_ecs/src/system/system_param.rs | 35 +++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index 3d8a10b3af68e..3959474ccb65c 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -304,6 +304,9 @@ pub fn impl_param_set(_input: TokenStream) -> TokenStream { } } + impl<'_w, '_s, #(#param: CommandParam,)*> CommandParam for ParamSet<'_w, '_s, (#(#param,)*)> + {} + impl<'w, 's, #(#param: SystemParam,)*> ParamSet<'w, 's, (#(#param,)*)> { #(#param_fn_mut)* diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index e08326f8868a7..ffe8ffdc7e718 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -8,7 +8,7 @@ use crate::{ query::{ Access, FilteredAccess, FilteredAccessSet, QueryState, ReadOnlyWorldQuery, WorldQuery, }, - system::{CommandQueue, Commands, Query, SystemMeta}, + system::{CommandParam, CommandQueue, Commands, Query, SystemMeta}, world::{FromWorld, World}, }; pub use bevy_ecs_macros::Resource; @@ -233,6 +233,11 @@ unsafe impl SystemPara } } +impl CommandParam + for Query<'_, '_, Q, F> +{ +} + fn assert_component_access_compatibility( system_name: &str, query_type: &'static str, @@ -463,6 +468,8 @@ unsafe impl<'a, T: Resource> SystemParam for Res<'a, T> { } } +impl CommandParam for Res<'_, T> {} + // SAFETY: Only reads a single World resource unsafe impl<'a, T: Resource> ReadOnlySystemParam for Option> {} @@ -496,6 +503,8 @@ unsafe impl<'a, T: Resource> SystemParam for Option> { } } +impl CommandParam for Option> {} + // SAFETY: Res ComponentId and ArchetypeComponentId access is applied to SystemMeta. If this Res // conflicts with any prior access, a panic will occur. unsafe impl<'a, T: Resource> SystemParam for ResMut<'a, T> { @@ -556,6 +565,8 @@ unsafe impl<'a, T: Resource> SystemParam for ResMut<'a, T> { } } +impl CommandParam for ResMut<'_, T> {} + // SAFETY: this impl defers to `ResMut`, which initializes and validates the correct world access. unsafe impl<'a, T: Resource> SystemParam for Option> { type State = ComponentId; @@ -586,6 +597,8 @@ unsafe impl<'a, T: Resource> SystemParam for Option> { } } +impl CommandParam for Option> {} + // SAFETY: Commands only accesses internal state unsafe impl<'w, 's> ReadOnlySystemParam for Commands<'w, 's> {} @@ -659,6 +672,8 @@ unsafe impl SystemParam for &'_ World { } } +impl CommandParam for &World {} + /// A system local [`SystemParam`]. /// /// A local may only be accessed by the system itself and is therefore not visible to other systems. @@ -985,6 +1000,8 @@ unsafe impl<'a, T: 'static> SystemParam for NonSend<'a, T> { } } +impl CommandParam for NonSend<'_, T> {} + // SAFETY: this impl defers to `NonSend`, which initializes and validates the correct world access. unsafe impl SystemParam for Option> { type State = ComponentId; @@ -1012,6 +1029,8 @@ unsafe impl SystemParam for Option> { } } +impl CommandParam for Option> {} + // SAFETY: Only reads a single non-send resource unsafe impl<'a, T: 'static> ReadOnlySystemParam for NonSendMut<'a, T> {} @@ -1072,6 +1091,8 @@ unsafe impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> { } } +impl CommandParam for NonSendMut<'_, T> {} + // SAFETY: this impl defers to `NonSendMut`, which initializes and validates the correct world access. unsafe impl<'a, T: 'static> SystemParam for Option> { type State = ComponentId; @@ -1097,6 +1118,8 @@ unsafe impl<'a, T: 'static> SystemParam for Option> { } } +impl CommandParam for Option> {} + // SAFETY: Only reads World archetypes unsafe impl<'a> ReadOnlySystemParam for &'a Archetypes {} @@ -1118,6 +1141,8 @@ unsafe impl<'a> SystemParam for &'a Archetypes { } } +impl CommandParam for &Archetypes {} + // SAFETY: Only reads World components unsafe impl<'a> ReadOnlySystemParam for &'a Components {} @@ -1139,6 +1164,8 @@ unsafe impl<'a> SystemParam for &'a Components { } } +impl CommandParam for &Components {} + // SAFETY: Only reads World entities unsafe impl<'a> ReadOnlySystemParam for &'a Entities {} @@ -1159,6 +1186,7 @@ unsafe impl<'a> SystemParam for &'a Entities { world.entities() } } +impl CommandParam for &Entities {} // SAFETY: Only reads World bundles unsafe impl<'a> ReadOnlySystemParam for &'a Bundles {} @@ -1181,6 +1209,8 @@ unsafe impl<'a> SystemParam for &'a Bundles { } } +impl CommandParam for &Bundles {} + /// A [`SystemParam`] that reads the previous and current change ticks of the system. /// /// A system's change ticks are updated each time it runs: @@ -1344,6 +1374,9 @@ macro_rules! impl_system_param_tuple { ($($param::get_param($param, _system_meta, _world, _change_tick),)*) } } + + #[allow(non_snake_case)] + impl<$($param: CommandParam),*> CommandParam for ($($param,)*) {} }; } From 535267229fd71259223b2053f8a6d094d73628ae Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Mon, 16 Jan 2023 19:37:31 -0500 Subject: [PATCH 04/16] implement `CommandParam` for derived types --- crates/bevy_ecs/macros/src/lib.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index 3959474ccb65c..7cd09804370b6 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -459,6 +459,16 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream { .push(syn::parse_quote!(#field_type: #path::system::ReadOnlySystemParam)); } + // Create a where clause for the `CommandParam` impl. + // Ensure that each field implements `CommandParam`. + let mut command_param_generics = generics.clone(); + let command_param_where_clause = command_param_generics.make_where_clause(); + for field_type in &field_types { + command_param_where_clause + .predicates + .push(syn::parse_quote!(#field_type: #path::system::CommandParam)); + } + let struct_name = &ast.ident; let state_struct_visibility = &ast.vis; @@ -514,6 +524,8 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream { // Safety: Each field is `ReadOnlySystemParam`, so this can only read from the `World` unsafe impl<'w, 's, #punctuated_generics> #path::system::ReadOnlySystemParam for #struct_name #ty_generics #read_only_where_clause {} + + impl<'w, 's, #punctuated_generics> #path::system::CommandParam for #struct_name #ty_generics #command_param_where_clause {} }; }) } From 04ea33f186ceabb1f09646a6d84e6a03e2d160d2 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Mon, 16 Jan 2023 19:38:54 -0500 Subject: [PATCH 05/16] add a test case for system commands --- crates/bevy_ecs/src/system/commands/mod.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 55fdc21ae21c6..2c04ae9214a8d 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -1018,6 +1018,7 @@ mod tests { use crate::{ self as bevy_ecs, component::Component, + event::{EventWriter, Events}, system::{CommandQueue, Commands, Resource}, world::World, }; @@ -1172,4 +1173,23 @@ mod tests { assert!(!world.contains_resource::>()); assert!(world.contains_resource::>()); } + + #[test] + fn system_commands() { + struct E; + + let mut world = World::new(); + world.init_resource::>(); + + let mut command_queue = CommandQueue::default(); + + let mut commands = Commands::new(&mut command_queue, &world); + commands.add(|mut events: EventWriter| { + events.send(E); + }); + + command_queue.apply(&mut world); + + assert!(!world.resource::>().is_empty()); + } } From 1f70a83e1332c249ecb1cfadc5c9d8af99f863f0 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Mon, 16 Jan 2023 20:15:18 -0500 Subject: [PATCH 06/16] add a module for system commands --- crates/bevy_ecs/src/system/commands/mod.rs | 15 ++------------- .../src/system/commands/system_command.rs | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 13 deletions(-) create mode 100644 crates/bevy_ecs/src/system/commands/system_command.rs diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 2c04ae9214a8d..b56d61d27257d 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -1,5 +1,6 @@ mod command_queue; mod parallel_scope; +mod system_command; use crate::{ bundle::Bundle, @@ -11,7 +12,7 @@ pub use command_queue::CommandQueue; pub use parallel_scope::*; use std::marker::PhantomData; -use super::{IntoSystem, Resource, SystemParam}; +use super::{Resource, SystemParam}; /// A [`World`] mutation. /// @@ -58,18 +59,6 @@ impl IntoCommand<()> for T { } } -pub struct IsSystemCommand; - -impl> IntoCommand<(IsSystemCommand, Marker)> for T -where - T::System: Command, -{ - type Command = T::System; - fn into_command(self) -> Self::Command { - IntoSystem::into_system(self) - } -} - /// A [`Command`] queue to perform impactful changes to the [`World`]. /// /// Since each command requires exclusive access to the `World`, diff --git a/crates/bevy_ecs/src/system/commands/system_command.rs b/crates/bevy_ecs/src/system/commands/system_command.rs new file mode 100644 index 0000000000000..b302f8e304068 --- /dev/null +++ b/crates/bevy_ecs/src/system/commands/system_command.rs @@ -0,0 +1,15 @@ +use crate::system::IntoSystem; + +use super::{Command, IntoCommand}; + +pub struct IsSystemCommand; + +impl> IntoCommand<(IsSystemCommand, Marker)> for T +where + T::System: Command, +{ + type Command = T::System; + fn into_command(self) -> Self::Command { + IntoSystem::into_system(self) + } +} From 290080eec56669c75d817a68a2ea971e50a2753f Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Mon, 16 Jan 2023 20:15:29 -0500 Subject: [PATCH 07/16] hide a marker struct --- crates/bevy_ecs/src/system/commands/system_command.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/bevy_ecs/src/system/commands/system_command.rs b/crates/bevy_ecs/src/system/commands/system_command.rs index b302f8e304068..ac585f23fcebf 100644 --- a/crates/bevy_ecs/src/system/commands/system_command.rs +++ b/crates/bevy_ecs/src/system/commands/system_command.rs @@ -2,6 +2,7 @@ use crate::system::IntoSystem; use super::{Command, IntoCommand}; +#[doc(hidden)] pub struct IsSystemCommand; impl> IntoCommand<(IsSystemCommand, Marker)> for T From ee58a907a33d4201bebad3e2ccc870ab5d2721d3 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Mon, 16 Jan 2023 20:17:02 -0500 Subject: [PATCH 08/16] move `CommandParam` into the new module --- crates/bevy_ecs/src/system/commands/mod.rs | 5 ++--- crates/bevy_ecs/src/system/commands/system_command.rs | 4 +++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index b56d61d27257d..637a340121cb0 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -11,8 +11,9 @@ use bevy_utils::tracing::{error, info}; pub use command_queue::CommandQueue; pub use parallel_scope::*; use std::marker::PhantomData; +pub use system_command::CommandParam; -use super::{Resource, SystemParam}; +use super::Resource; /// A [`World`] mutation. /// @@ -45,8 +46,6 @@ pub trait Command: Send + 'static { fn write(self, world: &mut World); } -pub trait CommandParam: SystemParam {} - pub trait IntoCommand { type Command: Command; fn into_command(self) -> Self::Command; diff --git a/crates/bevy_ecs/src/system/commands/system_command.rs b/crates/bevy_ecs/src/system/commands/system_command.rs index ac585f23fcebf..82048fb815701 100644 --- a/crates/bevy_ecs/src/system/commands/system_command.rs +++ b/crates/bevy_ecs/src/system/commands/system_command.rs @@ -1,10 +1,12 @@ -use crate::system::IntoSystem; +use crate::system::{IntoSystem, SystemParam}; use super::{Command, IntoCommand}; #[doc(hidden)] pub struct IsSystemCommand; +pub trait CommandParam: SystemParam {} + impl> IntoCommand<(IsSystemCommand, Marker)> for T where T::System: Command, From 69c148c3d08310a6609235ffe375fee5d116481f Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Mon, 16 Jan 2023 20:39:36 -0500 Subject: [PATCH 09/16] turn a method into an associated fn --- crates/bevy_ecs/src/system/commands/mod.rs | 8 ++++---- crates/bevy_ecs/src/system/commands/system_command.rs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 637a340121cb0..e17de22bcc902 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -48,13 +48,13 @@ pub trait Command: Send + 'static { pub trait IntoCommand { type Command: Command; - fn into_command(self) -> Self::Command; + fn into_command(this: Self) -> Self::Command; } impl IntoCommand<()> for T { type Command = Self; - fn into_command(self) -> Self::Command { - self + fn into_command(this: Self) -> Self::Command { + this } } @@ -537,7 +537,7 @@ impl<'w, 's> Commands<'w, 's> { /// # bevy_ecs::system::assert_is_system(add_twenty_five_to_counter_system); /// ``` pub fn add>(&mut self, command: C) { - self.queue.push(command.into_command()); + self.queue.push(IntoCommand::into_command(command)); } } diff --git a/crates/bevy_ecs/src/system/commands/system_command.rs b/crates/bevy_ecs/src/system/commands/system_command.rs index 82048fb815701..5d33b1ed6c6f1 100644 --- a/crates/bevy_ecs/src/system/commands/system_command.rs +++ b/crates/bevy_ecs/src/system/commands/system_command.rs @@ -12,7 +12,7 @@ where T::System: Command, { type Command = T::System; - fn into_command(self) -> Self::Command { - IntoSystem::into_system(self) + fn into_command(this: Self) -> Self::Command { + IntoSystem::into_system(this) } } From 5b72c8601fdde32d0cf6215949c13c9611960ed1 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Mon, 16 Jan 2023 20:40:09 -0500 Subject: [PATCH 10/16] replace `FunctionSystem` with a type specialized for commands --- .../src/system/commands/system_command.rs | 57 +++++++++++++++++-- crates/bevy_ecs/src/system/function_system.rs | 18 +----- 2 files changed, 54 insertions(+), 21 deletions(-) diff --git a/crates/bevy_ecs/src/system/commands/system_command.rs b/crates/bevy_ecs/src/system/commands/system_command.rs index 5d33b1ed6c6f1..cac4ffb7e4bdd 100644 --- a/crates/bevy_ecs/src/system/commands/system_command.rs +++ b/crates/bevy_ecs/src/system/commands/system_command.rs @@ -1,9 +1,11 @@ -use crate::system::{IntoSystem, SystemParam}; +use std::marker::PhantomData; -use super::{Command, IntoCommand}; +use crate::{ + prelude::World, + system::{IntoSystem, SystemMeta, SystemParam, SystemParamFunction}, +}; -#[doc(hidden)] -pub struct IsSystemCommand; +use super::{Command, IntoCommand}; pub trait CommandParam: SystemParam {} @@ -16,3 +18,50 @@ where IntoSystem::into_system(this) } } + +#[doc(hidden)] +pub struct IsSystemCommand; + +pub struct SystemCommand +where + Param: CommandParam, +{ + func: F, + system_meta: SystemMeta, + // NOTE: PhantomData T> gives this safe Send/Sync impls + marker: PhantomData (Param, Marker)>, +} + +impl IntoCommand<(IsSystemCommand, Param, Marker)> for F +where + Param: CommandParam + 'static, + Marker: 'static, + F: SystemParamFunction<(), (), Param, Marker> + Send + Sync + 'static, +{ + type Command = SystemCommand; + fn into_command(func: Self) -> Self::Command { + SystemCommand { + func, + system_meta: SystemMeta::new::(), + marker: PhantomData, + } + } +} + +impl Command for SystemCommand +where + Param: CommandParam + 'static, + Marker: 'static, + F: SystemParamFunction<(), (), Param, Marker> + Send + Sync + 'static, +{ + fn write(mut self, world: &mut World) { + let change_tick = world.change_tick(); + + let mut param_state = Param::init_state(world, &mut self.system_meta); + let params = + // SAFETY: We have exclusive world access. + unsafe { Param::get_param(&mut param_state, &self.system_meta, world, change_tick) }; + self.func.run((), params); + Param::apply(&mut param_state, &self.system_meta, world); + } +} diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index b78ab2dfc2cf3..7ec7c24489380 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -5,10 +5,7 @@ use crate::{ prelude::FromWorld, query::{Access, FilteredAccessSet}, schedule::{SystemLabel, SystemLabelId}, - system::{ - check_system_change_tick, Command, CommandParam, ReadOnlySystemParam, System, SystemParam, - SystemParamItem, - }, + system::{check_system_change_tick, ReadOnlySystemParam, System, SystemParam, SystemParamItem}, world::{World, WorldId}, }; use bevy_ecs_macros::all_tuples; @@ -461,19 +458,6 @@ where } } -impl Command for FunctionSystem<(), (), Param, Marker, F> -where - Param: CommandParam + 'static, - Marker: 'static, - F: SystemParamFunction<(), (), Param, Marker> + Send + Sync + 'static, -{ - fn write(mut self, world: &mut World) { - self.initialize(world); - self.run((), world); - self.apply_buffers(world); - } -} - /// A [`SystemLabel`] that was automatically generated for a system on the basis of its `TypeId`. pub struct SystemTypeIdLabel(pub(crate) PhantomData T>); From 2f524769180e521bdd7cd172842a5b92c32a54ef Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Mon, 16 Jan 2023 20:44:40 -0500 Subject: [PATCH 11/16] fix variance for a marker --- crates/bevy_ecs/src/system/commands/system_command.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/system/commands/system_command.rs b/crates/bevy_ecs/src/system/commands/system_command.rs index cac4ffb7e4bdd..1451ea7919832 100644 --- a/crates/bevy_ecs/src/system/commands/system_command.rs +++ b/crates/bevy_ecs/src/system/commands/system_command.rs @@ -28,8 +28,7 @@ where { func: F, system_meta: SystemMeta, - // NOTE: PhantomData T> gives this safe Send/Sync impls - marker: PhantomData (Param, Marker)>, + marker: PhantomData Marker>, } impl IntoCommand<(IsSystemCommand, Param, Marker)> for F From 927595a55e5548c5cd9a707706005304eedf5b89 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Mon, 16 Jan 2023 21:29:22 -0500 Subject: [PATCH 12/16] don't implement `CommandParam` for `NonSend*` --- crates/bevy_ecs/src/system/system_param.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index ef52fb7a6a559..b29a822400f7e 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -1000,8 +1000,6 @@ unsafe impl<'a, T: 'static> SystemParam for NonSend<'a, T> { } } -impl CommandParam for NonSend<'_, T> {} - // SAFETY: this impl defers to `NonSend`, which initializes and validates the correct world access. unsafe impl SystemParam for Option> { type State = ComponentId; @@ -1029,8 +1027,6 @@ unsafe impl SystemParam for Option> { } } -impl CommandParam for Option> {} - // SAFETY: NonSendMut ComponentId and ArchetypeComponentId access is applied to SystemMeta. If this // NonSendMut conflicts with any prior access, a panic will occur. unsafe impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> { @@ -1088,8 +1084,6 @@ unsafe impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> { } } -impl CommandParam for NonSendMut<'_, T> {} - // SAFETY: this impl defers to `NonSendMut`, which initializes and validates the correct world access. unsafe impl<'a, T: 'static> SystemParam for Option> { type State = ComponentId; @@ -1115,8 +1109,6 @@ unsafe impl<'a, T: 'static> SystemParam for Option> { } } -impl CommandParam for Option> {} - // SAFETY: Only reads World archetypes unsafe impl<'a> ReadOnlySystemParam for &'a Archetypes {} From e2fada4829966f08ca9ae8c942dd8dbc12071d40 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Mon, 16 Jan 2023 21:37:31 -0500 Subject: [PATCH 13/16] add a line break --- crates/bevy_ecs/src/system/system_param.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index b29a822400f7e..fbc29db9ede6b 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -1175,6 +1175,7 @@ unsafe impl<'a> SystemParam for &'a Entities { world.entities() } } + impl CommandParam for &Entities {} // SAFETY: Only reads World bundles From 2aa8501224b150477d8b74b8f8cad341db48a819 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Mon, 16 Jan 2023 21:47:26 -0500 Subject: [PATCH 14/16] `CommandParam` -> `CommandSystemParam` --- crates/bevy_ecs/macros/src/lib.rs | 10 ++++---- crates/bevy_ecs/src/system/commands/mod.rs | 2 +- .../src/system/commands/system_command.rs | 8 +++---- crates/bevy_ecs/src/system/system_param.rs | 24 +++++++++---------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index f6011a119be98..c97d440e1de1c 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -306,7 +306,7 @@ pub fn impl_param_set(_input: TokenStream) -> TokenStream { } } - impl<'_w, '_s, #(#param: CommandParam,)*> CommandParam for ParamSet<'_w, '_s, (#(#param,)*)> + impl<'_w, '_s, #(#param: CommandSystemParam,)*> CommandSystemParam for ParamSet<'_w, '_s, (#(#param,)*)> {} impl<'w, 's, #(#param: SystemParam,)*> ParamSet<'w, 's, (#(#param,)*)> @@ -461,14 +461,14 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream { .push(syn::parse_quote!(#field_type: #path::system::ReadOnlySystemParam)); } - // Create a where clause for the `CommandParam` impl. - // Ensure that each field implements `CommandParam`. + // Create a where clause for the `CommandSystemParam` impl. + // Ensure that each field implements `CommandSystemParam`. let mut command_param_generics = generics.clone(); let command_param_where_clause = command_param_generics.make_where_clause(); for field_type in &field_types { command_param_where_clause .predicates - .push(syn::parse_quote!(#field_type: #path::system::CommandParam)); + .push(syn::parse_quote!(#field_type: #path::system::CommandSystemParam)); } let struct_name = &ast.ident; @@ -527,7 +527,7 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream { // Safety: Each field is `ReadOnlySystemParam`, so this can only read from the `World` unsafe impl<'w, 's, #punctuated_generics> #path::system::ReadOnlySystemParam for #struct_name #ty_generics #read_only_where_clause {} - impl<'w, 's, #punctuated_generics> #path::system::CommandParam for #struct_name #ty_generics #command_param_where_clause {} + impl<'w, 's, #punctuated_generics> #path::system::CommandSystemParam for #struct_name #ty_generics #command_param_where_clause {} }; }) } diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index e17de22bcc902..2e8b1d6033601 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -11,7 +11,7 @@ use bevy_utils::tracing::{error, info}; pub use command_queue::CommandQueue; pub use parallel_scope::*; use std::marker::PhantomData; -pub use system_command::CommandParam; +pub use system_command::CommandSystemParam; use super::Resource; diff --git a/crates/bevy_ecs/src/system/commands/system_command.rs b/crates/bevy_ecs/src/system/commands/system_command.rs index 1451ea7919832..2b2b2c0a25a7a 100644 --- a/crates/bevy_ecs/src/system/commands/system_command.rs +++ b/crates/bevy_ecs/src/system/commands/system_command.rs @@ -7,7 +7,7 @@ use crate::{ use super::{Command, IntoCommand}; -pub trait CommandParam: SystemParam {} +pub trait CommandSystemParam: SystemParam {} impl> IntoCommand<(IsSystemCommand, Marker)> for T where @@ -24,7 +24,7 @@ pub struct IsSystemCommand; pub struct SystemCommand where - Param: CommandParam, + Param: CommandSystemParam, { func: F, system_meta: SystemMeta, @@ -33,7 +33,7 @@ where impl IntoCommand<(IsSystemCommand, Param, Marker)> for F where - Param: CommandParam + 'static, + Param: CommandSystemParam + 'static, Marker: 'static, F: SystemParamFunction<(), (), Param, Marker> + Send + Sync + 'static, { @@ -49,7 +49,7 @@ where impl Command for SystemCommand where - Param: CommandParam + 'static, + Param: CommandSystemParam + 'static, Marker: 'static, F: SystemParamFunction<(), (), Param, Marker> + Send + Sync + 'static, { diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index fbc29db9ede6b..2c4caecd5d552 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -8,7 +8,7 @@ use crate::{ query::{ Access, FilteredAccess, FilteredAccessSet, QueryState, ReadOnlyWorldQuery, WorldQuery, }, - system::{CommandParam, CommandQueue, Commands, Query, SystemMeta}, + system::{CommandQueue, CommandSystemParam, Commands, Query, SystemMeta}, world::{FromWorld, World}, }; pub use bevy_ecs_macros::Resource; @@ -233,7 +233,7 @@ unsafe impl SystemPara } } -impl CommandParam +impl CommandSystemParam for Query<'_, '_, Q, F> { } @@ -468,7 +468,7 @@ unsafe impl<'a, T: Resource> SystemParam for Res<'a, T> { } } -impl CommandParam for Res<'_, T> {} +impl CommandSystemParam for Res<'_, T> {} // SAFETY: Only reads a single World resource unsafe impl<'a, T: Resource> ReadOnlySystemParam for Option> {} @@ -503,7 +503,7 @@ unsafe impl<'a, T: Resource> SystemParam for Option> { } } -impl CommandParam for Option> {} +impl CommandSystemParam for Option> {} // SAFETY: Res ComponentId and ArchetypeComponentId access is applied to SystemMeta. If this Res // conflicts with any prior access, a panic will occur. @@ -565,7 +565,7 @@ unsafe impl<'a, T: Resource> SystemParam for ResMut<'a, T> { } } -impl CommandParam for ResMut<'_, T> {} +impl CommandSystemParam for ResMut<'_, T> {} // SAFETY: this impl defers to `ResMut`, which initializes and validates the correct world access. unsafe impl<'a, T: Resource> SystemParam for Option> { @@ -597,7 +597,7 @@ unsafe impl<'a, T: Resource> SystemParam for Option> { } } -impl CommandParam for Option> {} +impl CommandSystemParam for Option> {} // SAFETY: Commands only accesses internal state unsafe impl<'w, 's> ReadOnlySystemParam for Commands<'w, 's> {} @@ -672,7 +672,7 @@ unsafe impl SystemParam for &'_ World { } } -impl CommandParam for &World {} +impl CommandSystemParam for &World {} /// A system local [`SystemParam`]. /// @@ -1130,7 +1130,7 @@ unsafe impl<'a> SystemParam for &'a Archetypes { } } -impl CommandParam for &Archetypes {} +impl CommandSystemParam for &Archetypes {} // SAFETY: Only reads World components unsafe impl<'a> ReadOnlySystemParam for &'a Components {} @@ -1153,7 +1153,7 @@ unsafe impl<'a> SystemParam for &'a Components { } } -impl CommandParam for &Components {} +impl CommandSystemParam for &Components {} // SAFETY: Only reads World entities unsafe impl<'a> ReadOnlySystemParam for &'a Entities {} @@ -1176,7 +1176,7 @@ unsafe impl<'a> SystemParam for &'a Entities { } } -impl CommandParam for &Entities {} +impl CommandSystemParam for &Entities {} // SAFETY: Only reads World bundles unsafe impl<'a> ReadOnlySystemParam for &'a Bundles {} @@ -1199,7 +1199,7 @@ unsafe impl<'a> SystemParam for &'a Bundles { } } -impl CommandParam for &Bundles {} +impl CommandSystemParam for &Bundles {} /// A [`SystemParam`] that reads the previous and current change ticks of the system. /// @@ -1366,7 +1366,7 @@ macro_rules! impl_system_param_tuple { } #[allow(non_snake_case)] - impl<$($param: CommandParam),*> CommandParam for ($($param,)*) {} + impl<$($param: CommandSystemParam),*> CommandSystemParam for ($($param,)*) {} }; } From 98d51ac4dac7152b90b789acf6ceadc1aae1a698 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Mon, 16 Jan 2023 21:51:21 -0500 Subject: [PATCH 15/16] remove redundant bounds --- crates/bevy_ecs/src/system/commands/system_command.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/system/commands/system_command.rs b/crates/bevy_ecs/src/system/commands/system_command.rs index 2b2b2c0a25a7a..a974ad9e2d427 100644 --- a/crates/bevy_ecs/src/system/commands/system_command.rs +++ b/crates/bevy_ecs/src/system/commands/system_command.rs @@ -35,7 +35,7 @@ impl IntoCommand<(IsSystemCommand, Param, Marker)> for F where Param: CommandSystemParam + 'static, Marker: 'static, - F: SystemParamFunction<(), (), Param, Marker> + Send + Sync + 'static, + F: SystemParamFunction<(), (), Param, Marker>, { type Command = SystemCommand; fn into_command(func: Self) -> Self::Command { @@ -51,7 +51,7 @@ impl Command for SystemCommand where Param: CommandSystemParam + 'static, Marker: 'static, - F: SystemParamFunction<(), (), Param, Marker> + Send + Sync + 'static, + F: SystemParamFunction<(), (), Param, Marker>, { fn write(mut self, world: &mut World) { let change_tick = world.change_tick(); From 75e524d37a1c5c7ccc6300276acdca915dc40c57 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Mon, 16 Jan 2023 21:56:10 -0500 Subject: [PATCH 16/16] don't store `SystemMeta` --- crates/bevy_ecs/src/system/commands/system_command.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/bevy_ecs/src/system/commands/system_command.rs b/crates/bevy_ecs/src/system/commands/system_command.rs index a974ad9e2d427..83ed88cff5bea 100644 --- a/crates/bevy_ecs/src/system/commands/system_command.rs +++ b/crates/bevy_ecs/src/system/commands/system_command.rs @@ -27,7 +27,6 @@ where Param: CommandSystemParam, { func: F, - system_meta: SystemMeta, marker: PhantomData Marker>, } @@ -41,7 +40,6 @@ where fn into_command(func: Self) -> Self::Command { SystemCommand { func, - system_meta: SystemMeta::new::(), marker: PhantomData, } } @@ -56,11 +54,12 @@ where fn write(mut self, world: &mut World) { let change_tick = world.change_tick(); - let mut param_state = Param::init_state(world, &mut self.system_meta); + let mut system_meta = SystemMeta::new::(); + let mut param_state = Param::init_state(world, &mut system_meta); let params = // SAFETY: We have exclusive world access. - unsafe { Param::get_param(&mut param_state, &self.system_meta, world, change_tick) }; + unsafe { Param::get_param(&mut param_state, &system_meta, world, change_tick) }; self.func.run((), params); - Param::apply(&mut param_state, &self.system_meta, world); + Param::apply(&mut param_state, &system_meta, world); } }