Skip to content

Commit

Permalink
Add Mut::reborrow (bevyengine#7114)
Browse files Browse the repository at this point in the history
# Objective

- In some cases, you need a `Mut<T>` 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<T>(val: Mut<T>) { ... }

for x: Mut<T> in &mut query {
    // The function expects a `Mut<T>`, 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<T>(val: Mut<T>) { ... }

for x: Mut<T> 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`.
  • Loading branch information
JoJoJet authored and alradish committed Jan 22, 2023
1 parent bd3a64d commit f8f78b7
Showing 1 changed file with 37 additions and 0 deletions.
37 changes: 37 additions & 0 deletions crates/bevy_ecs/src/change_detection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
/// <T>`, but you need a `Mut<T>`.
///
/// 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
Expand Down Expand Up @@ -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).
Expand Down

0 comments on commit f8f78b7

Please sign in to comment.