Conversion of ResMut and NonSendMut to Mut (#5438)

# Objective

Enable treating components and resources equally, which can
simplify the implementation of some systems where only the change
detection feature is relevant and not the kind of object (resource or
component).

## Solution

Implement `From<ResMut<T>>` and `From<NonSendMut<T>>` for
`Mut`. Since the 3 structs are similar, and only differ by their system
param role, the conversion is trivial.

---

## Changelog

Added - `From<ResMut>` and `From<NonSendMut>` for `Mut<T>`.
This commit is contained in:
Jerome Humbert 2022-07-25 16:11:29 +00:00
parent 231894a3a6
commit d4787111a3

View file

@ -185,6 +185,17 @@ change_detection_impl!(ResMut<'a, T>, T, Resource);
impl_into_inner!(ResMut<'a, T>, T, Resource);
impl_debug!(ResMut<'a, T>, Resource);
impl<'a, T: Resource> From<ResMut<'a, T>> for Mut<'a, T> {
/// Convert this `ResMut` into a `Mut`. This allows keeping the change-detection feature of `Mut`
/// while losing the specificity of `ResMut` for resources.
fn from(other: ResMut<'a, T>) -> Mut<'a, T> {
Mut {
value: other.value,
ticks: other.ticks,
}
}
}
/// Unique borrow of a non-[`Send`] resource.
///
/// Only [`Send`] resources may be accessed with the [`ResMut`] [`SystemParam`](crate::system::SystemParam). In case that the
@ -206,6 +217,17 @@ change_detection_impl!(NonSendMut<'a, T>, T,);
impl_into_inner!(NonSendMut<'a, T>, T,);
impl_debug!(NonSendMut<'a, T>,);
impl<'a, T: Resource> From<NonSendMut<'a, T>> for Mut<'a, T> {
/// Convert this `NonSendMut` into a `Mut`. This allows keeping the change-detection feature of `Mut`
/// while losing the specificity of `NonSendMut`.
fn from(other: NonSendMut<'a, T>) -> Mut<'a, T> {
Mut {
value: other.value,
ticks: other.ticks,
}
}
}
/// Unique mutable borrow of an entity's component
pub struct Mut<'a, T> {
pub(crate) value: &'a mut T,
@ -286,7 +308,9 @@ impl std::fmt::Debug for MutUntyped<'_> {
mod tests {
use crate::{
self as bevy_ecs,
change_detection::{CHECK_TICK_THRESHOLD, MAX_CHANGE_AGE},
change_detection::{
ComponentTicks, Mut, NonSendMut, ResMut, Ticks, CHECK_TICK_THRESHOLD, MAX_CHANGE_AGE,
},
component::Component,
query::ChangeTrackers,
system::{IntoSystem, Query, System},
@ -296,6 +320,8 @@ mod tests {
#[derive(Component)]
struct C;
struct R; // Resource
#[test]
fn change_expiration() {
fn change_detected(query: Query<ChangeTrackers<C>>) -> bool {
@ -382,4 +408,52 @@ mod tests {
assert!(ticks_since_change == MAX_CHANGE_AGE);
}
}
#[test]
fn mut_from_res_mut() {
let mut component_ticks = ComponentTicks {
added: 1,
changed: 2,
};
let ticks = Ticks {
component_ticks: &mut component_ticks,
last_change_tick: 3,
change_tick: 4,
};
let mut res = R {};
let res_mut = ResMut {
value: &mut res,
ticks,
};
let into_mut: Mut<R> = res_mut.into();
assert_eq!(1, into_mut.ticks.component_ticks.added);
assert_eq!(2, into_mut.ticks.component_ticks.changed);
assert_eq!(3, into_mut.ticks.last_change_tick);
assert_eq!(4, into_mut.ticks.change_tick);
}
#[test]
fn mut_from_non_send_mut() {
let mut component_ticks = ComponentTicks {
added: 1,
changed: 2,
};
let ticks = Ticks {
component_ticks: &mut component_ticks,
last_change_tick: 3,
change_tick: 4,
};
let mut res = R {};
let non_send_mut = NonSendMut {
value: &mut res,
ticks,
};
let into_mut: Mut<R> = non_send_mut.into();
assert_eq!(1, into_mut.ticks.component_ticks.added);
assert_eq!(2, into_mut.ticks.component_ticks.changed);
assert_eq!(3, into_mut.ticks.last_change_tick);
assert_eq!(4, into_mut.ticks.change_tick);
}
}