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>
			
			
This commit is contained in:
		
							parent
							
								
									635320f172
								
							
						
					
					
						commit
						f2f8f9097f
					
				@ -3,7 +3,7 @@
 | 
			
		||||
#![warn(missing_docs)]
 | 
			
		||||
 | 
			
		||||
use core::{
 | 
			
		||||
    cell::UnsafeCell, marker::PhantomData, mem::MaybeUninit, num::NonZeroUsize, ptr::NonNull,
 | 
			
		||||
    cell::UnsafeCell, marker::PhantomData, mem::ManuallyDrop, num::NonZeroUsize, ptr::NonNull,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Type-erased borrow of some unknown type chosen when constructing this type.
 | 
			
		||||
@ -98,6 +98,9 @@ macro_rules! impl_ptr {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl_ptr!(Ptr);
 | 
			
		||||
impl_ptr!(PtrMut);
 | 
			
		||||
impl_ptr!(OwningPtr);
 | 
			
		||||
 | 
			
		||||
impl<'a> Ptr<'a> {
 | 
			
		||||
    /// Transforms this [`Ptr`] into an [`PtrMut`]
 | 
			
		||||
    ///
 | 
			
		||||
@ -127,7 +130,16 @@ impl<'a> Ptr<'a> {
 | 
			
		||||
        self.0.as_ptr()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
impl_ptr!(PtrMut);
 | 
			
		||||
 | 
			
		||||
impl<'a, T> From<&'a T> for Ptr<'a> {
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn from(val: &'a T) -> Self {
 | 
			
		||||
        // SAFETY: The returned pointer has the same lifetime as the passed reference.
 | 
			
		||||
        // Access is immutable.
 | 
			
		||||
        unsafe { Self::new(NonNull::from(val).cast()) }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> PtrMut<'a> {
 | 
			
		||||
    /// Transforms this [`PtrMut`] into an [`OwningPtr`]
 | 
			
		||||
    ///
 | 
			
		||||
@ -157,15 +169,24 @@ impl<'a> PtrMut<'a> {
 | 
			
		||||
        self.0.as_ptr()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
impl_ptr!(OwningPtr);
 | 
			
		||||
 | 
			
		||||
impl<'a, T> From<&'a mut T> for PtrMut<'a> {
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn from(val: &'a mut T) -> Self {
 | 
			
		||||
        // SAFETY: The returned pointer has the same lifetime as the passed reference.
 | 
			
		||||
        // The reference is mutable, and thus will not alias.
 | 
			
		||||
        unsafe { Self::new(NonNull::from(val).cast()) }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> OwningPtr<'a> {
 | 
			
		||||
    /// Consumes a value and creates an [`OwningPtr`] to it while ensuring a double drop does not happen.
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn make<T, F: FnOnce(OwningPtr<'_>) -> R, R>(val: T, f: F) -> R {
 | 
			
		||||
        let mut temp = MaybeUninit::new(val);
 | 
			
		||||
        // SAFETY: `temp.as_mut_ptr()` is a reference to a local value on the stack, so it cannot be null
 | 
			
		||||
        let ptr = unsafe { NonNull::new_unchecked(temp.as_mut_ptr().cast::<u8>()) };
 | 
			
		||||
        f(Self(ptr, PhantomData))
 | 
			
		||||
        let mut temp = ManuallyDrop::new(val);
 | 
			
		||||
        // SAFETY: The value behind the pointer will not get dropped or observed later,
 | 
			
		||||
        // so it's safe to promote it to an owning pointer.
 | 
			
		||||
        f(unsafe { PtrMut::from(&mut *temp).promote() })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Consumes the [`OwningPtr`] to obtain ownership of the underlying data of type `T`.
 | 
			
		||||
 | 
			
		||||
@ -475,7 +475,7 @@ impl<T: for<'a> Deserialize<'a> + Reflect> FromType<T> for ReflectDeserialize {
 | 
			
		||||
/// type_registry.register::<Reflected>();
 | 
			
		||||
///
 | 
			
		||||
/// let mut value = Reflected("Hello world!".to_string());
 | 
			
		||||
/// let value = unsafe { Ptr::new(NonNull::from(&mut value).cast()) };
 | 
			
		||||
/// let value = Ptr::from(&value);
 | 
			
		||||
///
 | 
			
		||||
/// let reflect_data = type_registry.get(std::any::TypeId::of::<Reflected>()).unwrap();
 | 
			
		||||
/// let reflect_from_ptr = reflect_data.data::<ReflectFromPtr>().unwrap();
 | 
			
		||||
@ -534,8 +534,6 @@ impl<T: Reflect> FromType<T> for ReflectFromPtr {
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod test {
 | 
			
		||||
    use std::ptr::NonNull;
 | 
			
		||||
 | 
			
		||||
    use crate::{GetTypeRegistration, ReflectFromPtr, TypeRegistration};
 | 
			
		||||
    use bevy_ptr::{Ptr, PtrMut};
 | 
			
		||||
    use bevy_utils::HashMap;
 | 
			
		||||
@ -560,8 +558,7 @@ mod test {
 | 
			
		||||
 | 
			
		||||
        let mut value = Foo { a: 1.0 };
 | 
			
		||||
        {
 | 
			
		||||
            // SAFETY: lifetime doesn't outlive original value, access is unique
 | 
			
		||||
            let value = unsafe { PtrMut::new(NonNull::from(&mut value).cast()) };
 | 
			
		||||
            let value = PtrMut::from(&mut value);
 | 
			
		||||
            // SAFETY: reflect_from_ptr was constructed for the correct type
 | 
			
		||||
            let dyn_reflect = unsafe { reflect_from_ptr.as_reflect_ptr_mut(value) };
 | 
			
		||||
            match dyn_reflect.reflect_mut() {
 | 
			
		||||
@ -573,10 +570,8 @@ mod test {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
            // SAFETY: lifetime doesn't outlive original value
 | 
			
		||||
            let value = unsafe { Ptr::new(NonNull::from(&mut value).cast()) };
 | 
			
		||||
            // SAFETY: reflect_from_ptr was constructed for the correct type
 | 
			
		||||
            let dyn_reflect = unsafe { reflect_from_ptr.as_reflect_ptr(value) };
 | 
			
		||||
            let dyn_reflect = unsafe { reflect_from_ptr.as_reflect_ptr(Ptr::from(&value)) };
 | 
			
		||||
            match dyn_reflect.reflect_ref() {
 | 
			
		||||
                bevy_reflect::ReflectRef::Struct(strukt) => {
 | 
			
		||||
                    let a = strukt.field("a").unwrap().downcast_ref::<f32>().unwrap();
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user