From dfdc9f8369a0e7dd7e6f78a950f687a5c3822c39 Mon Sep 17 00:00:00 2001 From: Testare Date: Sun, 1 Oct 2023 17:53:12 -0700 Subject: [PATCH] `as_deref_mut()` method for Mut-like types (#9912) # Objective Add a new method so you can do `set_if_neq` with dereferencing components: `as_deref_mut()`! ## Solution Added an as_deref_mut method so that we can use `set_if_neq()` without having to wrap up types for derefencable components --------- Co-authored-by: Alice Cecile Co-authored-by: Joseph <21144246+JoJoJet@users.noreply.github.com> --- crates/bevy_ecs/src/change_detection.rs | 49 +++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index 0db970ba58..1c5697d337 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -381,6 +381,15 @@ macro_rules! impl_methods { ticks: self.ticks, } } + + /// Allows you access to the dereferenced value of this pointer without immediately + /// triggering change detection. + pub fn as_deref_mut(&mut self) -> Mut<'_, <$target as Deref>::Target> + where $target: DerefMut + { + self.reborrow().map_unchanged(|v| v.deref_mut()) + } + } }; } @@ -907,6 +916,7 @@ mod tests { use bevy_ecs_macros::Resource; use bevy_ptr::PtrMut; use bevy_reflect::{FromType, ReflectFromPtr}; + use std::ops::{Deref, DerefMut}; use crate::{ self as bevy_ecs, @@ -929,6 +939,19 @@ mod tests { #[derive(Resource, PartialEq)] struct R2(u8); + impl Deref for R2 { + type Target = u8; + fn deref(&self) -> &u8 { + &self.0 + } + } + + impl DerefMut for R2 { + fn deref_mut(&mut self) -> &mut u8 { + &mut self.0 + } + } + #[test] fn change_expiration() { fn change_detected(query: Query>) -> bool { @@ -1143,6 +1166,32 @@ mod tests { ); } + #[test] + fn as_deref_mut() { + let mut world = World::new(); + + world.insert_resource(R2(0)); + // Resources are Changed when first added + world.increment_change_tick(); + // This is required to update world::last_change_tick + world.clear_trackers(); + + let mut r = world.resource_mut::(); + assert!(!r.is_changed(), "Resource must begin unchanged."); + + let mut r = r.as_deref_mut(); + assert!( + !r.is_changed(), + "Dereferencing should not mark the item as changed yet" + ); + + r.set_if_neq(3); + assert!( + r.is_changed(), + "Resource must be changed after setting to a different value." + ); + } + #[test] fn mut_untyped_to_reflect() { let last_run = Tick::new(2);