diff options
| author | Cristi Cobzarenco <cristi.cobzarenco@gmail.com> | 2016-10-15 16:32:14 +0100 |
|---|---|---|
| committer | Cristi Cobzarenco <cristi.cobzarenco@gmail.com> | 2016-11-05 00:50:41 +0000 |
| commit | 651cf58f2e906fa6d333013891adca5074440bea (patch) | |
| tree | 0a9de6025b1d0605d854beb2cbfbda06fb91c4d2 /src/liballoc/rc.rs | |
| parent | d34318dd538bf4c9175e4138b3e4188ea8211620 (diff) | |
| download | rust-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.rs | 79 |
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; |
