From 9c85d19b9cf7af2ebb4dfdb4957da6f8c30a22c0 Mon Sep 17 00:00:00 2001 From: Nile Date: Tue, 27 Dec 2022 16:05:16 +0000 Subject: [PATCH] Round out the untyped api s (#7009) # Objective Bevy uses custom `Ptr` types so the rust borrow checker can help ensure lifetimes are correct, even when types aren't known. However, these types don't benefit from the automatic lifetime coercion regular rust references enjoy ## Solution Add a couple methods to Ptr, PtrMut, and MutUntyped to allow for easy usage of these types in more complex scenarios. ## Changelog - Added `as_mut` and `as_ref` methods to `MutUntyped`. - Added `shrink` and `as_ref` methods to `PtrMut`. ## Migration Guide - `MutUntyped::into_inner` now marks things as changed. --- crates/bevy_ecs/src/change_detection.rs | 24 +++++++++++++++++---- crates/bevy_ptr/src/lib.rs | 28 +++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index 2bd966fd1845e..d029d9dad9bf9 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 2163e6478471b..bf38fd5ff1d9f 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