about summary refs log tree commit diff
path: root/src/liballoc
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-02-01 21:53:53 +0000
committerbors <bors@rust-lang.org>2015-02-01 21:53:53 +0000
commitca4b9674c26c1de07a2042cb68e6a062d7184cef (patch)
tree759ff3ca5e735f22b9cc47a4bec21e87aa204262 /src/liballoc
parentc2bda2a5bb55e2ed54fecd2a03b133bb108e66e7 (diff)
parent5a722f8632eabfa5a776171ebdd6c1f6385098c7 (diff)
downloadrust-ca4b9674c26c1de07a2042cb68e6a062d7184cef.tar.gz
rust-ca4b9674c26c1de07a2042cb68e6a062d7184cef.zip
Auto merge of #21318 - stepancheg:box-fns, r=alexcrichton
Functions are needed for safety and convenience.

It is a common pattern to use `mem::transmute` to convert between
`Box` and raw pointer, like this:

```
let b = Box::new(3);
let p = mem::transmute(b);
// pass `p` to some C library
```

After this commit, conversion can be written as:

```
let p = b.into_raw();
```

`into_raw` and `from_raw` functions are still unsafe, but they are
much safer than `mem::transmute`, because *raw functions do not
convert between incompatible pointers. For example, this likely
incorrect code can be successfully compiled:

```
let p: *mut u64 = ...
let b: Box<u32> = mem::transmute(p);
```

Using `from_raw` results in compile-time error:

```
let p: *mut u64 = ...
let b: Box<u32> = Box::from_raw(p); // compile-time error
```

`into_raw` and `from_raw` functions are similar to C++ `std::unique_ptr`
`release` function [1] and constructor from pointer [2].

[1] http://en.cppreference.com/w/cpp/memory/unique_ptr/release
[2] http://en.cppreference.com/w/cpp/memory/unique_ptr/unique_ptr
Diffstat (limited to 'src/liballoc')
-rw-r--r--src/liballoc/boxed.rs46
-rw-r--r--src/liballoc/boxed_test.rs42
2 files changed, 88 insertions, 0 deletions
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index 91577e30d9a..504b58d8ad1 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -102,6 +102,52 @@ impl<T> Box<T> {
     }
 }
 
+impl<T : ?Sized> Box<T> {
+    /// Constructs a box from the raw pointer.
+    ///
+    /// After this function call, pointer is owned by resulting box.
+    /// In particular, it means that `Box` destructor calls destructor
+    /// of `T` and releases memory. Since the way `Box` allocates and
+    /// releases memory is unspecified, so the only valid pointer to
+    /// pass to this function is the one taken from another `Box` with
+    /// `box::into_raw` function.
+    ///
+    /// Function is unsafe, because improper use of this function may
+    /// lead to memory problems like double-free, for example if the
+    /// function is called twice on the same raw pointer.
+    #[unstable(feature = "alloc",
+               reason = "may be renamed or moved out of Box scope")]
+    pub unsafe fn from_raw(raw: *mut T) -> Self {
+        mem::transmute(raw)
+    }
+}
+
+/// Consumes the `Box`, returning the wrapped raw pointer.
+///
+/// After call to this function, caller is responsible for the memory
+/// previously managed by `Box`, in particular caller should properly
+/// destroy `T` and release memory. The proper way to do it is to
+/// convert pointer back to `Box` with `Box::from_raw` function, because
+/// `Box` does not specify, how memory is allocated.
+///
+/// Function is unsafe, because result of this function is no longer
+/// automatically managed that may lead to memory or other resource
+/// leak.
+///
+/// # Example
+/// ```
+/// use std::boxed;
+///
+/// let seventeen = Box::new(17u32);
+/// let raw = unsafe { boxed::into_raw(seventeen) };
+/// let boxed_again = unsafe { Box::from_raw(raw) };
+/// ```
+#[unstable(feature = "alloc",
+           reason = "may be renamed")]
+pub unsafe fn into_raw<T : ?Sized>(b: Box<T>) -> *mut T {
+    mem::transmute(b)
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Default> Default for Box<T> {
     #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/liballoc/boxed_test.rs b/src/liballoc/boxed_test.rs
index 4ffb94e7a61..f7ddfcb09d7 100644
--- a/src/liballoc/boxed_test.rs
+++ b/src/liballoc/boxed_test.rs
@@ -15,6 +15,7 @@ use core::ops::Deref;
 use core::result::Result::{Ok, Err};
 use core::clone::Clone;
 
+use std::boxed;
 use std::boxed::Box;
 use std::boxed::BoxAny;
 
@@ -73,3 +74,44 @@ fn deref() {
     fn homura<T: Deref<Target=i32>>(_: T) { }
     homura(Box::new(765i32));
 }
+
+#[test]
+fn raw_sized() {
+    unsafe {
+        let x = Box::new(17i32);
+        let p = boxed::into_raw(x);
+        assert_eq!(17, *p);
+        *p = 19;
+        let y = Box::from_raw(p);
+        assert_eq!(19, *y);
+    }
+}
+
+#[test]
+fn raw_trait() {
+    trait Foo {
+        fn get(&self) -> u32;
+        fn set(&mut self, value: u32);
+    }
+
+    struct Bar(u32);
+
+    impl Foo for Bar {
+        fn get(&self) -> u32 {
+            self.0
+        }
+
+        fn set(&mut self, value: u32) {
+            self.0 = value;
+        }
+    }
+
+    unsafe {
+        let x: Box<Foo> = Box::new(Bar(17));
+        let p = boxed::into_raw(x);
+        assert_eq!(17, (*p).get());
+        (*p).set(19);
+        let y: Box<Foo> = Box::from_raw(p);
+        assert_eq!(19, y.get());
+    }
+}