@@ -20,8 +20,8 @@ use proc_macro::TokenStream;
2020use proc_macro2:: { Ident , Span } ;
2121use quote:: { format_ident, quote, ToTokens } ;
2222use syn:: {
23- parse_macro_input, parse_quote, punctuated:: Punctuated , token:: Comma , ConstParam , Data ,
24- DeriveInput , GenericParam , TypeParam ,
23+ parse_macro_input, parse_quote, punctuated:: Punctuated , token:: Comma , visit_mut :: VisitMut ,
24+ ConstParam , Data , DeriveInput , GenericParam , TypeParam ,
2525} ;
2626
2727enum BundleFieldKind {
@@ -229,6 +229,16 @@ pub fn derive_map_entities(input: TokenStream) -> TokenStream {
229229 } )
230230}
231231
232+ struct LifetimeEraser {
233+ erased_ident : Ident ,
234+ }
235+
236+ impl VisitMut for LifetimeEraser {
237+ fn visit_lifetime_mut ( & mut self , i : & mut syn:: Lifetime ) {
238+ i. ident = self . erased_ident . clone ( ) ;
239+ }
240+ }
241+
232242/// Implement `SystemParam` to use a struct as a parameter in a system
233243#[ proc_macro_derive( SystemParam , attributes( system_param) ) ]
234244pub fn derive_system_param ( input : TokenStream ) -> TokenStream {
@@ -240,6 +250,7 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
240250 Err ( e) => e. into_compile_error ( ) . into ( ) ,
241251 }
242252}
253+
243254fn derive_system_param_impl (
244255 token_stream : TokenStream ,
245256 ast : DeriveInput ,
@@ -253,6 +264,17 @@ fn derive_system_param_impl(
253264 . collect :: < Vec < _ > > ( ) ;
254265 let field_members = fields. members ( ) . collect :: < Vec < _ > > ( ) ;
255266 let field_types = fields. iter ( ) . map ( |f| & f. ty ) . collect :: < Vec < _ > > ( ) ;
267+ let shadowed_lifetime_field_types = fields
268+ . iter ( )
269+ . map ( |f| {
270+ let mut ty = f. ty . clone ( ) ;
271+ let mut eraser = LifetimeEraser {
272+ erased_ident : format_ident ! ( "static" ) ,
273+ } ;
274+ syn:: visit_mut:: visit_type_mut ( & mut eraser, & mut ty) ;
275+ ty
276+ } )
277+ . collect :: < Vec < _ > > ( ) ;
256278
257279 let field_validation_names = fields. members ( ) . map ( |m| format ! ( "::{}" , quote! { #m } ) ) ;
258280 let mut field_validation_messages = Vec :: with_capacity ( fields. len ( ) ) ;
@@ -356,6 +378,18 @@ fn derive_system_param_impl(
356378 . push ( syn:: parse_quote!( #field_type: #path:: system:: ReadOnlySystemParam ) ) ;
357379 }
358380
381+ // Create a where clause for the `ReborrowSystemParam` impl.
382+ // Ensure that each field implements `ReborrowSystemParam`.
383+ let mut reborrow_generics = generics. clone ( ) ;
384+ let reborrow_where_clause = reborrow_generics. make_where_clause ( ) ;
385+ for ( shadowed_lifetime_field_type, field_type) in
386+ shadowed_lifetime_field_types. iter ( ) . zip ( & field_types)
387+ {
388+ reborrow_where_clause
389+ . predicates
390+ . push ( syn:: parse_quote!( for <' w, ' s> #shadowed_lifetime_field_type: #path:: system:: ReborrowSystemParam <Item <' w, ' s> = #field_type>) ) ;
391+ }
392+
359393 let fields_alias =
360394 ensure_no_collision ( format_ident ! ( "__StructFieldsAlias" ) , token_stream. clone ( ) ) ;
361395
@@ -482,6 +516,19 @@ fn derive_system_param_impl(
482516 // Safety: Each field is `ReadOnlySystemParam`, so this can only read from the `World`
483517 unsafe impl <' w, ' s, #punctuated_generics> #path:: system:: ReadOnlySystemParam for #struct_name #ty_generics #read_only_where_clause { }
484518
519+ impl <#punctuated_generics> #path:: system:: ReborrowSystemParam for #struct_name <#( #shadowed_lifetimes, ) * #punctuated_generic_idents> #reborrow_where_clause {
520+ fn reborrow<' wlong: ' short, ' slong: ' short, ' short>(
521+ item: & ' short mut Self :: Item <' wlong, ' slong>,
522+ ) -> Self :: Item <' short, ' short> {
523+ #(
524+ let #field_locals = <#shadowed_lifetime_field_types as #path:: system:: ReborrowSystemParam >:: reborrow( & mut item. #field_members) ;
525+ ) *
526+ #struct_name {
527+ #( #field_members: #field_locals, ) *
528+ }
529+ }
530+ }
531+
485532 #builder_impl
486533 } ;
487534
0 commit comments