From 375dac1933539973bd83c6a039ce5236865360cc Mon Sep 17 00:00:00 2001 From: Jerome Humbert Date: Mon, 25 Jul 2022 16:11:29 +0000 Subject: [PATCH] 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>` and `From>` for `Mut`. Since the 3 structs are similar, and only differ by their system param role, the conversion is trivial. --- ## Changelog Added - `From` and `From` for `Mut`. --- crates/bevy_ecs/src/change_detection.rs | 76 ++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index b96f4e48c16c97..a93ec510778ba0 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -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> 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> 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>) -> 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 = 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 = 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); + } }