Skip to content

Commit

Permalink
Stabilization for owned (now boxed) and cell
Browse files Browse the repository at this point in the history
This PR is the outcome of the library stabilization meeting for the
`liballoc::owned` and `libcore::cell` modules.

Aside from the stability attributes, there are a few breaking changes:

* The `owned` modules is now named `boxed`, to better represent its
  contents. (`box` was unavailable, since it's a keyword.) This will
  help avoid the misconception that `Box` plays a special role wrt
  ownership.

* The `AnyOwnExt` extension trait is renamed to `BoxAny`, and its `move`
  method is renamed to `downcast`, in both cases to improve clarity.

* The recently-added `AnySendOwnExt` extension trait is removed; it was
  not being used and is unnecessary.

[breaking-change]
  • Loading branch information
aturon committed Jul 13, 2014
1 parent b57d272 commit e0ede9c
Show file tree
Hide file tree
Showing 49 changed files with 112 additions and 107 deletions.
59 changes: 19 additions & 40 deletions src/liballoc/owned.rs → src/liballoc/boxed.rs
Expand Up @@ -16,7 +16,6 @@ use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
use core::default::Default;
use core::fmt;
use core::intrinsics;
use core::kinds::Send;
use core::mem;
use core::option::Option;
use core::raw::TraitObject;
Expand All @@ -27,17 +26,19 @@ use core::result::{Ok, Err, Result};
///
/// The following two examples are equivalent:
///
/// use std::owned::HEAP;
/// use std::boxed::HEAP;
///
/// # struct Bar;
/// # impl Bar { fn new(_a: int) { } }
/// let foo = box(HEAP) Bar::new(2);
/// let foo = box Bar::new(2);
#[lang="exchange_heap"]
#[lang = "exchange_heap"]
#[experimental = "may be renamed; uncertain about custom allocator design"]
pub static HEAP: () = ();

/// A type that represents a uniquely-owned value.
#[lang="owned_box"]
#[lang = "owned_box"]
#[unstable = "custom allocators will add an additional type parameter (with default)"]
pub struct Box<T>(*mut T);

impl<T: Default> Default for Box<T> {
Expand All @@ -57,7 +58,6 @@ impl<T: Clone> Clone for Box<T> {
}
}

// box pointers
impl<T:PartialEq> PartialEq for Box<T> {
#[inline]
fn eq(&self, other: &Box<T>) -> bool { *(*self) == *(*other) }
Expand Down Expand Up @@ -85,48 +85,27 @@ impl<T: Ord> Ord for Box<T> {
impl<T: Eq> Eq for Box<T> {}

/// Extension methods for an owning `Any` trait object
pub trait AnyOwnExt {
#[unstable = "post-DST, the signature of `downcast` will change to take `Box<Self>`"]
pub trait BoxAny {
/// Returns the boxed value if it is of type `T`, or
/// `Err(Self)` if it isn't.
fn move<T: 'static>(self) -> Result<Box<T>, Self>;
}

impl AnyOwnExt for Box<Any> {
#[inline]
fn move<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
if self.is::<T>() {
unsafe {
// Get the raw representation of the trait object
let to: TraitObject =
*mem::transmute::<&Box<Any>, &TraitObject>(&self);

// Prevent destructor on self being run
intrinsics::forget(self);
fn downcast<T: 'static>(self) -> Result<Box<T>, Self>;

// Extract the data pointer
Ok(mem::transmute(to.data))
}
} else {
Err(self)
}
/// Deprecated; this method has been renamed to `downcast`.
#[deprecated = "use downcast instead"]
fn move<T: 'static>(self) -> Result<Box<T>, Self> {
self.downcast::<T>()
}
}

/// Extension methods for an owning `Any+Send` trait object
pub trait AnySendOwnExt {
/// Returns the boxed value if it is of type `T`, or
/// `Err(Self)` if it isn't.
fn move_send<T: 'static>(self) -> Result<Box<T>, Self>;
}

impl AnySendOwnExt for Box<Any+Send> {
impl BoxAny for Box<Any> {
#[inline]
fn move_send<T: 'static>(self) -> Result<Box<T>, Box<Any+Send>> {
fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
if self.is::<T>() {
unsafe {
// Get the raw representation of the trait object
let to: TraitObject =
*mem::transmute::<&Box<Any+Send>, &TraitObject>(&self);
*mem::transmute::<&Box<Any>, &TraitObject>(&self);

// Prevent destructor on self being run
intrinsics::forget(self);
Expand Down Expand Up @@ -166,20 +145,20 @@ mod test {
let a = box 8u as Box<Any>;
let b = box Test as Box<Any>;

match a.move::<uint>() {
match a.downcast::<uint>() {
Ok(a) => { assert!(a == box 8u); }
Err(..) => fail!()
}
match b.move::<Test>() {
match b.downcast::<Test>() {
Ok(a) => { assert!(a == box Test); }
Err(..) => fail!()
}

let a = box 8u as Box<Any>;
let b = box Test as Box<Any>;

assert!(a.move::<Box<Test>>().is_err());
assert!(b.move::<Box<uint>>().is_err());
assert!(a.downcast::<Box<Test>>().is_err());
assert!(b.downcast::<Box<uint>>().is_err());
}

#[test]
Expand Down
14 changes: 10 additions & 4 deletions src/liballoc/lib.rs
Expand Up @@ -21,11 +21,11 @@
//!
//! Currently, there are four major definitions in this library.
//!
//! ## Owned pointers
//! ## Boxed values
//!
//! The [`Box`](owned/index.html) type is the core owned pointer type in rust.
//! The [`Box`](boxed/index.html) type is the core owned pointer type in rust.
//! There can only be one owner of a `Box`, and the owner can decide to mutate
//! the contents.
//! the contents, which live on the heap.
//!
//! This type can be sent among tasks efficiently as the size of a `Box` value
//! is just a pointer. Tree-like data structures are often built on owned
Expand Down Expand Up @@ -82,6 +82,12 @@ extern crate libc;
#[cfg(test)] #[phase(plugin, link)] extern crate std;
#[cfg(test)] #[phase(plugin, link)] extern crate log;

// The deprecated name of the boxed module

#[deprecated = "use boxed instead"]
#[cfg(not(test))]
pub use owned = boxed;

// Heaps provided for low-level allocation strategies

pub mod heap;
Expand All @@ -91,7 +97,7 @@ pub mod util;
// Primitive types using the heaps above

#[cfg(not(test))]
pub mod owned;
pub mod boxed;
pub mod arc;
pub mod rc;

Expand Down
2 changes: 1 addition & 1 deletion src/libcollections/btree.rs
Expand Up @@ -20,7 +20,7 @@

use core::prelude::*;

use alloc::owned::Box;
use alloc::boxed::Box;
use core::fmt;
use core::fmt::Show;

Expand Down
2 changes: 1 addition & 1 deletion src/libcollections/dlist.rs
Expand Up @@ -23,7 +23,7 @@

use core::prelude::*;

use alloc::owned::Box;
use alloc::boxed::Box;
use core::default::Default;
use core::fmt;
use core::iter;
Expand Down
2 changes: 1 addition & 1 deletion src/libcollections/hash/mod.rs
Expand Up @@ -65,7 +65,7 @@

use core::prelude::*;

use alloc::owned::Box;
use alloc::boxed::Box;
use alloc::rc::Rc;
use core::intrinsics::TypeId;
use core::mem;
Expand Down
2 changes: 1 addition & 1 deletion src/libcollections/treemap.rs
Expand Up @@ -14,7 +14,7 @@

use core::prelude::*;

use alloc::owned::Box;
use alloc::boxed::Box;
use core::default::Default;
use core::fmt;
use core::fmt::Show;
Expand Down
2 changes: 1 addition & 1 deletion src/libcollections/trie.rs
Expand Up @@ -12,7 +12,7 @@

use core::prelude::*;

use alloc::owned::Box;
use alloc::boxed::Box;
use core::default::Default;
use core::mem::zeroed;
use core::mem;
Expand Down
24 changes: 21 additions & 3 deletions src/libcore/cell.rs
Expand Up @@ -163,11 +163,13 @@ use option::{None, Option, Some};
use ty::Unsafe;

/// A mutable memory location that admits only `Copy` data.
#[unstable = "likely to be renamed; otherwise stable"]
pub struct Cell<T> {
value: Unsafe<T>,
noshare: marker::NoShare,
}

#[stable]
impl<T:Copy> Cell<T> {
/// Creates a new `Cell` containing the given value.
pub fn new(value: T) -> Cell<T> {
Expand All @@ -192,20 +194,22 @@ impl<T:Copy> Cell<T> {
}
}

#[unstable]
#[unstable = "waiting for `Clone` trait to become stable"]
impl<T:Copy> Clone for Cell<T> {
fn clone(&self) -> Cell<T> {
Cell::new(self.get())
}
}

#[unstable = "waiting for `PartialEq` trait to become stable"]
impl<T:PartialEq + Copy> PartialEq for Cell<T> {
fn eq(&self, other: &Cell<T>) -> bool {
self.get() == other.get()
}
}

/// A mutable memory location with dynamically checked borrow rules
#[unstable = "likely to be renamed; otherwise stable"]
pub struct RefCell<T> {
value: Unsafe<T>,
borrow: Cell<BorrowFlag>,
Expand All @@ -221,6 +225,7 @@ static WRITING: BorrowFlag = -1;

impl<T> RefCell<T> {
/// Create a new `RefCell` containing `value`
#[stable]
pub fn new(value: T) -> RefCell<T> {
RefCell {
value: Unsafe::new(value),
Expand All @@ -231,6 +236,7 @@ impl<T> RefCell<T> {
}

/// Consumes the `RefCell`, returning the wrapped value.
#[unstable = "may be renamed, depending on global conventions"]
pub fn unwrap(self) -> T {
debug_assert!(self.borrow.get() == UNUSED);
unsafe{self.value.unwrap()}
Expand All @@ -242,6 +248,7 @@ impl<T> RefCell<T> {
/// immutable borrows can be taken out at the same time.
///
/// Returns `None` if the value is currently mutably borrowed.
#[unstable = "may be renamed, depending on global conventions"]
pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
match self.borrow.get() {
WRITING => None,
Expand All @@ -260,6 +267,7 @@ impl<T> RefCell<T> {
/// # Failure
///
/// Fails if the value is currently mutably borrowed.
#[unstable]
pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
match self.try_borrow() {
Some(ptr) => ptr,
Expand All @@ -273,6 +281,7 @@ impl<T> RefCell<T> {
/// cannot be borrowed while this borrow is active.
///
/// Returns `None` if the value is currently borrowed.
#[unstable = "may be renamed, depending on global conventions"]
pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
match self.borrow.get() {
UNUSED => {
Expand All @@ -291,6 +300,7 @@ impl<T> RefCell<T> {
/// # Failure
///
/// Fails if the value is currently borrowed.
#[unstable]
pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
match self.try_borrow_mut() {
Some(ptr) => ptr,
Expand All @@ -299,27 +309,30 @@ impl<T> RefCell<T> {
}
}

#[unstable]
#[unstable = "waiting for `Clone` to become stable"]
impl<T: Clone> Clone for RefCell<T> {
fn clone(&self) -> RefCell<T> {
RefCell::new(self.borrow().clone())
}
}

#[unstable = "waiting for `PartialEq` to become stable"]
impl<T: PartialEq> PartialEq for RefCell<T> {
fn eq(&self, other: &RefCell<T>) -> bool {
*self.borrow() == *other.borrow()
}
}

/// Wraps a borrowed reference to a value in a `RefCell` box.
#[unstable]
pub struct Ref<'b, T> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
_parent: &'b RefCell<T>
}

#[unsafe_destructor]
#[unstable]
impl<'b, T> Drop for Ref<'b, T> {
fn drop(&mut self) {
let borrow = self._parent.borrow.get();
Expand All @@ -328,6 +341,7 @@ impl<'b, T> Drop for Ref<'b, T> {
}
}

#[unstable = "waiting for `Deref` to become stable"]
impl<'b, T> Deref<T> for Ref<'b, T> {
#[inline]
fn deref<'a>(&'a self) -> &'a T {
Expand All @@ -341,7 +355,7 @@ impl<'b, T> Deref<T> for Ref<'b, T> {
///
/// A `Clone` implementation would interfere with the widespread
/// use of `r.borrow().clone()` to clone the contents of a `RefCell`.
#[experimental]
#[experimental = "likely to be moved to a method, pending language changes"]
pub fn clone_ref<'b, T>(orig: &Ref<'b, T>) -> Ref<'b, T> {
// Since this Ref exists, we know the borrow flag
// is not set to WRITING.
Expand All @@ -355,13 +369,15 @@ pub fn clone_ref<'b, T>(orig: &Ref<'b, T>) -> Ref<'b, T> {
}

/// Wraps a mutable borrowed reference to a value in a `RefCell` box.
#[unstable]
pub struct RefMut<'b, T> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
_parent: &'b RefCell<T>
}

#[unsafe_destructor]
#[unstable]
impl<'b, T> Drop for RefMut<'b, T> {
fn drop(&mut self) {
let borrow = self._parent.borrow.get();
Expand All @@ -370,13 +386,15 @@ impl<'b, T> Drop for RefMut<'b, T> {
}
}

#[unstable = "waiting for `Deref` to become stable"]
impl<'b, T> Deref<T> for RefMut<'b, T> {
#[inline]
fn deref<'a>(&'a self) -> &'a T {
unsafe { &*self._parent.value.get() }
}
}

#[unstable = "waiting for `DerefMut` to become stable"]
impl<'b, T> DerefMut<T> for RefMut<'b, T> {
#[inline]
fn deref_mut<'a>(&'a mut self) -> &'a mut T {
Expand Down
2 changes: 1 addition & 1 deletion src/librustrt/args.rs
Expand Up @@ -45,7 +45,7 @@ pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() }
mod imp {
use core::prelude::*;

use alloc::owned::Box;
use alloc::boxed::Box;
use collections::vec::Vec;
use core::mem;
use core::slice;
Expand Down
2 changes: 1 addition & 1 deletion src/librustrt/at_exit_imp.rs
Expand Up @@ -14,7 +14,7 @@

use core::prelude::*;

use alloc::owned::Box;
use alloc::boxed::Box;
use collections::vec::Vec;
use core::atomics;
use core::mem;
Expand Down
2 changes: 1 addition & 1 deletion src/librustrt/lib.rs
Expand Up @@ -37,7 +37,7 @@ pub use self::unwind::{begin_unwind, begin_unwind_fmt};

use core::prelude::*;

use alloc::owned::Box;
use alloc::boxed::Box;
use core::any::Any;

use task::{Task, BlockedTask, TaskOpts};
Expand Down

5 comments on commit e0ede9c

@bors
Copy link
Contributor

@bors bors commented on e0ede9c Jul 13, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from alexcrichton
at aturon@e0ede9c

@bors
Copy link
Contributor

@bors bors commented on e0ede9c Jul 13, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging aturon/rust/box-cell-stability = e0ede9c into auto

@bors
Copy link
Contributor

@bors bors commented on e0ede9c Jul 13, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aturon/rust/box-cell-stability = e0ede9c merged ok, testing candidate = ffd9966

@bors
Copy link
Contributor

@bors bors commented on e0ede9c Jul 13, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fast-forwarding master to auto = ffd9966

Please sign in to comment.