From 852733959d42dcfa73665005c5916469fe8ccee5 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Fri, 10 Mar 2023 17:55:56 -0500 Subject: [PATCH 1/3] make `BaseSystemSet` and `FreeSystemSet` mutually exclusive --- crates/bevy_ecs/macros/src/set.rs | 18 ++++++++++-------- crates/bevy_ecs/src/schedule/set.rs | 24 ++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/crates/bevy_ecs/macros/src/set.rs b/crates/bevy_ecs/macros/src/set.rs index 054735c858653..db2a0e6fb0745 100644 --- a/crates/bevy_ecs/macros/src/set.rs +++ b/crates/bevy_ecs/macros/src/set.rs @@ -2,6 +2,8 @@ use proc_macro::TokenStream; use quote::{format_ident, quote, ToTokens}; use syn::parse::{Parse, ParseStream}; +use crate::bevy_ecs_path; + pub static SYSTEM_SET_ATTRIBUTE_NAME: &str = "system_set"; pub static BASE_ATTRIBUTE_NAME: &str = "base"; @@ -12,6 +14,8 @@ 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 path = bevy_ecs_path(); + let mut base_trait_path = trait_path.clone(); let ident = &mut base_trait_path.segments.last_mut().unwrap().ident; *ident = format_ident!("Base{ident}"); @@ -73,14 +77,10 @@ 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 {} - } + let kind = if is_base { + quote! { #path::schedule::Base } } else { - quote! { - impl #impl_generics #free_trait_path for #ident #ty_generics #where_clause {} - } + quote! { #path::schedule::Free } }; (quote! { @@ -94,7 +94,9 @@ pub fn derive_set(input: syn::DeriveInput, trait_path: &syn::Path) -> TokenStrea } } - #marker_impl + impl #impl_generics #path::schedule::KindedSystemSet for #ident #ty_generics #where_clause { + type Kind = #kind; + } }) .into() } diff --git a/crates/bevy_ecs/src/schedule/set.rs b/crates/bevy_ecs/src/schedule/set.rs index 23058a3de9fbc..ebcc69691aa2c 100644 --- a/crates/bevy_ecs/src/schedule/set.rs +++ b/crates/bevy_ecs/src/schedule/set.rs @@ -13,6 +13,10 @@ use crate::system::{ define_boxed_label!(ScheduleLabel); +mod sealed { + pub trait SystemSetKind {} +} + pub type BoxedSystemSet = Box; pub type BoxedScheduleLabel = Box; @@ -37,19 +41,35 @@ pub trait SystemSet: DynHash + Debug + Send + Sync + 'static { fn dyn_clone(&self) -> Box; } +pub trait KindedSystemSet: SystemSet { + type Kind: sealed::SystemSetKind; +} + +pub struct Base; + +impl sealed::SystemSetKind for Base {} + /// A marker trait for `SystemSet` types where [`is_base`] returns `true`. /// This should only be implemented for types that satisfy this requirement. /// It is automatically implemented for base set types by `#[derive(SystemSet)]`. /// /// [`is_base`]: SystemSet::is_base -pub trait BaseSystemSet: SystemSet {} +pub trait BaseSystemSet: KindedSystemSet {} + +impl> BaseSystemSet for T {} + +pub struct Free; + +impl sealed::SystemSetKind for Free {} /// A marker trait for `SystemSet` types where [`is_base`] returns `false`. /// This should only be implemented for types that satisfy this requirement. /// It is automatically implemented for non-base set types by `#[derive(SystemSet)]`. /// /// [`is_base`]: SystemSet::is_base -pub trait FreeSystemSet: SystemSet {} +pub trait FreeSystemSet: KindedSystemSet {} + +impl> FreeSystemSet for T {} impl PartialEq for dyn SystemSet { fn eq(&self, other: &Self) -> bool { From 3c98cad86f196e6716d97fc6d76500d12d1f992a Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Fri, 10 Mar 2023 18:17:25 -0500 Subject: [PATCH 2/3] improve the API --- crates/bevy_ecs/macros/src/set.rs | 4 +-- crates/bevy_ecs/src/schedule/set.rs | 47 +++++++++++++++-------------- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/crates/bevy_ecs/macros/src/set.rs b/crates/bevy_ecs/macros/src/set.rs index db2a0e6fb0745..c55b42d3e4733 100644 --- a/crates/bevy_ecs/macros/src/set.rs +++ b/crates/bevy_ecs/macros/src/set.rs @@ -78,9 +78,9 @@ pub fn derive_set(input: syn::DeriveInput, trait_path: &syn::Path) -> TokenStrea ); let kind = if is_base { - quote! { #path::schedule::Base } + quote! { #path::schedule::BaseSystemSetMarker } } else { - quote! { #path::schedule::Free } + quote! { #path::schedule::FreeSystemSetMarker } }; (quote! { diff --git a/crates/bevy_ecs/src/schedule/set.rs b/crates/bevy_ecs/src/schedule/set.rs index ebcc69691aa2c..45ad281a75319 100644 --- a/crates/bevy_ecs/src/schedule/set.rs +++ b/crates/bevy_ecs/src/schedule/set.rs @@ -13,10 +13,6 @@ use crate::system::{ define_boxed_label!(ScheduleLabel); -mod sealed { - pub trait SystemSetKind {} -} - pub type BoxedSystemSet = Box; pub type BoxedScheduleLabel = Box; @@ -41,35 +37,42 @@ pub trait SystemSet: DynHash + Debug + Send + Sync + 'static { fn dyn_clone(&self) -> Box; } +/// Supertrait for [`BaseSystemSet`] and [`FreeSystemSet`]. pub trait KindedSystemSet: SystemSet { + /// Whether this is a [`BaseSystemSet`] or [`FreeSystemSet`]. + /// + /// If [`SystemSet::is_base`] returns true, this should be `BaseSystemSetMarker`. + /// If it returns `false`, this should be `FreeSystemSetMarker`. type Kind: sealed::SystemSetKind; } -pub struct Base; - -impl sealed::SystemSetKind for Base {} +mod sealed { + pub trait SystemSetKind {} +} -/// A marker trait for `SystemSet` types where [`is_base`] returns `true`. -/// This should only be implemented for types that satisfy this requirement. -/// It is automatically implemented for base set types by `#[derive(SystemSet)]`. -/// -/// [`is_base`]: SystemSet::is_base -pub trait BaseSystemSet: KindedSystemSet {} +/// Marker for [`BaseSystemSet`] when using [`KindedSystemSet`]. +pub struct BaseSystemSetMarker; -impl> BaseSystemSet for T {} +/// Marker for [`FreeSystemSet`] when using [`KindedSystemSet`]. +pub struct FreeSystemSetMarker; -pub struct Free; +impl sealed::SystemSetKind for BaseSystemSetMarker {} +impl sealed::SystemSetKind for FreeSystemSetMarker {} -impl sealed::SystemSetKind for Free {} +/// A system set that is never contained in another set. +/// Systems and other system sets may only belong to one base set. +/// +/// [`SystemSet::is_base`] always returns `true` for these types. +pub trait BaseSystemSet: KindedSystemSet {} -/// A marker trait for `SystemSet` types where [`is_base`] returns `false`. -/// This should only be implemented for types that satisfy this requirement. -/// It is automatically implemented for non-base set types by `#[derive(SystemSet)]`. +/// System sets that are not base sets. +/// They have no extra restrictions on ordering in the schedule. /// -/// [`is_base`]: SystemSet::is_base -pub trait FreeSystemSet: KindedSystemSet {} +/// [`SystemSet::is_base`] always returns `false` for these types. +pub trait FreeSystemSet: KindedSystemSet {} -impl> FreeSystemSet for T {} +impl> BaseSystemSet for T {} +impl> FreeSystemSet for T {} impl PartialEq for dyn SystemSet { fn eq(&self, other: &Self) -> bool { From 0e62836d3f8f6dda9e830a778b96bf2669b38430 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Fri, 10 Mar 2023 18:19:06 -0500 Subject: [PATCH 3/3] remove unused variables --- crates/bevy_ecs/macros/src/set.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/crates/bevy_ecs/macros/src/set.rs b/crates/bevy_ecs/macros/src/set.rs index c55b42d3e4733..5baff378c5759 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::{format_ident, quote, ToTokens}; +use quote::{quote, ToTokens}; use syn::parse::{Parse, ParseStream}; use crate::bevy_ecs_path; @@ -16,14 +16,6 @@ pub static BASE_ATTRIBUTE_NAME: &str = "base"; pub fn derive_set(input: syn::DeriveInput, trait_path: &syn::Path) -> TokenStream { let path = bevy_ecs_path(); - let mut base_trait_path = trait_path.clone(); - let ident = &mut base_trait_path.segments.last_mut().unwrap().ident; - *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{ident}"); - let ident = input.ident; let mut is_base = false;