diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index 6936ca4aff3a6..bc843cd32e4ab 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -20,8 +20,8 @@ use proc_macro::TokenStream; use proc_macro2::{Ident, Span}; use quote::{format_ident, quote, ToTokens}; use syn::{ - parse_macro_input, parse_quote, punctuated::Punctuated, token::Comma, ConstParam, Data, - DeriveInput, GenericParam, TypeParam, + parse_macro_input, parse_quote, punctuated::Punctuated, token::Comma, visit_mut::VisitMut, + ConstParam, Data, DeriveInput, GenericParam, TypeParam, }; enum BundleFieldKind { @@ -229,6 +229,16 @@ pub fn derive_map_entities(input: TokenStream) -> TokenStream { }) } +struct LifetimeEraser { + erased_ident: Ident, +} + +impl VisitMut for LifetimeEraser { + fn visit_lifetime_mut(&mut self, i: &mut syn::Lifetime) { + i.ident = self.erased_ident.clone(); + } +} + /// Implement `SystemParam` to use a struct as a parameter in a system #[proc_macro_derive(SystemParam, attributes(system_param))] pub fn derive_system_param(input: TokenStream) -> TokenStream { @@ -240,6 +250,7 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream { Err(e) => e.into_compile_error().into(), } } + fn derive_system_param_impl( token_stream: TokenStream, ast: DeriveInput, @@ -253,6 +264,17 @@ fn derive_system_param_impl( .collect::>(); let field_members = fields.members().collect::>(); let field_types = fields.iter().map(|f| &f.ty).collect::>(); + let shadowed_lifetime_field_types = fields + .iter() + .map(|f| { + let mut ty = f.ty.clone(); + let mut eraser = LifetimeEraser { + erased_ident: format_ident!("static"), + }; + syn::visit_mut::visit_type_mut(&mut eraser, &mut ty); + ty + }) + .collect::>(); let field_validation_names = fields.members().map(|m| format!("::{}", quote! { #m })); let mut field_validation_messages = Vec::with_capacity(fields.len()); @@ -431,6 +453,17 @@ fn derive_system_param_impl( type State = #state_struct_name<#punctuated_generic_idents>; type Item<'w, 's> = #struct_name #ty_generics; + fn reborrow<'a>( + item: &'a mut Self::Item<'_, '_>, + ) -> Self::Item<'a, 'a> { + #( + let #field_locals = <#shadowed_lifetime_field_types as #path::system::SystemParam>::reborrow(&mut item.#field_members); + )* + #struct_name { + #(#field_members: #field_locals,)* + } + } + fn init_state(world: &mut #path::world::World) -> Self::State { #state_struct_name { state: <#fields_alias::<'_, '_, #punctuated_generic_idents> as #path::system::SystemParam>::init_state(world), diff --git a/crates/bevy_ecs/macros/src/query_data.rs b/crates/bevy_ecs/macros/src/query_data.rs index a91dd193e51c1..ea9ed75a196d7 100644 --- a/crates/bevy_ecs/macros/src/query_data.rs +++ b/crates/bevy_ecs/macros/src/query_data.rs @@ -247,6 +247,16 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream { } } + fn reborrow<'a>( + item: &'a mut Self::Item<'_, '_>, + ) -> Self::Item<'a, 'a> { + #read_only_item_struct_name { + #( + #field_members: <#read_only_field_types as #path::query::QueryData>::reborrow(&mut item.#field_members), + )* + } + } + fn provide_extra_access( state: &mut Self::State, access: &mut #path::query::Access, @@ -318,6 +328,16 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream { } } + fn reborrow<'a>( + item: &'a mut Self::Item<'_, '_>, + ) -> Self::Item<'a, 'a> { + #item_struct_name { + #( + #field_members: <#field_types as #path::query::QueryData>::reborrow(&mut item.#field_members), + )* + } + } + fn provide_extra_access( state: &mut Self::State, access: &mut #path::query::Access, diff --git a/crates/bevy_ecs/src/change_detection/params.rs b/crates/bevy_ecs/src/change_detection/params.rs index e66d62864a604..2fa833227cca5 100644 --- a/crates/bevy_ecs/src/change_detection/params.rs +++ b/crates/bevy_ecs/src/change_detection/params.rs @@ -11,7 +11,7 @@ use core::{ /// Used by immutable query parameters (such as [`Ref`] and [`Res`]) /// to store immutable access to the [`Tick`]s of a single component or resource. -#[derive(Clone)] +#[derive(Clone, Copy)] pub(crate) struct ComponentTicksRef<'w> { pub(crate) added: &'w Tick, pub(crate) changed: &'w Tick, @@ -113,7 +113,7 @@ impl<'w, T: Resource> Res<'w, T> { pub fn clone(this: &Self) -> Self { Self { value: this.value, - ticks: this.ticks.clone(), + ticks: this.ticks, } } @@ -231,6 +231,14 @@ pub struct NonSend<'w, T: ?Sized + 'static> { pub(crate) ticks: ComponentTicksRef<'w>, } +impl<'w, T: ?Sized + 'static> Clone for NonSend<'w, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'w, T: ?Sized + 'static> Copy for NonSend<'w, T> {} + change_detection_impl!(NonSend<'w, T>, T,); impl_debug!(NonSend<'w, T>,); @@ -362,6 +370,14 @@ impl<'w, T: ?Sized> Ref<'w, T> { } } +impl<'w, T: ?Sized> Clone for Ref<'w, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'w, T: ?Sized> Copy for Ref<'w, T> {} + impl<'w, 'a, T> IntoIterator for &'a Ref<'w, T> where &'a T: IntoIterator, diff --git a/crates/bevy_ecs/src/change_detection/traits.rs b/crates/bevy_ecs/src/change_detection/traits.rs index 30025551ada58..58b4dc342366e 100644 --- a/crates/bevy_ecs/src/change_detection/traits.rs +++ b/crates/bevy_ecs/src/change_detection/traits.rs @@ -449,12 +449,16 @@ macro_rules! impl_methods { self.value } - /// Returns a `Mut<>` with a smaller lifetime. + /// Returns a ` + #[doc = stringify!($name)] + /// <>` with a smaller lifetime. /// This is useful if you have `&mut #[doc = stringify!($name)] - /// `, but you need a `Mut`. - pub fn reborrow(&mut self) -> Mut<'_, $target> { - Mut { + /// `, but you need a ` + #[doc = stringify!($name)] + /// `. + pub fn reborrow(&mut self) -> $name<'_, $target> { + $name { value: self.value, ticks: ComponentTicksMut { added: self.ticks.added, diff --git a/crates/bevy_ecs/src/lifecycle.rs b/crates/bevy_ecs/src/lifecycle.rs index adfb660e8b38a..26535d3769403 100644 --- a/crates/bevy_ecs/src/lifecycle.rs +++ b/crates/bevy_ecs/src/lifecycle.rs @@ -614,13 +614,17 @@ impl<'w, 's, T: Component> RemovedComponents<'w, 's, T> { } // SAFETY: Only reads World removed component messages -unsafe impl<'a> ReadOnlySystemParam for &'a RemovedComponentMessages {} +unsafe impl ReadOnlySystemParam for &'_ RemovedComponentMessages {} // SAFETY: no component value access. -unsafe impl<'a> SystemParam for &'a RemovedComponentMessages { +unsafe impl SystemParam for &'_ RemovedComponentMessages { type State = (); type Item<'w, 's> = &'w RemovedComponentMessages; + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + fn init_state(_world: &mut World) -> Self::State {} fn init_access( diff --git a/crates/bevy_ecs/src/query/fetch.rs b/crates/bevy_ecs/src/query/fetch.rs index d0b191513e8ed..40b25fc630ac5 100644 --- a/crates/bevy_ecs/src/query/fetch.rs +++ b/crates/bevy_ecs/src/query/fetch.rs @@ -309,6 +309,9 @@ pub unsafe trait QueryData: WorldQuery { item: Self::Item<'wlong, 's>, ) -> Self::Item<'wshort, 's>; + /// Returns a `QueryData` item with a smaller lifetime. + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a>; + /// Offers additional access above what we requested in `update_component_access`. /// Implementations may add additional access that is a subset of `available_access` /// and does not conflict with anything in `access`, @@ -449,6 +452,10 @@ unsafe impl QueryData for Entity { item } + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + #[inline(always)] unsafe fn fetch<'w, 's>( _state: &'s Self::State, @@ -545,6 +552,10 @@ unsafe impl QueryData for EntityLocation { item } + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + #[inline(always)] unsafe fn fetch<'w, 's>( _state: &'s Self::State, @@ -715,6 +726,10 @@ unsafe impl QueryData for SpawnDetails { item } + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + #[inline(always)] unsafe fn fetch<'w, 's>( _state: &'s Self::State, @@ -766,7 +781,7 @@ pub struct EntityFetch<'w> { /// `fetch` accesses all components in a readonly way. /// This is sound because `update_component_access` sets read access for all components and panic when appropriate. /// Filters are unchanged. -unsafe impl<'a> WorldQuery for EntityRef<'a> { +unsafe impl WorldQuery for EntityRef<'_> { type Fetch<'w> = EntityFetch<'w>; type State = (); @@ -829,7 +844,7 @@ unsafe impl<'a> WorldQuery for EntityRef<'a> { } /// SAFETY: `Self` is the same as `Self::ReadOnly` -unsafe impl<'a> QueryData for EntityRef<'a> { +unsafe impl QueryData for EntityRef<'_> { const IS_READ_ONLY: bool = true; const IS_ARCHETYPAL: bool = true; type ReadOnly = Self; @@ -841,6 +856,10 @@ unsafe impl<'a> QueryData for EntityRef<'a> { item } + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + #[inline(always)] unsafe fn fetch<'w, 's>( _state: &'s Self::State, @@ -876,7 +895,7 @@ impl ReleaseStateQueryData for EntityRef<'_> { impl ArchetypeQueryData for EntityRef<'_> {} /// SAFETY: The accesses of `Self::ReadOnly` are a subset of the accesses of `Self` -unsafe impl<'a> WorldQuery for EntityMut<'a> { +unsafe impl WorldQuery for EntityMut<'_> { type Fetch<'w> = EntityFetch<'w>; type State = (); @@ -939,10 +958,10 @@ unsafe impl<'a> WorldQuery for EntityMut<'a> { } /// SAFETY: access of `EntityRef` is a subset of `EntityMut` -unsafe impl<'a> QueryData for EntityMut<'a> { +unsafe impl<'__w> QueryData for EntityMut<'__w> { const IS_READ_ONLY: bool = false; const IS_ARCHETYPAL: bool = true; - type ReadOnly = EntityRef<'a>; + type ReadOnly = EntityRef<'__w>; type Item<'w, 's> = EntityMut<'w>; fn shrink<'wlong: 'wshort, 'wshort, 's>( @@ -951,6 +970,10 @@ unsafe impl<'a> QueryData for EntityMut<'a> { item } + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.reborrow() + } + #[inline(always)] unsafe fn fetch<'w, 's>( _state: &'s Self::State, @@ -1048,7 +1071,7 @@ unsafe impl WorldQuery for FilteredEntityRef<'_, '_> { } /// SAFETY: `Self` is the same as `Self::ReadOnly` -unsafe impl<'a, 'b> QueryData for FilteredEntityRef<'a, 'b> { +unsafe impl QueryData for FilteredEntityRef<'_, '_> { const IS_READ_ONLY: bool = true; const IS_ARCHETYPAL: bool = true; type ReadOnly = Self; @@ -1060,6 +1083,10 @@ unsafe impl<'a, 'b> QueryData for FilteredEntityRef<'a, 'b> { item } + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + #[inline] fn provide_extra_access( state: &mut Self::State, @@ -1173,10 +1200,10 @@ unsafe impl WorldQuery for FilteredEntityMut<'_, '_> { } /// SAFETY: access of `FilteredEntityRef` is a subset of `FilteredEntityMut` -unsafe impl<'a, 'b> QueryData for FilteredEntityMut<'a, 'b> { +unsafe impl<'__w, '__s> QueryData for FilteredEntityMut<'__w, '__s> { const IS_READ_ONLY: bool = false; const IS_ARCHETYPAL: bool = true; - type ReadOnly = FilteredEntityRef<'a, 'b>; + type ReadOnly = FilteredEntityRef<'__w, '__s>; type Item<'w, 's> = FilteredEntityMut<'w, 's>; fn shrink<'wlong: 'wshort, 'wshort, 's>( @@ -1185,6 +1212,10 @@ unsafe impl<'a, 'b> QueryData for FilteredEntityMut<'a, 'b> { item } + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.reborrow() + } + #[inline] fn provide_extra_access( state: &mut Self::State, @@ -1230,7 +1261,7 @@ impl ArchetypeQueryData for FilteredEntityMut<'_, '_> {} /// SAFETY: `EntityRefExcept` guards access to all components in the bundle `B` /// and populates `Access` values so that queries that conflict with this access /// are rejected. -unsafe impl<'a, 'b, B> WorldQuery for EntityRefExcept<'a, 'b, B> +unsafe impl WorldQuery for EntityRefExcept<'_, '_, B> where B: Bundle, { @@ -1306,7 +1337,7 @@ where } /// SAFETY: `Self` is the same as `Self::ReadOnly`. -unsafe impl<'a, 'b, B> QueryData for EntityRefExcept<'a, 'b, B> +unsafe impl QueryData for EntityRefExcept<'_, '_, B> where B: Bundle, { @@ -1321,6 +1352,10 @@ where item } + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + unsafe fn fetch<'w, 's>( access: &'s Self::State, fetch: &mut Self::Fetch<'w>, @@ -1348,7 +1383,7 @@ impl ArchetypeQueryData for EntityRefExcept<'_, '_, B> {} /// SAFETY: `EntityMutExcept` guards access to all components in the bundle `B` /// and populates `Access` values so that queries that conflict with this access /// are rejected. -unsafe impl<'a, 'b, B> WorldQuery for EntityMutExcept<'a, 'b, B> +unsafe impl WorldQuery for EntityMutExcept<'_, '_, B> where B: Bundle, { @@ -1425,13 +1460,13 @@ where /// SAFETY: All accesses that `EntityRefExcept` provides are also accesses that /// `EntityMutExcept` provides. -unsafe impl<'a, 'b, B> QueryData for EntityMutExcept<'a, 'b, B> +unsafe impl<'__w, '__s, B> QueryData for EntityMutExcept<'__w, '__s, B> where B: Bundle, { const IS_READ_ONLY: bool = false; const IS_ARCHETYPAL: bool = true; - type ReadOnly = EntityRefExcept<'a, 'b, B>; + type ReadOnly = EntityRefExcept<'__w, '__s, B>; type Item<'w, 's> = EntityMutExcept<'w, 's, B>; fn shrink<'wlong: 'wshort, 'wshort, 's>( @@ -1440,6 +1475,10 @@ where item } + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.reborrow() + } + unsafe fn fetch<'w, 's>( access: &'s Self::State, fetch: &mut Self::Fetch<'w>, @@ -1530,6 +1569,10 @@ unsafe impl QueryData for &Archetype { item } + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + #[inline(always)] unsafe fn fetch<'w, 's>( _state: &'s Self::State, @@ -1689,6 +1732,10 @@ unsafe impl QueryData for &T { item } + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + #[inline(always)] unsafe fn fetch<'w, 's>( _state: &'s Self::State, @@ -1879,6 +1926,10 @@ unsafe impl<'__w, T: Component> QueryData for Ref<'__w, T> { item } + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + #[inline(always)] unsafe fn fetch<'w, 's>( _state: &'s Self::State, @@ -2096,6 +2147,10 @@ unsafe impl<'__w, T: Component> QueryData for &'__w mut T item } + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.reborrow() + } + #[inline(always)] unsafe fn fetch<'w, 's>( _state: &'s Self::State, @@ -2257,6 +2312,10 @@ unsafe impl<'__w, T: Component> QueryData for Mut<'__w, T> <&mut T as QueryData>::shrink(item) } + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.reborrow() + } + #[inline(always)] // Forwarded to `&mut T` unsafe fn fetch<'w, 's>( @@ -2406,6 +2465,10 @@ unsafe impl QueryData for Option { item.map(T::shrink) } + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.as_mut().map(T::reborrow) + } + #[inline(always)] unsafe fn fetch<'w, 's>( state: &'s Self::State, @@ -2592,6 +2655,10 @@ unsafe impl QueryData for Has { item } + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + #[inline(always)] unsafe fn fetch<'w, 's>( _state: &'s Self::State, @@ -2658,6 +2725,12 @@ macro_rules! impl_tuple_query_data { )*) } + fn reborrow<'a>( + ($($item,)*): &'a mut Self::Item<'_, '_>, + ) -> Self::Item<'a, 'a> { + ($($name::reborrow($item),)*) + } + #[inline] fn provide_extra_access( state: &mut Self::State, @@ -2856,6 +2929,12 @@ macro_rules! impl_anytuple_fetch { )*) } + fn reborrow<'a>( + ($($item,)*): &'a mut Self::Item<'_, '_>, + ) -> Self::Item<'a, 'a> { + ($( as QueryData>::reborrow($item),)*) + } + #[inline(always)] unsafe fn fetch<'w, 's>( _state: &'s Self::State, @@ -2999,6 +3078,8 @@ unsafe impl QueryData for NopWorldQuery { ) -> Self::Item<'wshort, 's> { } + fn reborrow<'a>(_item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> {} + #[inline(always)] unsafe fn fetch<'w, 's>( _state: &'s Self::State, @@ -3089,6 +3170,8 @@ unsafe impl QueryData for PhantomData { ) -> Self::Item<'wshort, 's> { } + fn reborrow<'a>(_item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> {} + unsafe fn fetch<'w, 's>( _state: &'s Self::State, _fetch: &mut Self::Fetch<'w>, @@ -3300,6 +3383,8 @@ mod tests { ) -> Self::Item<'wshort, 's> { } + fn reborrow<'a>(_item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> {} + #[inline(always)] unsafe fn fetch<'w, 's>( _state: &'s Self::State, diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 8422ceacaa643..7da3ba8fa2bfd 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -130,6 +130,10 @@ const _: () = { type Item<'w, 's> = Commands<'w, 's>; + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.reborrow() + } + fn init_state(world: &mut World) -> Self::State { FetchState { state: <__StructFieldsAlias<'_, '_> as bevy_ecs::system::SystemParam>::init_state( diff --git a/crates/bevy_ecs/src/system/query.rs b/crates/bevy_ecs/src/system/query.rs index b8c29d448adbf..20ba6c121ffc2 100644 --- a/crates/bevy_ecs/src/system/query.rs +++ b/crates/bevy_ecs/src/system/query.rs @@ -2674,6 +2674,15 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Single<'w, 's, D, F> { pub fn into_inner(self) -> D::Item<'w, 's> { self.item } + + /// Returns a `Single<>` with a smaller lifetime. + /// This is useful if you have `&Single`, but you need an `Single`. + pub fn reborrow(&mut self) -> Single<'_, '_, D, F> { + Single { + item: D::reborrow(&mut self.item), + _filter: PhantomData, + } + } } /// [System parameter] that works very much like [`Query`] except it always contains at least one matching entity. @@ -2710,6 +2719,12 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Populated<'w, 's, D, F> { pub fn into_inner(self) -> Query<'w, 's, D, F> { self.0 } + + /// Returns a `Populated<>` with a smaller lifetime. + /// This is useful if you have `&Populated`, but you need a `Populated`. + pub fn reborrow(&mut self) -> Populated<'_, '_, D, F> { + Populated(self.0.reborrow()) + } } impl<'w, 's, D: QueryData, F: QueryFilter> IntoIterator for Populated<'w, 's, D, F> { diff --git a/crates/bevy_ecs/src/system/system_name.rs b/crates/bevy_ecs/src/system/system_name.rs index af4fc91f3c9a2..55dcab66b8730 100644 --- a/crates/bevy_ecs/src/system/system_name.rs +++ b/crates/bevy_ecs/src/system/system_name.rs @@ -34,7 +34,7 @@ use derive_more::derive::{Display, Into}; /// logger.log("Hello"); /// } /// ``` -#[derive(Debug, Into, Display)] +#[derive(Debug, Into, Display, Clone)] pub struct SystemName(DebugName); impl SystemName { @@ -49,6 +49,10 @@ unsafe impl SystemParam for SystemName { type State = (); type Item<'w, 's> = SystemName; + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.clone() + } + fn init_state(_world: &mut World) -> Self::State {} fn init_access( diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index de15c850ccdb9..3601d011659e4 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -220,6 +220,9 @@ pub unsafe trait SystemParam: Sized { /// You could think of [`SystemParam::Item<'w, 's>`] as being an *operation* that changes the lifetimes bound to `Self`. type Item<'world, 'state>: SystemParam; + /// Returns a `SystemParam` item with a smaller lifetime. + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a>; + /// Creates a new instance of this param's [`State`](SystemParam::State). fn init_state(world: &mut World) -> Self::State; @@ -331,6 +334,11 @@ unsafe impl SystemParam for Qu type State = QueryState; type Item<'w, 's> = Query<'w, 's, D, F>; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.reborrow() + } + fn init_state(world: &mut World) -> Self::State { QueryState::new(world) } @@ -389,12 +397,15 @@ fn assert_component_access_compatibility( // SAFETY: Relevant query ComponentId access is applied to SystemMeta. If // this Query conflicts with any prior access, a panic will occur. -unsafe impl<'a, 'b, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam - for Single<'a, 'b, D, F> -{ +unsafe impl SystemParam for Single<'_, '_, D, F> { type State = QueryState; type Item<'w, 's> = Single<'w, 's, D, F>; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.reborrow() + } + fn init_state(world: &mut World) -> Self::State { Query::init_state(world) } @@ -453,8 +464,8 @@ unsafe impl<'a, 'b, D: QueryData + 'static, F: QueryFilter + 'static> SystemPara } // SAFETY: QueryState is constrained to read-only fetches, so it only reads World. -unsafe impl<'a, 'b, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOnlySystemParam - for Single<'a, 'b, D, F> +unsafe impl ReadOnlySystemParam + for Single<'_, '_, D, F> { } @@ -466,6 +477,11 @@ unsafe impl SystemParam type State = QueryState; type Item<'w, 's> = Populated<'w, 's, D, F>; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.reborrow() + } + fn init_state(world: &mut World) -> Self::State { Query::init_state(world) } @@ -623,7 +639,7 @@ unsafe impl<'w, 's, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> Re /// for message in set.p0().read() { /// // ... /// # let _message = message; -/// } +/// }https://doc.rust-lang.org/nomicon/subtyping.html /// set.p1().write(MyMessage::new()); /// /// let entities = set.p2().entities(); @@ -643,9 +659,18 @@ macro_rules! impl_param_set { ($(($index: tt, $param: ident, $fn_name: ident)),*) => { // SAFETY: All parameters are constrained to ReadOnlySystemParam, so World is only read unsafe impl<'w, 's, $($param,)*> ReadOnlySystemParam for ParamSet<'w, 's, ($($param,)*)> - where $($param: ReadOnlySystemParam,)* + where $($param: ReadOnlySystemParam + 'static,)* { } + + #[expect( + clippy::allow_attributes, + reason = "This is inside a macro meant for tuples; as such, `non_snake_case` won't always lint." + )] + #[allow( + non_snake_case, + reason = "Certain variable names are provided by the caller, not by us." + )] // SAFETY: Relevant parameter ComponentId access is applied to SystemMeta. If any ParamState conflicts // with any prior access, a panic will occur. unsafe impl<'_w, '_s, $($param: SystemParam,)*> SystemParam for ParamSet<'_w, '_s, ($($param,)*)> @@ -653,26 +678,17 @@ macro_rules! impl_param_set { type State = ($($param::State,)*); type Item<'w, 's> = ParamSet<'w, 's, ($($param,)*)>; - #[expect( - clippy::allow_attributes, - reason = "This is inside a macro meant for tuples; as such, `non_snake_case` won't always lint." - )] - #[allow( - non_snake_case, - reason = "Certain variable names are provided by the caller, not by us." - )] + #[inline] + fn reborrow<'a>( + item: &'a mut Self::Item<'_, '_>, + ) -> Self::Item<'a, 'a> { + item.reborrow() + } + fn init_state(world: &mut World) -> Self::State { ($($param::init_state(world),)*) } - #[expect( - clippy::allow_attributes, - reason = "This is inside a macro meant for tuples; as such, `non_snake_case` won't always lint." - )] - #[allow( - non_snake_case, - reason = "Certain variable names are provided by the caller, not by us." - )] fn init_access(state: &Self::State, system_meta: &mut SystemMeta, component_access_set: &mut FilteredAccessSet, world: &mut World) { let ($($param,)*) = state; $( @@ -739,20 +755,40 @@ macro_rules! impl_param_set { } )* } + + impl<'w, 's, $($param: SystemParam,)*> ParamSet<'w, 's, ($($param,)*)> + { + /// Returns a `ParamSet` with a smaller lifetime. + /// This can be useful if you have an `&ParamSet` and need a `ParamSet`. + #[inline] + fn reborrow(&mut self) -> ParamSet<'_, '_, ($($param,)*)> { + ParamSet { + param_states: self.param_states, + world: self.world, + system_meta: self.system_meta.clone(), + change_tick: self.change_tick, + } + } + } } } all_tuples_enumerated!(impl_param_set, 1, 8, P, p); // SAFETY: Res only reads a single World resource -unsafe impl<'a, T: Resource> ReadOnlySystemParam for Res<'a, T> {} +unsafe impl ReadOnlySystemParam for Res<'_, T> {} // SAFETY: Res ComponentId access is applied to SystemMeta. If this Res // conflicts with any prior access, a panic will occur. -unsafe impl<'a, T: Resource> SystemParam for Res<'a, T> { +unsafe impl SystemParam for Res<'_, T> { type State = ComponentId; type Item<'w, 's> = Res<'w, T>; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + Res::clone(item) + } + fn init_state(world: &mut World) -> Self::State { world.components_registrator().register_resource::() } @@ -825,10 +861,15 @@ unsafe impl<'a, T: Resource> SystemParam for Res<'a, T> { // SAFETY: Res ComponentId access is applied to SystemMeta. If this Res // conflicts with any prior access, a panic will occur. -unsafe impl<'a, T: Resource> SystemParam for ResMut<'a, T> { +unsafe impl SystemParam for ResMut<'_, T> { type State = ComponentId; type Item<'w, 's> = ResMut<'w, T>; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.reborrow() + } + fn init_state(world: &mut World) -> Self::State { world.components_registrator().register_resource::() } @@ -909,6 +950,11 @@ unsafe impl SystemParam for &'_ World { type State = (); type Item<'w, 's> = &'w World; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + fn init_state(_world: &mut World) -> Self::State {} fn init_access( @@ -946,6 +992,11 @@ unsafe impl<'w> SystemParam for DeferredWorld<'w> { type State = (); type Item<'world, 'state> = DeferredWorld<'world>; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.reborrow() + } + fn init_state(_world: &mut World) -> Self::State {} fn init_access( @@ -1091,6 +1142,15 @@ unsafe impl<'w> SystemParam for DeferredWorld<'w> { #[derive(Debug)] pub struct Local<'s, T: FromWorld + Send + 'static>(pub(crate) &'s mut T); +impl<'s, T: FromWorld + Send + 'static> Local<'s, T> { + /// Returns a [`Local`] with a shorter lifetime. + /// This is useful if you have an `&mut Local` but want a `Local` + #[inline] + pub fn reborrow(&mut self) -> Local<'_, T> { + Local(self.0) + } +} + // SAFETY: Local only accesses internal state unsafe impl<'s, T: FromWorld + Send + 'static> ReadOnlySystemParam for Local<'s, T> {} @@ -1135,10 +1195,15 @@ where } // SAFETY: only local state is accessed -unsafe impl<'a, T: FromWorld + Send + 'static> SystemParam for Local<'a, T> { +unsafe impl SystemParam for Local<'_, T> { type State = SyncCell; type Item<'w, 's> = Local<'s, T>; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.reborrow() + } + fn init_state(world: &mut World) -> Self::State { SyncCell::new(T::from_world(world)) } @@ -1314,6 +1379,7 @@ impl<'a, T: SystemBuffer> DerefMut for Deferred<'a, T> { impl Deferred<'_, T> { /// Returns a [`Deferred`] with a smaller lifetime. /// This is useful if you have `&mut Deferred` but need `Deferred`. + #[inline] pub fn reborrow(&mut self) -> Deferred<'_, T> { Deferred(self.0) } @@ -1327,6 +1393,11 @@ unsafe impl SystemParam for Deferred<'_, T> { type State = SyncCell; type Item<'w, 's> = Deferred<'s, T>; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.reborrow() + } + fn init_state(world: &mut World) -> Self::State { SyncCell::new(T::from_world(world)) } @@ -1367,6 +1438,11 @@ unsafe impl SystemParam for ExclusiveMarker { type State = (); type Item<'w, 's> = Self; + #[inline] + fn reborrow<'a>(_item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + Self(PhantomData) + } + #[inline] fn init_state(_world: &mut World) -> Self::State {} @@ -1401,6 +1477,11 @@ unsafe impl SystemParam for NonSendMarker { type State = (); type Item<'w, 's> = Self; + #[inline] + fn reborrow<'a>(_item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + NonSendMarker(PhantomData) + } + #[inline] fn init_state(_world: &mut World) -> Self::State {} @@ -1428,14 +1509,19 @@ unsafe impl SystemParam for NonSendMarker { unsafe impl ReadOnlySystemParam for NonSendMarker {} // SAFETY: Only reads a single World non-send resource -unsafe impl<'w, T> ReadOnlySystemParam for NonSend<'w, T> {} +unsafe impl ReadOnlySystemParam for NonSend<'_, T> {} // SAFETY: NonSendComponentId access is applied to SystemMeta. If this // NonSend conflicts with any prior access, a panic will occur. -unsafe impl<'a, T: 'static> SystemParam for NonSend<'a, T> { +unsafe impl SystemParam for NonSend<'_, T> { type State = ComponentId; type Item<'w, 's> = NonSend<'w, T>; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + fn init_state(world: &mut World) -> Self::State { world.components_registrator().register_non_send::() } @@ -1503,10 +1589,15 @@ unsafe impl<'a, T: 'static> SystemParam for NonSend<'a, T> { // SAFETY: NonSendMut ComponentId access is applied to SystemMeta. If this // NonSendMut conflicts with any prior access, a panic will occur. -unsafe impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> { +unsafe impl SystemParam for NonSendMut<'_, T> { type State = ComponentId; type Item<'w, 's> = NonSendMut<'w, T>; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.reborrow() + } + fn init_state(world: &mut World) -> Self::State { world.components_registrator().register_non_send::() } @@ -1576,13 +1667,18 @@ unsafe impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> { } // SAFETY: Only reads World archetypes -unsafe impl<'a> ReadOnlySystemParam for &'a Archetypes {} +unsafe impl ReadOnlySystemParam for &'_ Archetypes {} // SAFETY: no component value access -unsafe impl<'a> SystemParam for &'a Archetypes { +unsafe impl SystemParam for &'_ Archetypes { type State = (); type Item<'w, 's> = &'w Archetypes; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + fn init_state(_world: &mut World) -> Self::State {} fn init_access( @@ -1605,13 +1701,18 @@ unsafe impl<'a> SystemParam for &'a Archetypes { } // SAFETY: Only reads World components -unsafe impl<'a> ReadOnlySystemParam for &'a Components {} +unsafe impl ReadOnlySystemParam for &'_ Components {} // SAFETY: no component value access -unsafe impl<'a> SystemParam for &'a Components { +unsafe impl SystemParam for &'_ Components { type State = (); type Item<'w, 's> = &'w Components; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + fn init_state(_world: &mut World) -> Self::State {} fn init_access( @@ -1634,13 +1735,18 @@ unsafe impl<'a> SystemParam for &'a Components { } // SAFETY: Only reads World entities -unsafe impl<'a> ReadOnlySystemParam for &'a Entities {} +unsafe impl ReadOnlySystemParam for &'_ Entities {} // SAFETY: no component value access -unsafe impl<'a> SystemParam for &'a Entities { +unsafe impl SystemParam for &'_ Entities { type State = (); type Item<'w, 's> = &'w Entities; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + fn init_state(_world: &mut World) -> Self::State {} fn init_access( @@ -1663,13 +1769,18 @@ unsafe impl<'a> SystemParam for &'a Entities { } // SAFETY: Only reads World entities -unsafe impl<'a> ReadOnlySystemParam for &'a EntityAllocator {} +unsafe impl ReadOnlySystemParam for &'_ EntityAllocator {} // SAFETY: no component value access -unsafe impl<'a> SystemParam for &'a EntityAllocator { +unsafe impl SystemParam for &'_ EntityAllocator { type State = (); type Item<'w, 's> = &'w EntityAllocator; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + fn init_state(_world: &mut World) -> Self::State {} fn init_access( @@ -1692,13 +1803,18 @@ unsafe impl<'a> SystemParam for &'a EntityAllocator { } // SAFETY: Only reads World bundles -unsafe impl<'a> ReadOnlySystemParam for &'a Bundles {} +unsafe impl ReadOnlySystemParam for &'_ Bundles {} // SAFETY: no component value access -unsafe impl<'a> SystemParam for &'a Bundles { +unsafe impl SystemParam for &'_ Bundles { type State = (); type Item<'w, 's> = &'w Bundles; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + fn init_state(_world: &mut World) -> Self::State {} fn init_access( @@ -1757,6 +1873,11 @@ unsafe impl SystemParam for SystemChangeTick { type State = (); type Item<'w, 's> = SystemChangeTick; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + fn init_state(_world: &mut World) -> Self::State {} fn init_access( @@ -1784,9 +1905,13 @@ unsafe impl SystemParam for SystemChangeTick { // SAFETY: Delegates to `T`, which ensures the safety requirements are met unsafe impl SystemParam for Option { type State = T::State; - type Item<'world, 'state> = Option>; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.as_mut().map(T::reborrow) + } + fn init_state(world: &mut World) -> Self::State { T::init_state(world) } @@ -1827,9 +1952,13 @@ unsafe impl ReadOnlySystemParam for Option {} // SAFETY: Delegates to `T`, which ensures the safety requirements are met unsafe impl SystemParam for Result { type State = T::State; - type Item<'world, 'state> = Result, SystemParamValidationError>; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.as_mut().map(T::reborrow).map_err(|err| err.clone()) + } + fn init_state(world: &mut World) -> Self::State { T::init_state(world) } @@ -1925,6 +2054,11 @@ unsafe impl SystemParam for If { type Item<'world, 'state> = If>; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + If(T::reborrow(&mut item.0)) + } + fn init_state(world: &mut World) -> Self::State { T::init_state(world) } @@ -1976,9 +2110,13 @@ unsafe impl ReadOnlySystemParam for If {} // If any one conflicts, it will panic. unsafe impl SystemParam for Vec { type State = Vec; - type Item<'world, 'state> = Vec>; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.iter_mut().map(T::reborrow).collect() + } + fn init_state(_world: &mut World) -> Self::State { Vec::new() } @@ -2040,9 +2178,13 @@ unsafe impl SystemParam for Vec { // the call passing a copy of the current access will panic. unsafe impl SystemParam for ParamSet<'_, '_, Vec> { type State = Vec; - type Item<'world, 'state> = ParamSet<'world, 'state, Vec>; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.reborrow() + } + fn init_state(_world: &mut World) -> Self::State { Vec::new() } @@ -2096,6 +2238,18 @@ unsafe impl SystemParam for ParamSet<'_, '_, Vec> { } impl ParamSet<'_, '_, Vec> { + /// Returns a `ParamSet` with a smaller lifetime. + /// This can be useful if you have an `&ParamSet` and need a `ParamSet`. + #[inline] + fn reborrow(&mut self) -> ParamSet<'_, '_, Vec> { + ParamSet { + param_states: self.param_states, + world: self.world, + system_meta: self.system_meta.clone(), + change_tick: self.change_tick, + } + } + /// Accesses the parameter at the given index. /// No other parameters may be accessed while this one is active. pub fn get_mut(&mut self, index: usize) -> T::Item<'_, '_> { @@ -2128,7 +2282,7 @@ impl ParamSet<'_, '_, Vec> { } macro_rules! impl_system_param_tuple { - ($(#[$meta:meta])* $($param: ident),*) => { + ($(#[$meta:meta])* $(($param: ident, $item: ident)),*) => { $(#[$meta])* // SAFETY: tuple consists only of ReadOnlySystemParams unsafe impl<$($param: ReadOnlySystemParam),*> ReadOnlySystemParam for ($($param,)*) {} @@ -2145,13 +2299,21 @@ macro_rules! impl_system_param_tuple { unused_variables, reason = "Zero-length tuples won't use some of the parameters." )] - #[allow(clippy::unused_unit, reason = "Zero length tuple is unit.")] + #[allow( + clippy::unused_unit, + reason = "Zero-length tuples cause redundant unit expressions." + )] $(#[$meta])* // SAFETY: implementers of each `SystemParam` in the tuple have validated their impls unsafe impl<$($param: SystemParam),*> SystemParam for ($($param,)*) { type State = ($($param::State,)*); type Item<'w, 's> = ($($param::Item::<'w, 's>,)*); + #[inline] + fn reborrow<'a>(($($item,)*): &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + ($($param::reborrow($item),)*) + } + #[inline] fn init_state(world: &mut World) -> Self::State { ($($param::init_state(world),)*) @@ -2197,10 +2359,6 @@ macro_rules! impl_system_param_tuple { change_tick: Tick, ) -> Self::Item<'w, 's> { let ($($param,)*) = state; - #[allow( - clippy::unused_unit, - reason = "Zero-length tuples won't have any params to get." - )] ($($param::get_param($param, system_meta, world, change_tick),)*) } } @@ -2212,7 +2370,8 @@ all_tuples!( impl_system_param_tuple, 0, 16, - P + P, + i ); /// Contains type aliases for built-in [`SystemParam`]s with `'static` lifetimes. @@ -2327,6 +2486,11 @@ unsafe impl SystemParam for StaticSystemParam<'_, '_, type State = P::State; type Item<'world, 'state> = StaticSystemParam<'world, 'state, P>; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + StaticSystemParam(P::reborrow(&mut item.0)) + } + fn init_state(world: &mut World) -> Self::State { P::init_state(world) } @@ -2374,6 +2538,11 @@ unsafe impl SystemParam for PhantomData { type State = (); type Item<'world, 'state> = Self; + #[inline] + fn reborrow<'a>(_item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + PhantomData + } + fn init_state(_world: &mut World) -> Self::State {} fn init_access( @@ -2538,6 +2707,18 @@ impl<'w, 's> DynSystemParam<'w, 's> { // - The inner system param only performs read access, so it's safe to copy that access for the full `'w` lifetime. unsafe { downcast::(self.state, &self.system_meta, self.world, self.change_tick) } } + + /// Returns a `Res<>` with a smaller lifetime. + /// This is useful if you have `&Res`, but you need a `Res`. + #[inline] + pub fn reborrow(&mut self) -> DynSystemParam<'_, '_> { + DynSystemParam { + state: self.state, + world: self.world, + system_meta: self.system_meta.clone(), + change_tick: self.change_tick, + } + } } /// # Safety @@ -2646,9 +2827,13 @@ impl DynParamState for ParamState { // SAFETY: Delegates to the wrapped parameter, which ensures the safety requirements are met unsafe impl SystemParam for DynSystemParam<'_, '_> { type State = DynSystemParamState; - type Item<'world, 'state> = DynSystemParam<'world, 'state>; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.reborrow() + } + fn init_state(_world: &mut World) -> Self::State { DynSystemParamState::new::<()>(()) } @@ -2701,9 +2886,13 @@ unsafe impl SystemParam for DynSystemParam<'_, '_> { // conflicts with any prior access, a panic will occur. unsafe impl SystemParam for FilteredResources<'_, '_> { type State = Access; - type Item<'world, 'state> = FilteredResources<'world, 'state>; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + fn init_state(_world: &mut World) -> Self::State { Access::new() } @@ -2753,6 +2942,11 @@ unsafe impl SystemParam for FilteredResourcesMut<'_, '_> { type Item<'world, 'state> = FilteredResourcesMut<'world, 'state>; + #[inline] + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.reborrow() + } + fn init_state(_world: &mut World) -> Self::State { Access::new() } @@ -3074,18 +3268,6 @@ mod tests { assert_is_system(my_system); } - // Regression test for https://github.com/bevyengine/bevy/issues/8192. - #[test] - fn system_param_invariant_lifetime() { - #[derive(SystemParam)] - pub struct InvariantParam<'w, 's> { - _set: ParamSet<'w, 's, (Query<'w, 's, ()>,)>, - } - - fn my_system(_: InvariantParam) {} - assert_is_system(my_system); - } - // Compile test for https://github.com/bevyengine/bevy/pull/9589. #[test] fn non_sync_local() { diff --git a/crates/bevy_ecs/src/world/identifier.rs b/crates/bevy_ecs/src/world/identifier.rs index ea4a2b20bc74b..bcaa02e51a507 100644 --- a/crates/bevy_ecs/src/world/identifier.rs +++ b/crates/bevy_ecs/src/world/identifier.rs @@ -54,6 +54,10 @@ unsafe impl SystemParam for WorldId { type Item<'world, 'state> = WorldId; + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + fn init_state(_: &mut World) -> Self::State {} fn init_access( diff --git a/crates/bevy_gizmos/src/gizmos.rs b/crates/bevy_gizmos/src/gizmos.rs index 3d666cbbf51fe..9840bee4aeeb4 100644 --- a/crates/bevy_gizmos/src/gizmos.rs +++ b/crates/bevy_gizmos/src/gizmos.rs @@ -152,6 +152,22 @@ where pub config_ext: &'w Config, } +impl<'w, 's, Config, Clear> Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + /// Returns a [`Gizmos`] with a shorter lifetime. + /// Useful if you have an `&mut Gizmos` but want a `Gizmos` + pub fn reborrow(&mut self) -> Gizmos<'_, '_, Config, Clear> { + Gizmos { + buffer: self.buffer.reborrow(), + config: self.config, + config_ext: self.config_ext, + } + } +} + impl<'w, 's, Config, Clear> Deref for Gizmos<'w, 's, Config, Clear> where Config: GizmoConfigGroup, @@ -200,6 +216,10 @@ where type State = GizmosFetchState; type Item<'w, 's> = Gizmos<'w, 's, Config, Clear>; + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.reborrow() + } + fn init_state(world: &mut World) -> Self::State { GizmosFetchState { state: GizmosState::::init_state(world), diff --git a/crates/bevy_render/src/extract_param.rs b/crates/bevy_render/src/extract_param.rs index 4d81fb9eb1903..a9aedc77ce776 100644 --- a/crates/bevy_render/src/extract_param.rs +++ b/crates/bevy_render/src/extract_param.rs @@ -72,6 +72,10 @@ where type State = ExtractState

