Skip to content

Commit

Permalink
Allow SystemParams with private fields (#7056)
Browse files Browse the repository at this point in the history
# 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.
  • Loading branch information
JoJoJet committed Jan 4, 2023
1 parent 9ff111e commit 8ca3d04
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 20 deletions.
31 changes: 11 additions & 20 deletions crates/bevy_ecs/macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
// <EventReader<'static, 'static, T> 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 <TSystemParamState, #punctuated_generics> {
state: TSystemParamState,
marker: std::marker::PhantomData<fn()->(#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;

Expand Down
6 changes: 6 additions & 0 deletions crates/bevy_ecs/src/system/system_param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>);
}

0 comments on commit 8ca3d04

Please sign in to comment.