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..12af8ac26c318 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, } } @@ -362,6 +362,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/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/query/mod.rs b/crates/bevy_ecs/src/query/mod.rs index b5c1b3d7d18a5..3deaaac0fd279 100644 --- a/crates/bevy_ecs/src/query/mod.rs +++ b/crates/bevy_ecs/src/query/mod.rs @@ -890,6 +890,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_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_traits.md b/release-content/migration-guides/reborrow_traits.md new file mode 100644 index 0000000000000..ccca63c283d24 --- /dev/null +++ b/release-content/migration-guides/reborrow_traits.md @@ -0,0 +1,14 @@ +--- +title: ECS reborrowing traits +pull_requests: [22025] +--- + +Bevy 0.18 adds a new `reborrow` method to `QueryData`, which enables shortening the lifetime of a query item. + +```rust +fn reborrow<'a>(item: &'a mut Self::Item<'_, '_>) -> Self::Item<'a, 'a>; +``` + +Since `QueryData` implementers already have to be covariant over their lifetimes, +this shouldn't make the trait any harder to implement. For most read-only query +data, the method can be implemented with a simple deref: `*item`.