From f8f78b7475b0d0f441decbcdd2cb53653f0f8632 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Mon, 9 Jan 2023 22:20:10 +0000 Subject: [PATCH] Add `Mut::reborrow` (#7114) # Objective - In some cases, you need a `Mut` pointer, but you only have a mutable reference to one. There is no easy way of converting `&'a mut Mut<'_, T>` -> `Mut<'a, T>` outside of the engine. ### Example (Before) ```rust fn do_with_mut(val: Mut) { ... } for x: Mut in &mut query { // The function expects a `Mut`, so `x` gets moved here. do_with_mut(x); // Error: use of moved value. do_a_thing(&x); } ``` ## Solution - Add the function `reborrow`, which performs the mapping. This is analogous to `PtrMut::reborrow`. ### Example (After) ```rust fn do_with_mut(val: Mut) { ... } for x: Mut in &mut query { // We reborrow `x`, so the original does not get moved. do_with_mut(x.reborrow()); // Works fine. do_a_thing(&x); } ``` --- ## Changelog - Added the method `reborrow` to `Mut`, `ResMut`, `NonSendMut`, and `MutUntyped`. --- crates/bevy_ecs/src/change_detection.rs | 37 +++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index d9ce86e60294d..ac28a8c29a11b 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -209,6 +209,25 @@ macro_rules! impl_methods { self.value } + /// Returns a `Mut<>` with a smaller lifetime. + /// This is useful if you have `&mut + #[doc = stringify!($name)] + /// `, but you need a `Mut`. + /// + /// Note that calling [`DetectChanges::set_last_changed`] on the returned value + /// will not affect the original. + pub fn reborrow(&mut self) -> Mut<'_, $target> { + Mut { + value: self.value, + ticks: Ticks { + added: self.ticks.added, + changed: self.ticks.changed, + last_change_tick: self.ticks.last_change_tick, + change_tick: self.ticks.change_tick, + } + } + } + /// Maps to an inner value by applying a function to the contained reference, without flagging a change. /// /// You should never modify the argument passed to the closure -- if you want to modify the data @@ -427,6 +446,24 @@ impl<'a> MutUntyped<'a> { self.value } + /// Returns a [`MutUntyped`] with a smaller lifetime. + /// This is useful if you have `&mut MutUntyped`, but you need a `MutUntyped`. + /// + /// Note that calling [`DetectChanges::set_last_changed`] on the returned value + /// will not affect the original. + #[inline] + pub fn reborrow(&mut self) -> MutUntyped { + MutUntyped { + value: self.value.reborrow(), + ticks: Ticks { + added: self.ticks.added, + changed: self.ticks.changed, + last_change_tick: self.ticks.last_change_tick, + change_tick: self.ticks.change_tick, + }, + } + } + /// Returns a pointer to the value without taking ownership of this smart pointer, marking it as changed. /// /// In order to avoid marking the value as changed, you need to call [`bypass_change_detection`](DetectChanges::bypass_change_detection).