Skip to content

Commit

Permalink
Round out the untyped api s (bevyengine#7009)
Browse files Browse the repository at this point in the history
# 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.
  • Loading branch information
TheRawMeatball authored and alradish committed Jan 22, 2023
1 parent 3c56b49 commit 9c85d19
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 4 deletions.
24 changes: 20 additions & 4 deletions crates/bevy_ecs/src/change_detection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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> {
Expand Down
28 changes: 28 additions & 0 deletions crates/bevy_ptr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 9c85d19

Please sign in to comment.