; type Item<'w, 's> = Extract<'w, 's, P>; + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + item.reborrow() + } + fn init_state(world: &mut World) -> Self::State { let mut main_world = world.resource_mut::(); ExtractState { @@ -141,6 +145,14 @@ where } } +impl<'w, 's, P: ReadOnlySystemParam> Extract<'w, 's, P> { + pub fn reborrow(&mut self) -> Extract<'_, '_, P> { + Extract { + item: P::reborrow(&mut self.item), + } + } +} + impl<'w, 's, P> Deref for Extract<'w, 's, P> where P: ReadOnlySystemParam, diff --git a/crates/bevy_render/src/sync_world.rs b/crates/bevy_render/src/sync_world.rs index 6a1a1fa813a21..1de21d71944ec 100644 --- a/crates/bevy_render/src/sync_world.rs +++ b/crates/bevy_render/src/sync_world.rs @@ -373,6 +373,10 @@ mod render_entities_world_query_impls { item } + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + #[inline(always)] unsafe fn fetch<'w, 's>( state: &'s Self::State, @@ -488,6 +492,10 @@ mod render_entities_world_query_impls { item } + fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a> { + *item + } + #[inline(always)] unsafe fn fetch<'w, 's>( state: &'s Self::State, diff --git a/release-content/migration-guides/reborrow_methods.md b/release-content/migration-guides/reborrow_methods.md new file mode 100644 index 0000000000000..182e4c2588a1f --- /dev/null +++ b/release-content/migration-guides/reborrow_methods.md @@ -0,0 +1,20 @@ +--- +title: ECS reborrowing methods +pull_requests: [22025] +--- + +Bevy 0.18 adds a new `reborrow` method to `QueryData` and `SystemParam`, which +enables shortening the lifetime of a system param/query item. + +```rust +fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a>; +``` + +Since most implementations will have covariant lifetimes, this should be +an easy method to add. However, there's a couple narrow exceptions. + +If you have a `ParamSet` in a custom system param that looks like +`ParamSet<'w, 's, InnerParam<'w, 's>>`, this is actually *invariant* over +the lifetimes `'w` and `'s`, so it's impossible to implement `reborrow` +for the custom param. Instead, you should write the inner param's lifetimes +as `'static`. For more info on lifetime variance, see the [nomicon](https://doc.rust-lang.org/nomicon/subtyping.html).