Skip to content

Commit f2f8f90

Browse files
joseph-giocart
andcommitted
Add safe constructors for untyped pointers Ptr and PtrMut (#6539)
# Objective Currently, `Ptr` and `PtrMut` can only be constructed via unsafe code. This means that downgrading a reference to an untyped pointer is very cumbersome, despite being a very simple operation. ## Solution Define conversions for easily and safely constructing untyped pointers. This is the non-owned counterpart to `OwningPtr::make`. Before: ```rust let ptr = unsafe { PtrMut::new(NonNull::from(&mut value).cast()) }; ``` After: ```rust let ptr = PtrMut::from(&mut value); ``` Co-authored-by: Carter Anderson <mcanders1@gmail.com>
1 parent 635320f commit f2f8f90

File tree

2 files changed

+31
-15
lines changed

2 files changed

+31
-15
lines changed

crates/bevy_ptr/src/lib.rs

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#![warn(missing_docs)]
44

55
use core::{
6-
cell::UnsafeCell, marker::PhantomData, mem::MaybeUninit, num::NonZeroUsize, ptr::NonNull,
6+
cell::UnsafeCell, marker::PhantomData, mem::ManuallyDrop, num::NonZeroUsize, ptr::NonNull,
77
};
88

99
/// Type-erased borrow of some unknown type chosen when constructing this type.
@@ -98,6 +98,9 @@ macro_rules! impl_ptr {
9898
}
9999

100100
impl_ptr!(Ptr);
101+
impl_ptr!(PtrMut);
102+
impl_ptr!(OwningPtr);
103+
101104
impl<'a> Ptr<'a> {
102105
/// Transforms this [`Ptr`] into an [`PtrMut`]
103106
///
@@ -127,7 +130,16 @@ impl<'a> Ptr<'a> {
127130
self.0.as_ptr()
128131
}
129132
}
130-
impl_ptr!(PtrMut);
133+
134+
impl<'a, T> From<&'a T> for Ptr<'a> {
135+
#[inline]
136+
fn from(val: &'a T) -> Self {
137+
// SAFETY: The returned pointer has the same lifetime as the passed reference.
138+
// Access is immutable.
139+
unsafe { Self::new(NonNull::from(val).cast()) }
140+
}
141+
}
142+
131143
impl<'a> PtrMut<'a> {
132144
/// Transforms this [`PtrMut`] into an [`OwningPtr`]
133145
///
@@ -157,15 +169,24 @@ impl<'a> PtrMut<'a> {
157169
self.0.as_ptr()
158170
}
159171
}
160-
impl_ptr!(OwningPtr);
172+
173+
impl<'a, T> From<&'a mut T> for PtrMut<'a> {
174+
#[inline]
175+
fn from(val: &'a mut T) -> Self {
176+
// SAFETY: The returned pointer has the same lifetime as the passed reference.
177+
// The reference is mutable, and thus will not alias.
178+
unsafe { Self::new(NonNull::from(val).cast()) }
179+
}
180+
}
181+
161182
impl<'a> OwningPtr<'a> {
162183
/// Consumes a value and creates an [`OwningPtr`] to it while ensuring a double drop does not happen.
163184
#[inline]
164185
pub fn make<T, F: FnOnce(OwningPtr<'_>) -> R, R>(val: T, f: F) -> R {
165-
let mut temp = MaybeUninit::new(val);
166-
// SAFETY: `temp.as_mut_ptr()` is a reference to a local value on the stack, so it cannot be null
167-
let ptr = unsafe { NonNull::new_unchecked(temp.as_mut_ptr().cast::<u8>()) };
168-
f(Self(ptr, PhantomData))
186+
let mut temp = ManuallyDrop::new(val);
187+
// SAFETY: The value behind the pointer will not get dropped or observed later,
188+
// so it's safe to promote it to an owning pointer.
189+
f(unsafe { PtrMut::from(&mut *temp).promote() })
169190
}
170191

171192
/// Consumes the [`OwningPtr`] to obtain ownership of the underlying data of type `T`.

crates/bevy_reflect/src/type_registry.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ impl<T: for<'a> Deserialize<'a> + Reflect> FromType<T> for ReflectDeserialize {
475475
/// type_registry.register::<Reflected>();
476476
///
477477
/// let mut value = Reflected("Hello world!".to_string());
478-
/// let value = unsafe { Ptr::new(NonNull::from(&mut value).cast()) };
478+
/// let value = Ptr::from(&value);
479479
///
480480
/// let reflect_data = type_registry.get(std::any::TypeId::of::<Reflected>()).unwrap();
481481
/// let reflect_from_ptr = reflect_data.data::<ReflectFromPtr>().unwrap();
@@ -534,8 +534,6 @@ impl<T: Reflect> FromType<T> for ReflectFromPtr {
534534

535535
#[cfg(test)]
536536
mod test {
537-
use std::ptr::NonNull;
538-
539537
use crate::{GetTypeRegistration, ReflectFromPtr, TypeRegistration};
540538
use bevy_ptr::{Ptr, PtrMut};
541539
use bevy_utils::HashMap;
@@ -560,8 +558,7 @@ mod test {
560558

561559
let mut value = Foo { a: 1.0 };
562560
{
563-
// SAFETY: lifetime doesn't outlive original value, access is unique
564-
let value = unsafe { PtrMut::new(NonNull::from(&mut value).cast()) };
561+
let value = PtrMut::from(&mut value);
565562
// SAFETY: reflect_from_ptr was constructed for the correct type
566563
let dyn_reflect = unsafe { reflect_from_ptr.as_reflect_ptr_mut(value) };
567564
match dyn_reflect.reflect_mut() {
@@ -573,10 +570,8 @@ mod test {
573570
}
574571

575572
{
576-
// SAFETY: lifetime doesn't outlive original value
577-
let value = unsafe { Ptr::new(NonNull::from(&mut value).cast()) };
578573
// SAFETY: reflect_from_ptr was constructed for the correct type
579-
let dyn_reflect = unsafe { reflect_from_ptr.as_reflect_ptr(value) };
574+
let dyn_reflect = unsafe { reflect_from_ptr.as_reflect_ptr(Ptr::from(&value)) };
580575
match dyn_reflect.reflect_ref() {
581576
bevy_reflect::ReflectRef::Struct(strukt) => {
582577
let a = strukt.field("a").unwrap().downcast_ref::<f32>().unwrap();

0 commit comments

Comments
 (0)