diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index 2bd966fd18..d029d9dad9 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -5,7 +5,7 @@ use crate::{ ptr::PtrMut, system::Resource, }; -use bevy_ptr::UnsafeCellDeref; +use bevy_ptr::{Ptr, UnsafeCellDeref}; use std::ops::{Deref, DerefMut}; /// The (arbitrarily chosen) minimum number of world tick increments between `check_tick` scans. @@ -421,13 +421,29 @@ pub struct MutUntyped<'a> { } impl<'a> MutUntyped<'a> { - /// Returns the pointer to the value, without marking it as changed. + /// Returns the pointer to the value, marking it as changed. /// - /// In order to mark the value as changed, you need to call [`set_changed`](DetectChanges::set_changed) manually. + /// In order to avoid marking the value as changed, you need to call [`bypass_change_detection`](DetectChanges::bypass_change_detection). #[inline] - pub fn into_inner(self) -> PtrMut<'a> { + pub fn into_inner(mut self) -> PtrMut<'a> { + self.set_changed(); self.value } + + /// 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). + #[inline] + pub fn as_mut(&mut self) -> PtrMut<'_> { + self.set_changed(); + self.value.reborrow() + } + + /// Returns an immutable pointer to the value without taking ownership. + #[inline] + pub fn as_ref(&self) -> Ptr<'_> { + self.value.as_ref() + } } impl<'a> DetectChanges for MutUntyped<'a> { diff --git a/crates/bevy_ptr/src/lib.rs b/crates/bevy_ptr/src/lib.rs index 2163e64784..bf38fd5ff1 100644 --- a/crates/bevy_ptr/src/lib.rs +++ b/crates/bevy_ptr/src/lib.rs @@ -176,6 +176,20 @@ impl<'a> PtrMut<'a> { pub fn as_ptr(&self) -> *mut u8 { self.0.as_ptr() } + + /// Gets a `PtrMut` from this with a smaller lifetime. + #[inline] + pub fn reborrow(&mut self) -> PtrMut<'_> { + // SAFE: the ptrmut we're borrowing from is assumed to be valid + unsafe { PtrMut::new(self.0) } + } + + /// Gets an immutable reference from this mutable reference + #[inline] + pub fn as_ref(&self) -> Ptr<'_> { + // SAFE: The `PtrMut` type's guarantees about the validity of this pointer are a superset of `Ptr` s guarantees + unsafe { Ptr::new(self.0) } + } } impl<'a, T> From<&'a mut T> for PtrMut<'a> { @@ -224,6 +238,20 @@ impl<'a> OwningPtr<'a> { pub fn as_ptr(&self) -> *mut u8 { self.0.as_ptr() } + + /// Gets an immutable pointer from this owned pointer. + #[inline] + pub fn as_ref(&self) -> Ptr<'_> { + // SAFE: The `Owning` type's guarantees about the validity of this pointer are a superset of `Ptr` s guarantees + unsafe { Ptr::new(self.0) } + } + + /// Gets a mutable pointer from this owned pointer. + #[inline] + pub fn as_mut(&mut self) -> PtrMut<'_> { + // SAFE: The `Owning` type's guarantees about the validity of this pointer are a superset of `Ptr` s guarantees + unsafe { PtrMut::new(self.0) } + } } /// Conceptually equivalent to `&'a [T]` but with length information cut out for performance reasons