chiark / gitweb /
docs and box
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Thu, 14 Nov 2024 23:30:44 +0000 (23:30 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Thu, 14 Nov 2024 23:30:44 +0000 (23:30 +0000)
src/lib.rs

index f13d92910ce27b06d7899d206368ec7e1a052a6a..a859008d09c4f278025404f9aae360f4d4804fb1 100644 (file)
@@ -115,8 +115,8 @@ pub struct Ptr<T: ?Sized> {
     ptr: NonNull<T>,
 }
 
-unsafe impl<T: Sync> Sync for Ptr<T> {}
-unsafe impl<T: Send> Send for Ptr<T> {}
+unsafe impl<T: Sync + ?Sized> Sync for Ptr<T> {}
+unsafe impl<T: Send + ?Sized> Send for Ptr<T> {}
 
 /// Singleton, used for compile-time alias checking
 #[derive(Debug)] // Not Clone or Copy
@@ -249,19 +249,14 @@ impl<T: Sealed> Sealed for &mut T {}
 
 //---------- principal API for borrowing etc. ----------
 
-impl<T> Clone for Ptr<T> { fn clone(&self) -> Self { *self } }
-impl<T> Copy for Ptr<T> {}
+impl<T: ?Sized> Clone for Ptr<T> { fn clone(&self) -> Self { *self } }
+impl<T: ?Sized> Copy for Ptr<T> {}
 
-impl<T> Ptr<T> {
-    pub fn new_heap(t: T) -> Self {
-        let b = Box::new(t);
-        let ptr = Box::into_raw(b);
-        let ptr = unsafe {
-            // SAFETY
-            // Box.into_raw() guarantees it's not null
-            NonNull::new_unchecked(ptr)
-        };
-        Ptr { ptr }
+impl<T: ?Sized> Ptr<T> {
+    pub fn new_heap(t: T) -> Self
+    where T: Sized
+    {
+        Box::new(t).into()
     }
 
     #[inline]
@@ -299,7 +294,9 @@ impl<T> Ptr<T> {
     ///
     /// # SAFETY
     ///
-    /// `self` must have come from `new_heap`.
+    /// `self` must have come from `new_heap`,
+    /// and be the only remaining copy of this `Ptr`
+    /// (or the only one which will be used).
     ///
     /// All copies of `self` will be invalidated.
     ///
@@ -311,7 +308,30 @@ impl<T> Ptr<T> {
     ///
     /// (The compiler will check that no borrows are live.)
     #[inline]
-    pub unsafe fn free_heap<'a>(self, tok: impl IsMutToken<'a>) -> T {
+    pub unsafe fn free_heap<'a>(self, tok: impl IsMutToken<'a>) {
+        let _t: Box<T> = unsafe { self.into_box(tok) };
+    }
+
+    /// Frees a `Ptr` that was made with `new_heap` and returns the `T`
+    ///
+    /// # SAFETY
+    ///
+    /// The same rules as [`free_heap`](Ptr::free_heap) apply.
+    #[inline]
+    pub unsafe fn from_heap<'a>(self, tok: impl IsMutToken<'a>) -> T
+    where T: Sized
+    {
+        let t: Box<T> = unsafe { self.into_box(tok) };
+        *t
+    }
+
+    /// Converts a `Ptr` that was made with `new_heap` into a `Box<T>`
+    ///
+    /// # SAFETY
+    ///
+    /// The same rules as [`free_heap`](Ptr::free_heap) apply.
+    #[inline]
+    pub unsafe fn into_box<'a>(self, tok: impl IsMutToken<'a>) -> Box<T> {
         let _ = tok;
         let t: Box<T> = unsafe {
             // SAFETY
@@ -324,7 +344,7 @@ impl<T> Ptr<T> {
             // is going to do this.
             Box::from_raw(self.ptr.as_ptr())
         };
-        *t
+        t
     }
 
 /*
@@ -362,16 +382,28 @@ impl NoAliasSingleton {
 
 //---------- helpful impls ----------
 
-pub trait OptionPtrExt<T> {
+impl<T: ?Sized> From<Box<T>> for Ptr<T> {
+    fn from(b: Box<T>) -> Ptr<T> {
+        let ptr = Box::into_raw(b);
+        let ptr = unsafe {
+            // SAFETY
+            // Box.into_raw() guarantees it's not null
+            NonNull::new_unchecked(ptr)
+        };
+        Ptr { ptr }
+    }
+}
+
+pub trait OptionPtrExt<T: ?Sized> {
     fn as_ptr(self) -> Option<*mut T>;
 }
-impl<T> OptionPtrExt<T> for Option<Ptr<T>> {
+impl<T: ?Sized> OptionPtrExt<T> for Option<Ptr<T>> {
     fn as_ptr(self) -> Option<*mut T> {
         self.map(|p| p.ptr.as_ptr())
     }
 }
 
-impl<T> Debug for Ptr<T> {
+impl<T: ?Sized> Debug for Ptr<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_tuple("Ptr").field(&self.ptr).finish()
     }