From 1040b9fe8517ca1c6c25ce9534d65464ca42e1eb Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Wed, 1 Mar 2023 20:27:57 -0500 Subject: [PATCH 1/7] add marker traits to separate base system sets --- crates/bevy_app/src/config.rs | 6 +++--- crates/bevy_ecs/macros/src/set.rs | 22 +++++++++++++++++++++- crates/bevy_ecs/src/schedule/config.rs | 10 ++++++---- crates/bevy_ecs/src/schedule/mod.rs | 14 -------------- crates/bevy_ecs/src/schedule/set.rs | 10 ++++++++++ 5 files changed, 40 insertions(+), 22 deletions(-) diff --git a/crates/bevy_app/src/config.rs b/crates/bevy_app/src/config.rs index 81d35f8574445..b2614d8d3be2a 100644 --- a/crates/bevy_app/src/config.rs +++ b/crates/bevy_app/src/config.rs @@ -1,8 +1,8 @@ use bevy_ecs::{ all_tuples, schedule::{ - BoxedScheduleLabel, Condition, IntoSystemConfig, IntoSystemSet, ScheduleLabel, - SystemConfig, SystemConfigs, SystemSet, + BaseSystemSet, BoxedScheduleLabel, Condition, IntoSystemConfig, IntoSystemSet, + ScheduleLabel, SystemConfig, SystemConfigs, SystemSet, }, }; @@ -93,7 +93,7 @@ impl IntoSystemConfig<(), Self> for SystemAppConfig { } #[track_caller] - fn in_base_set(self, set: impl SystemSet) -> Self { + fn in_base_set(self, set: impl BaseSystemSet) -> Self { let Self { system, schedule } = self; Self { system: system.in_base_set(set), diff --git a/crates/bevy_ecs/macros/src/set.rs b/crates/bevy_ecs/macros/src/set.rs index 545de5ef87eb4..cf4134cfc5b7d 100644 --- a/crates/bevy_ecs/macros/src/set.rs +++ b/crates/bevy_ecs/macros/src/set.rs @@ -1,5 +1,5 @@ use proc_macro::TokenStream; -use quote::{quote, ToTokens}; +use quote::{format_ident, quote, ToTokens}; use syn::parse::{Parse, ParseStream}; pub static SYSTEM_SET_ATTRIBUTE_NAME: &str = "system_set"; @@ -12,6 +12,14 @@ pub static BASE_ATTRIBUTE_NAME: &str = "base"; /// - `input`: The [`syn::DeriveInput`] for the struct that we want to derive the set trait for /// - `trait_path`: The [`syn::Path`] to the set trait pub fn derive_set(input: syn::DeriveInput, trait_path: &syn::Path) -> TokenStream { + let mut base_trait_path = trait_path.clone(); + let x = &mut base_trait_path.segments.last_mut().unwrap().ident; + *x = format_ident!("Base{x}"); + + let mut free_trait_path = trait_path.clone(); + let x = &mut free_trait_path.segments.last_mut().unwrap().ident; + *x = format_ident!("Free{x}"); + let ident = input.ident; let mut is_base = false; @@ -65,6 +73,16 @@ pub fn derive_set(input: syn::DeriveInput, trait_path: &syn::Path) -> TokenStrea .unwrap(), ); + let marker_impl = if is_base { + quote! { + impl #impl_generics #base_trait_path for #ident #ty_generics #where_clause {} + } + } else { + quote! { + impl #impl_generics #free_trait_path for #ident #ty_generics #where_clause {} + } + }; + (quote! { impl #impl_generics #trait_path for #ident #ty_generics #where_clause { fn is_base(&self) -> bool { @@ -75,6 +93,8 @@ pub fn derive_set(input: syn::DeriveInput, trait_path: &syn::Path) -> TokenStrea std::boxed::Box::new(std::clone::Clone::clone(self)) } } + + #marker_impl }) .into() } diff --git a/crates/bevy_ecs/src/schedule/config.rs b/crates/bevy_ecs/src/schedule/config.rs index 15dd3f1f79933..b2252384380d0 100644 --- a/crates/bevy_ecs/src/schedule/config.rs +++ b/crates/bevy_ecs/src/schedule/config.rs @@ -9,6 +9,8 @@ use crate::{ system::{BoxedSystem, IntoSystem, System}, }; +use super::BaseSystemSet; + /// A [`SystemSet`] with scheduling metadata. pub struct SystemSetConfig { pub(super) set: BoxedSystemSet, @@ -280,7 +282,7 @@ pub trait IntoSystemConfig { fn in_set(self, set: impl SystemSet) -> Config; /// Add to the provided "base" `set`. For more information on base sets, see [`SystemSet::is_base`]. #[track_caller] - fn in_base_set(self, set: impl SystemSet) -> Config; + fn in_base_set(self, set: impl BaseSystemSet) -> Config; /// Don't add this system to the schedules's default set. fn no_default_base_set(self) -> Config; /// Run before all systems in `set`. @@ -314,7 +316,7 @@ where } #[track_caller] - fn in_base_set(self, set: impl SystemSet) -> SystemConfig { + fn in_base_set(self, set: impl BaseSystemSet) -> SystemConfig { self.into_config().in_base_set(set) } @@ -354,7 +356,7 @@ impl IntoSystemConfig<()> for BoxedSystem<(), ()> { } #[track_caller] - fn in_base_set(self, set: impl SystemSet) -> SystemConfig { + fn in_base_set(self, set: impl BaseSystemSet) -> SystemConfig { self.into_config().in_base_set(set) } @@ -477,7 +479,7 @@ where /// Add these systems to the provided "base" `set`. For more information on base sets, see [`SystemSet::is_base`]. #[track_caller] - fn in_base_set(self, set: impl SystemSet) -> SystemConfigs { + fn in_base_set(self, set: impl BaseSystemSet) -> SystemConfigs { self.into_configs().in_base_set(set) } diff --git a/crates/bevy_ecs/src/schedule/mod.rs b/crates/bevy_ecs/src/schedule/mod.rs index fa7a2b72844a9..50b01c1345918 100644 --- a/crates/bevy_ecs/src/schedule/mod.rs +++ b/crates/bevy_ecs/src/schedule/mod.rs @@ -698,13 +698,6 @@ mod tests { schedule.add_system(named_system.in_set(Base::A)); } - #[test] - #[should_panic] - fn disallow_adding_sets_to_system_with_in_base_set() { - let mut schedule = Schedule::new(); - schedule.add_system(named_system.in_base_set(Normal::X)); - } - #[test] #[should_panic] fn disallow_adding_base_sets_to_systems_with_in_set() { @@ -712,13 +705,6 @@ mod tests { schedule.add_systems((named_system, named_system).in_set(Base::A)); } - #[test] - #[should_panic] - fn disallow_adding_sets_to_systems_with_in_base_set() { - let mut schedule = Schedule::new(); - schedule.add_systems((named_system, named_system).in_base_set(Normal::X)); - } - #[test] #[should_panic] fn disallow_adding_base_sets_to_set_with_in_set() { diff --git a/crates/bevy_ecs/src/schedule/set.rs b/crates/bevy_ecs/src/schedule/set.rs index 06a162c7549b9..ad882f11c1897 100644 --- a/crates/bevy_ecs/src/schedule/set.rs +++ b/crates/bevy_ecs/src/schedule/set.rs @@ -37,6 +37,16 @@ pub trait SystemSet: DynHash + Debug + Send + Sync + 'static { fn dyn_clone(&self) -> Box; } +/// A system set that is never contained in another set. +/// Systems and other system sets may only belong to one base set. +/// +/// This should only be implemented for types that return `true` from [`SystemSet::is_base`]. +pub trait BaseSystemSet: SystemSet {} + +/// System sets that are *not* base sets. This should not be implemented for +/// any types that implement [`BaseSystemSet`]. +pub trait FreeSystemSet: SystemSet {} + impl PartialEq for dyn SystemSet { fn eq(&self, other: &Self) -> bool { self.dyn_eq(other.as_dyn_eq()) From ac4ecd24cadf4bbb373ac1ae80b0043f1068f324 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Wed, 1 Mar 2023 20:41:40 -0500 Subject: [PATCH 2/7] restrict free systems --- crates/bevy_app/src/config.rs | 6 ++--- crates/bevy_ecs/src/schedule/config.rs | 16 ++++++------- crates/bevy_ecs/src/schedule/mod.rs | 31 -------------------------- 3 files changed, 11 insertions(+), 42 deletions(-) diff --git a/crates/bevy_app/src/config.rs b/crates/bevy_app/src/config.rs index b2614d8d3be2a..3a5f30a50453b 100644 --- a/crates/bevy_app/src/config.rs +++ b/crates/bevy_app/src/config.rs @@ -1,8 +1,8 @@ use bevy_ecs::{ all_tuples, schedule::{ - BaseSystemSet, BoxedScheduleLabel, Condition, IntoSystemConfig, IntoSystemSet, - ScheduleLabel, SystemConfig, SystemConfigs, SystemSet, + BaseSystemSet, BoxedScheduleLabel, Condition, FreeSystemSet, IntoSystemConfig, + IntoSystemSet, ScheduleLabel, SystemConfig, SystemConfigs, }, }; @@ -84,7 +84,7 @@ impl IntoSystemConfig<(), Self> for SystemAppConfig { } #[track_caller] - fn in_set(self, set: impl SystemSet) -> Self { + fn in_set(self, set: impl FreeSystemSet) -> Self { let Self { system, schedule } = self; Self { system: system.in_set(set), diff --git a/crates/bevy_ecs/src/schedule/config.rs b/crates/bevy_ecs/src/schedule/config.rs index b2252384380d0..616f4ff0a0c0e 100644 --- a/crates/bevy_ecs/src/schedule/config.rs +++ b/crates/bevy_ecs/src/schedule/config.rs @@ -9,7 +9,7 @@ use crate::{ system::{BoxedSystem, IntoSystem, System}, }; -use super::BaseSystemSet; +use super::{BaseSystemSet, FreeSystemSet}; /// A [`SystemSet`] with scheduling metadata. pub struct SystemSetConfig { @@ -88,7 +88,7 @@ pub trait IntoSystemSetConfig { fn into_config(self) -> SystemSetConfig; /// Add to the provided `set`. #[track_caller] - fn in_set(self, set: impl SystemSet) -> SystemSetConfig; + fn in_set(self, set: impl FreeSystemSet) -> SystemSetConfig; /// Add to the provided "base" `set`. For more information on base sets, see [`SystemSet::is_base`]. #[track_caller] fn in_base_set(self, set: impl SystemSet) -> SystemSetConfig; @@ -117,7 +117,7 @@ impl IntoSystemSetConfig for S { } #[track_caller] - fn in_set(self, set: impl SystemSet) -> SystemSetConfig { + fn in_set(self, set: impl FreeSystemSet) -> SystemSetConfig { self.into_config().in_set(set) } @@ -157,7 +157,7 @@ impl IntoSystemSetConfig for BoxedSystemSet { } #[track_caller] - fn in_set(self, set: impl SystemSet) -> SystemSetConfig { + fn in_set(self, set: impl FreeSystemSet) -> SystemSetConfig { self.into_config().in_set(set) } @@ -279,7 +279,7 @@ pub trait IntoSystemConfig { fn into_config(self) -> Config; /// Add to `set` membership. #[track_caller] - fn in_set(self, set: impl SystemSet) -> Config; + fn in_set(self, set: impl FreeSystemSet) -> Config; /// Add to the provided "base" `set`. For more information on base sets, see [`SystemSet::is_base`]. #[track_caller] fn in_base_set(self, set: impl BaseSystemSet) -> Config; @@ -311,7 +311,7 @@ where } #[track_caller] - fn in_set(self, set: impl SystemSet) -> SystemConfig { + fn in_set(self, set: impl FreeSystemSet) -> SystemConfig { self.into_config().in_set(set) } @@ -351,7 +351,7 @@ impl IntoSystemConfig<()> for BoxedSystem<(), ()> { } #[track_caller] - fn in_set(self, set: impl SystemSet) -> SystemConfig { + fn in_set(self, set: impl FreeSystemSet) -> SystemConfig { self.into_config().in_set(set) } @@ -473,7 +473,7 @@ where /// Add these systems to the provided `set`. #[track_caller] - fn in_set(self, set: impl SystemSet) -> SystemConfigs { + fn in_set(self, set: impl FreeSystemSet) -> SystemConfigs { self.into_configs().in_set(set) } diff --git a/crates/bevy_ecs/src/schedule/mod.rs b/crates/bevy_ecs/src/schedule/mod.rs index 50b01c1345918..3bbab7ca5d84f 100644 --- a/crates/bevy_ecs/src/schedule/mod.rs +++ b/crates/bevy_ecs/src/schedule/mod.rs @@ -567,16 +567,6 @@ mod tests { )); } - #[test] - #[should_panic] - fn in_system_type_set() { - fn foo() {} - fn bar() {} - - let mut schedule = Schedule::new(); - schedule.add_system(foo.in_set(bar.into_system_set())); - } - #[test] #[should_panic] fn configure_system_type_set() { @@ -691,27 +681,6 @@ mod tests { Z, } - #[test] - #[should_panic] - fn disallow_adding_base_sets_to_system_with_in_set() { - let mut schedule = Schedule::new(); - schedule.add_system(named_system.in_set(Base::A)); - } - - #[test] - #[should_panic] - fn disallow_adding_base_sets_to_systems_with_in_set() { - let mut schedule = Schedule::new(); - schedule.add_systems((named_system, named_system).in_set(Base::A)); - } - - #[test] - #[should_panic] - fn disallow_adding_base_sets_to_set_with_in_set() { - let mut schedule = Schedule::new(); - schedule.configure_set(Normal::Y.in_set(Base::A)); - } - #[test] #[should_panic] fn disallow_adding_sets_to_set_with_in_base_set() { From a517cd736f336e7e0b9f42fc255453ae99839f69 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Wed, 1 Mar 2023 20:44:12 -0500 Subject: [PATCH 3/7] restrict base sets more --- crates/bevy_ecs/src/schedule/config.rs | 8 ++++---- crates/bevy_ecs/src/schedule/mod.rs | 15 --------------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/crates/bevy_ecs/src/schedule/config.rs b/crates/bevy_ecs/src/schedule/config.rs index 616f4ff0a0c0e..923848fe6bfec 100644 --- a/crates/bevy_ecs/src/schedule/config.rs +++ b/crates/bevy_ecs/src/schedule/config.rs @@ -91,7 +91,7 @@ pub trait IntoSystemSetConfig { fn in_set(self, set: impl FreeSystemSet) -> SystemSetConfig; /// Add to the provided "base" `set`. For more information on base sets, see [`SystemSet::is_base`]. #[track_caller] - fn in_base_set(self, set: impl SystemSet) -> SystemSetConfig; + fn in_base_set(self, set: impl BaseSystemSet) -> SystemSetConfig; /// Add this set to the schedules's default base set. fn in_default_base_set(self) -> SystemSetConfig; /// Run before all systems in `set`. @@ -122,7 +122,7 @@ impl IntoSystemSetConfig for S { } #[track_caller] - fn in_base_set(self, set: impl SystemSet) -> SystemSetConfig { + fn in_base_set(self, set: impl BaseSystemSet) -> SystemSetConfig { self.into_config().in_base_set(set) } @@ -162,7 +162,7 @@ impl IntoSystemSetConfig for BoxedSystemSet { } #[track_caller] - fn in_base_set(self, set: impl SystemSet) -> SystemSetConfig { + fn in_base_set(self, set: impl BaseSystemSet) -> SystemSetConfig { self.into_config().in_base_set(set) } @@ -665,7 +665,7 @@ where /// Add these system sets to the provided "base" `set`. For more information on base sets, see [`SystemSet::is_base`]. #[track_caller] - fn in_base_set(self, set: impl SystemSet) -> SystemSetConfigs { + fn in_base_set(self, set: impl BaseSystemSet) -> SystemSetConfigs { self.into_configs().in_base_set(set) } diff --git a/crates/bevy_ecs/src/schedule/mod.rs b/crates/bevy_ecs/src/schedule/mod.rs index 3bbab7ca5d84f..448a8d55fe32a 100644 --- a/crates/bevy_ecs/src/schedule/mod.rs +++ b/crates/bevy_ecs/src/schedule/mod.rs @@ -678,14 +678,6 @@ mod tests { enum Normal { X, Y, - Z, - } - - #[test] - #[should_panic] - fn disallow_adding_sets_to_set_with_in_base_set() { - let mut schedule = Schedule::new(); - schedule.configure_set(Normal::Y.in_base_set(Normal::X)); } #[test] @@ -695,13 +687,6 @@ mod tests { schedule.configure_sets((Normal::X, Normal::Y).in_set(Base::A)); } - #[test] - #[should_panic] - fn disallow_adding_sets_to_sets_with_in_base_set() { - let mut schedule = Schedule::new(); - schedule.configure_sets((Normal::X, Normal::Y).in_base_set(Normal::Z)); - } - #[test] #[should_panic] fn disallow_adding_base_sets_to_sets() { From 497b77fcd986a5b535e6e479a2f0a0d769aeee44 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Wed, 1 Mar 2023 20:45:21 -0500 Subject: [PATCH 4/7] restrict free sets more --- crates/bevy_ecs/src/schedule/config.rs | 2 +- crates/bevy_ecs/src/schedule/mod.rs | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/crates/bevy_ecs/src/schedule/config.rs b/crates/bevy_ecs/src/schedule/config.rs index 923848fe6bfec..899985fb22b43 100644 --- a/crates/bevy_ecs/src/schedule/config.rs +++ b/crates/bevy_ecs/src/schedule/config.rs @@ -659,7 +659,7 @@ where /// Add these system sets to the provided `set`. #[track_caller] - fn in_set(self, set: impl SystemSet) -> SystemSetConfigs { + fn in_set(self, set: impl FreeSystemSet) -> SystemSetConfigs { self.into_configs().in_set(set) } diff --git a/crates/bevy_ecs/src/schedule/mod.rs b/crates/bevy_ecs/src/schedule/mod.rs index 448a8d55fe32a..f886d815d1d37 100644 --- a/crates/bevy_ecs/src/schedule/mod.rs +++ b/crates/bevy_ecs/src/schedule/mod.rs @@ -680,13 +680,6 @@ mod tests { Y, } - #[test] - #[should_panic] - fn disallow_adding_base_sets_to_sets_with_in_set() { - let mut schedule = Schedule::new(); - schedule.configure_sets((Normal::X, Normal::Y).in_set(Base::A)); - } - #[test] #[should_panic] fn disallow_adding_base_sets_to_sets() { From 7c98eb16dde0937b11c232688c038ff19a8b6d97 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Wed, 1 Mar 2023 20:52:33 -0500 Subject: [PATCH 5/7] fix a benchmark --- benches/benches/bevy_ecs/scheduling/schedule.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/benches/benches/bevy_ecs/scheduling/schedule.rs b/benches/benches/bevy_ecs/scheduling/schedule.rs index 18a2699becad9..3117c0fff2bc7 100644 --- a/benches/benches/bevy_ecs/scheduling/schedule.rs +++ b/benches/benches/bevy_ecs/scheduling/schedule.rs @@ -63,16 +63,11 @@ pub fn build_schedule(criterion: &mut Criterion) { // Use multiple different kinds of label to ensure that dynamic dispatch // doesn't somehow get optimized away. - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + #[derive(SystemSet, Debug, Clone, Copy, PartialEq, Eq, Hash)] struct NumSet(usize); - #[derive(Debug, Clone, Copy, SystemSet, PartialEq, Eq, Hash)] - struct DummySet; - impl SystemSet for NumSet { - fn dyn_clone(&self) -> Box { - Box::new(self.clone()) - } - } + #[derive(SystemSet, Debug, Clone, Copy, PartialEq, Eq, Hash)] + struct DummySet; let mut group = criterion.benchmark_group("build_schedule"); group.warm_up_time(std::time::Duration::from_millis(500)); From 6c1af1d7a8f9672a84062eefcc4a075f904a0413 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Wed, 1 Mar 2023 21:05:35 -0500 Subject: [PATCH 6/7] use a descriptive variable name --- crates/bevy_ecs/macros/src/set.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_ecs/macros/src/set.rs b/crates/bevy_ecs/macros/src/set.rs index cf4134cfc5b7d..5db4395ed08a3 100644 --- a/crates/bevy_ecs/macros/src/set.rs +++ b/crates/bevy_ecs/macros/src/set.rs @@ -13,12 +13,12 @@ pub static BASE_ATTRIBUTE_NAME: &str = "base"; /// - `trait_path`: The [`syn::Path`] to the set trait pub fn derive_set(input: syn::DeriveInput, trait_path: &syn::Path) -> TokenStream { let mut base_trait_path = trait_path.clone(); - let x = &mut base_trait_path.segments.last_mut().unwrap().ident; - *x = format_ident!("Base{x}"); + let ident = &mut base_trait_path.segments.last_mut().unwrap().ident; + *ident = format_ident!("Base{x}"); let mut free_trait_path = trait_path.clone(); - let x = &mut free_trait_path.segments.last_mut().unwrap().ident; - *x = format_ident!("Free{x}"); + let ident = &mut free_trait_path.segments.last_mut().unwrap().ident; + *ident = format_ident!("Free{x}"); let ident = input.ident; From b3a42d031fc2ad84df84bf41d4f40bd7e60319fb Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Wed, 1 Mar 2023 21:07:12 -0500 Subject: [PATCH 7/7] f2 betrayed me --- crates/bevy_ecs/macros/src/set.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/macros/src/set.rs b/crates/bevy_ecs/macros/src/set.rs index 5db4395ed08a3..054735c858653 100644 --- a/crates/bevy_ecs/macros/src/set.rs +++ b/crates/bevy_ecs/macros/src/set.rs @@ -14,11 +14,11 @@ pub static BASE_ATTRIBUTE_NAME: &str = "base"; pub fn derive_set(input: syn::DeriveInput, trait_path: &syn::Path) -> TokenStream { let mut base_trait_path = trait_path.clone(); let ident = &mut base_trait_path.segments.last_mut().unwrap().ident; - *ident = format_ident!("Base{x}"); + *ident = format_ident!("Base{ident}"); let mut free_trait_path = trait_path.clone(); let ident = &mut free_trait_path.segments.last_mut().unwrap().ident; - *ident = format_ident!("Free{x}"); + *ident = format_ident!("Free{ident}"); let ident = input.ident;