about summary refs log tree commit diff
path: root/src/liballoc/rc.rs
diff options
context:
space:
mode:
authorCristi Cobzarenco <cristi.cobzarenco@gmail.com>2016-10-15 16:32:14 +0100
committerCristi Cobzarenco <cristi.cobzarenco@gmail.com>2016-11-05 00:50:41 +0000
commit651cf58f2e906fa6d333013891adca5074440bea (patch)
tree0a9de6025b1d0605d854beb2cbfbda06fb91c4d2 /src/liballoc/rc.rs
parentd34318dd538bf4c9175e4138b3e4188ea8211620 (diff)
downloadrust-651cf58f2e906fa6d333013891adca5074440bea.tar.gz
rust-651cf58f2e906fa6d333013891adca5074440bea.zip
Add `{into,from}_raw` to Rc and Arc
Diffstat (limited to 'src/liballoc/rc.rs')
-rw-r--r--src/liballoc/rc.rs79
1 files changed, 79 insertions, 0 deletions
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index 699f777138d..bd87abc720d 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -363,6 +363,68 @@ impl<T> Rc<T> {
     pub fn would_unwrap(this: &Self) -> bool {
         Rc::strong_count(&this) == 1
     }
+
+    /// Consumes the `Rc`, returning the wrapped pointer.
+    ///
+    /// To avoid a memory leak the pointer must be converted back to an `Rc` using
+    /// [`Rc::from_raw`][from_raw].
+    ///
+    /// [from_raw]: struct.Rc.html#method.from_raw
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(rc_raw)]
+    ///
+    /// use std::rc::Rc;
+    ///
+    /// let x = Rc::new(10);
+    /// let x_ptr = Rc::into_raw(x);
+    /// assert_eq!(unsafe { *x_ptr }, 10);
+    /// ```
+    #[unstable(feature = "rc_raw", issue = "37197")]
+    pub fn into_raw(this: Self) -> *mut T {
+        let ptr = unsafe { &mut (**this.ptr).value as *mut _ };
+        mem::forget(this);
+        ptr
+    }
+
+    /// Constructs an `Rc` from a raw pointer.
+    ///
+    /// The raw pointer must have been previously returned by a call to a
+    /// [`Rc::into_raw`][into_raw].
+    ///
+    /// This function is unsafe because improper use may lead to memory problems. For example, a
+    /// double-free may occur if the function is called twice on the same raw pointer.
+    ///
+    /// [into_raw]: struct.Rc.html#method.into_raw
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(rc_raw)]
+    ///
+    /// use std::rc::Rc;
+    ///
+    /// let x = Rc::new(10);
+    /// let x_ptr = Rc::into_raw(x);
+    ///
+    /// unsafe {
+    ///     // Convert back to an `Rc` to prevent leak.
+    ///     let x = Rc::from_raw(x_ptr);
+    ///     assert_eq!(*x, 10);
+    ///
+    ///     // Further calls to `Rc::from_raw(x_ptr)` would be memory unsafe.
+    /// }
+    ///
+    /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling!
+    /// ```
+    #[unstable(feature = "rc_raw", issue = "37197")]
+    pub unsafe fn from_raw(ptr: *mut T) -> Self {
+        // To find the corresponding pointer to the `RcBox` we need to subtract the offset of the
+        // `value` field from the pointer.
+        Rc { ptr: Shared::new((ptr as *mut u8).offset(-offset_of!(RcBox<T>, value)) as *mut _) }
+    }
 }
 
 impl<T: ?Sized> Rc<T> {
@@ -1262,6 +1324,23 @@ mod tests {
     }
 
     #[test]
+    fn into_from_raw() {
+        let x = Rc::new(box "hello");
+        let y = x.clone();
+
+        let x_ptr = Rc::into_raw(x);
+        drop(y);
+        unsafe {
+            assert_eq!(**x_ptr, "hello");
+
+            let x = Rc::from_raw(x_ptr);
+            assert_eq!(**x, "hello");
+
+            assert_eq!(Rc::try_unwrap(x).map(|x| *x), Ok("hello"));
+        }
+    }
+
+    #[test]
     fn get_mut() {
         let mut x = Rc::new(3);
         *Rc::get_mut(&mut x).unwrap() = 4;