From f9ce9f58f698418b15c5293887a2ffbc9c238cb7 Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Mon, 31 Oct 2022 13:13:07 +0100 Subject: [PATCH 1/9] add MutUntyped::to_typed --- crates/bevy_ecs/src/change_detection.rs | 69 +++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index 1bf6a22d189c7..27dcdc0496448 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -691,6 +691,31 @@ impl<'a> MutUntyped<'a> { self.value.as_ref() } + /// Turn this [`MutUntyped`] into a [`Mut`] by mapping the inner [`PtrMut`] to another value. + /// If you know the type of the value you can do + /// ```no_run + /// # use bevy_ecs::change_detection::{Mut, MutUntyped}; + /// # let mut_untyped: MutUntyped = unimplemented!(); + /// // SAFETY: ptr is of type `u8` + /// mut_untyped.to_typed(|ptr| unsafe { ptr.deref_mut::() }); + /// ``` + /// If you have a [`ReflectFromPtr`](bevy_reflect::ReflectFromPtr) that you know belongs to this [`MutUntyped`], + /// you can do + /// ```no_run + /// # use bevy_ecs::change_detection::{Mut, MutUntyped}; + /// # let mut_untyped: MutUntyped = unimplemented!(); + /// # let reflect_from_ptr: bevy_reflect::ReflectFromPtr = unimplemented!(); + /// // SAFETY: from the context it is known that `ReflectFromPtr` was made for the type of the `MutUntyped` + /// mut_untyped.to_typed(|ptr| unsafe { reflect_from_ptr.as_reflect_ptr_mut(ptr) }); + /// ``` + pub fn to_typed(self, f: impl FnOnce(PtrMut<'a>) -> &'a mut T) -> Mut<'a, T> { + Mut { + value: f(self.value), + ticks: self.ticks, + } + } + + /// Transforms this [`MutUntyped`] into a [`Mut`] with the same lifetime. /// /// # Safety @@ -753,7 +778,11 @@ impl std::fmt::Debug for MutUntyped<'_> { #[cfg(test)] mod tests { + use std::ptr::NonNull; + use bevy_ecs_macros::Resource; + use bevy_ptr::PtrMut; + use bevy_reflect::{FromType, ReflectFromPtr}; use crate::{ self as bevy_ecs, @@ -766,7 +795,11 @@ mod tests { }; use super::DetectChanges; +<<<<<<< HEAD use super::DetectChangesMut; +======= + use super::MutUntyped; +>>>>>>> 181b463bf (add MutUntyped::to_typed) #[derive(Component, PartialEq)] struct C; @@ -990,4 +1023,40 @@ mod tests { "Resource must be changed after setting to a different value." ); } + + #[test] + fn mut_untyped_to_reflect() { + let (last_change_tick, change_tick) = (2, 3); + let mut component_ticks = ComponentTicks { + added: Tick::new(1), + changed: Tick::new(2), + }; + let ticks = Ticks { + added: &mut component_ticks.added, + changed: &mut component_ticks.changed, + last_change_tick, + change_tick, + }; + + let mut value: i32 = 5; + let value = MutUntyped { + // SAFETY: lifetime does not exceed `value` + value: unsafe { PtrMut::new(NonNull::new(&mut value as *mut i32 as *mut u8).unwrap()) }, + ticks, + }; + + let reflect_from_ptr = >::from_type(); + + let mut new = value.to_typed(|ptr| { + // SAFETY: ptr has type of ReflectFromPtr + let value = unsafe { reflect_from_ptr.as_reflect_ptr_mut(ptr) }; + value + }); + + assert!(!new.is_changed()); + + new.reflect_mut(); + + assert!(new.is_changed()); + } } From e422ad414f4634ad62becfe2707ef07c7c2272a6 Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Sat, 31 Dec 2022 21:37:38 +0100 Subject: [PATCH 2/9] rename to_typed to map_unchanged --- crates/bevy_ecs/src/change_detection.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index 27dcdc0496448..560cfad6a0233 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -697,7 +697,7 @@ impl<'a> MutUntyped<'a> { /// # use bevy_ecs::change_detection::{Mut, MutUntyped}; /// # let mut_untyped: MutUntyped = unimplemented!(); /// // SAFETY: ptr is of type `u8` - /// mut_untyped.to_typed(|ptr| unsafe { ptr.deref_mut::() }); + /// mut_untyped.map_unchanged(|ptr| unsafe { ptr.deref_mut::() }); /// ``` /// If you have a [`ReflectFromPtr`](bevy_reflect::ReflectFromPtr) that you know belongs to this [`MutUntyped`], /// you can do @@ -706,9 +706,9 @@ impl<'a> MutUntyped<'a> { /// # let mut_untyped: MutUntyped = unimplemented!(); /// # let reflect_from_ptr: bevy_reflect::ReflectFromPtr = unimplemented!(); /// // SAFETY: from the context it is known that `ReflectFromPtr` was made for the type of the `MutUntyped` - /// mut_untyped.to_typed(|ptr| unsafe { reflect_from_ptr.as_reflect_ptr_mut(ptr) }); + /// mut_untyped.map_unchanged(|ptr| unsafe { reflect_from_ptr.as_reflect_ptr_mut(ptr) }); /// ``` - pub fn to_typed(self, f: impl FnOnce(PtrMut<'a>) -> &'a mut T) -> Mut<'a, T> { + pub fn map_unchanged(self, f: impl FnOnce(PtrMut<'a>) -> &'a mut T) -> Mut<'a, T> { Mut { value: f(self.value), ticks: self.ticks, @@ -1047,7 +1047,7 @@ mod tests { let reflect_from_ptr = >::from_type(); - let mut new = value.to_typed(|ptr| { + let mut new = value.map_unchanged(|ptr| { // SAFETY: ptr has type of ReflectFromPtr let value = unsafe { reflect_from_ptr.as_reflect_ptr_mut(ptr) }; value From 291694baaa843292d61ca855fc5f7da8e859274c Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Mon, 13 Feb 2023 21:49:03 +0100 Subject: [PATCH 3/9] docs tweaks --- crates/bevy_ecs/src/change_detection.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index 560cfad6a0233..ab74d4e630a64 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -691,7 +691,11 @@ impl<'a> MutUntyped<'a> { self.value.as_ref() } - /// Turn this [`MutUntyped`] into a [`Mut`] by mapping the inner [`PtrMut`] to another value. + /// Turn this [`MutUntyped`] into a [`Mut`] by mapping the inner [`PtrMut`] to another value, + /// without flagging a change. [`MutUntyped`] equivalent of [`Mut::map_unchanged`]. + /// + /// You should never modify the argument passed to the closure – if you want to modify the data without flagging a change, consider using [`DetectChanges::bypass_change_detection`](crate::change_detection::DetectChangesMut::bypass to make your intent explicit. + /// /// If you know the type of the value you can do /// ```no_run /// # use bevy_ecs::change_detection::{Mut, MutUntyped}; From f7a9319ead62d01838e43823893e72c6ebc6bf66 Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Fri, 17 Feb 2023 11:30:48 +0100 Subject: [PATCH 4/9] remove merge conflict marker --- crates/bevy_ecs/src/change_detection.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index ab74d4e630a64..c9eff7d3be35c 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -719,7 +719,6 @@ impl<'a> MutUntyped<'a> { } } - /// Transforms this [`MutUntyped`] into a [`Mut`] with the same lifetime. /// /// # Safety @@ -799,11 +798,8 @@ mod tests { }; use super::DetectChanges; -<<<<<<< HEAD use super::DetectChangesMut; -======= use super::MutUntyped; ->>>>>>> 181b463bf (add MutUntyped::to_typed) #[derive(Component, PartialEq)] struct C; From 7c5fb100cee496d1f616caa717eb304f354ff77a Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Fri, 17 Feb 2023 11:34:53 +0100 Subject: [PATCH 5/9] fix docs --- crates/bevy_ecs/src/change_detection.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index c9eff7d3be35c..73d841c035973 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -694,7 +694,7 @@ impl<'a> MutUntyped<'a> { /// Turn this [`MutUntyped`] into a [`Mut`] by mapping the inner [`PtrMut`] to another value, /// without flagging a change. [`MutUntyped`] equivalent of [`Mut::map_unchanged`]. /// - /// You should never modify the argument passed to the closure – if you want to modify the data without flagging a change, consider using [`DetectChanges::bypass_change_detection`](crate::change_detection::DetectChangesMut::bypass to make your intent explicit. + /// You should never modify the argument passed to the closure – if you want to modify the data without flagging a change, consider using [`bypass_change_detection`](DetectChangesMut::bypass_change_detection) to make your intent explicit. /// /// If you know the type of the value you can do /// ```no_run From aa8112c29b5b0b7201b1218e923930357195dbba Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Fri, 17 Feb 2023 11:50:20 +0100 Subject: [PATCH 6/9] fix test --- crates/bevy_ecs/src/change_detection.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index 73d841c035973..407646ca6936e 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -1031,7 +1031,7 @@ mod tests { added: Tick::new(1), changed: Tick::new(2), }; - let ticks = Ticks { + let ticks = TicksMut { added: &mut component_ticks.added, changed: &mut component_ticks.changed, last_change_tick, From c1d07dc933f4655a0565b9a4ae95eac16271d053 Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Fri, 17 Feb 2023 15:39:12 +0100 Subject: [PATCH 7/9] merge imports --- crates/bevy_ecs/src/change_detection.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index 407646ca6936e..53dd5bf2d661c 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -797,9 +797,7 @@ mod tests { world::World, }; - use super::DetectChanges; - use super::DetectChangesMut; - use super::MutUntyped; + use super::{DetectChanges, DetectChangesMut, MutUntyped}; #[derive(Component, PartialEq)] struct C; From 645ba5071ff52772223be583b316e815b2ce94a9 Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Fri, 17 Feb 2023 16:21:33 +0100 Subject: [PATCH 8/9] Update crates/bevy_ecs/src/change_detection.rs Co-authored-by: JoJoJet <21144246+JoJoJet@users.noreply.github.com> --- crates/bevy_ecs/src/change_detection.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index 53dd5bf2d661c..7241a9e280955 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -1038,8 +1038,7 @@ mod tests { let mut value: i32 = 5; let value = MutUntyped { - // SAFETY: lifetime does not exceed `value` - value: unsafe { PtrMut::new(NonNull::new(&mut value as *mut i32 as *mut u8).unwrap()) }, + value: PtrMut::from(&mut value), ticks, }; From 251825ae42f82872402a77e159275cc3c7a6efc1 Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Mon, 6 Mar 2023 20:23:23 +0100 Subject: [PATCH 9/9] remove unused import --- crates/bevy_ecs/src/change_detection.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index 7241a9e280955..5bb4d547f711f 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -781,8 +781,6 @@ impl std::fmt::Debug for MutUntyped<'_> { #[cfg(test)] mod tests { - use std::ptr::NonNull; - use bevy_ecs_macros::Resource; use bevy_ptr::PtrMut; use bevy_reflect::{FromType, ReflectFromPtr};