From 8e65bcdcc5e869207b5ffab44e84e570353cf2d4 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Wed, 4 Jan 2023 23:25:36 +0000 Subject: [PATCH] Allow `SystemParam`s with private fields (#7056) # Objective - Fix #4200 Currently, `#[derive(SystemParam)]` publicly exposes each field type, which makes it impossible to encapsulate private fields. ## Solution Previously, the fields were leaked because they were used as an input generic type to the macro-generated `SystemParam::State` struct. That type has been changed to store its state in a field with a specific type, instead of a generic type. --- ## Changelog - Fixed a bug that caused `#[derive(SystemParam)]` to leak the types of private fields. --- crates/bevy_ecs/macros/src/lib.rs | 31 ++++++++-------------- crates/bevy_ecs/src/system/system_param.rs | 6 +++++ 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index 1a0d2f0c4770d..b697c9d0ba497 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -411,7 +411,7 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream { } } - let (_impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let lifetimeless_generics: Vec<_> = generics .params @@ -441,12 +441,6 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream { } } - let mut punctuated_type_generic_idents = Punctuated::<_, Token![,]>::new(); - punctuated_type_generic_idents.extend(lifetimeless_generics.iter().filter_map(|g| match g { - GenericParam::Type(g) => Some(&g.ident), - _ => None, - })); - let mut punctuated_generic_idents = Punctuated::<_, Token![,]>::new(); punctuated_generic_idents.extend(lifetimeless_generics.iter().map(|g| match g { GenericParam::Type(g) => &g.ident, @@ -485,24 +479,21 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream { // The struct can still be accessed via SystemParam::State, e.g. EventReaderState can be accessed via // as SystemParam>::State const _: () = { - impl<'w, 's, #punctuated_generics> #path::system::SystemParam for #struct_name #ty_generics #where_clause { - type State = State<'w, 's, #punctuated_generic_idents>; + impl #impl_generics #path::system::SystemParam for #struct_name #ty_generics #where_clause { + type State = FetchState<'static, 'static, #punctuated_generic_idents>; } #[doc(hidden)] - type State<'w, 's, #punctuated_generics_no_bounds> = FetchState< - (#(<#tuple_types as #path::system::SystemParam>::State,)*), - #punctuated_generic_idents - >; - - #[doc(hidden)] - #state_struct_visibility struct FetchState { - state: TSystemParamState, - marker: std::marker::PhantomData(#punctuated_type_generic_idents)> + #state_struct_visibility struct FetchState <'w, 's, #(#lifetimeless_generics,)*> { + state: (#(<#tuple_types as #path::system::SystemParam>::State,)*), + marker: std::marker::PhantomData<( + <#path::prelude::Query<'w, 's, ()> as #path::system::SystemParam>::State, + #(fn() -> #ignored_field_types,)* + )>, } - unsafe impl<'__w, '__s, #punctuated_generics> #path::system::SystemParamState for - State<'__w, '__s, #punctuated_generic_idents> + unsafe impl<#punctuated_generics> #path::system::SystemParamState for + FetchState<'static, 'static, #punctuated_generic_idents> #where_clause { type Item<'w, 's> = #struct_name #ty_generics; diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 8c9ff2ddfa01b..7b09919698a33 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -1809,4 +1809,10 @@ mod tests { Res<'w, R>, Local<'s, L>, ); + + #[derive(Resource)] + struct PrivateResource; + + #[derive(SystemParam)] + pub struct EncapsulatedParam<'w>(Res<'w, PrivateResource>); }