about summary refs log tree commit diff
path: root/src/liballoc
diff options
context:
space:
mode:
Diffstat (limited to 'src/liballoc')
-rw-r--r--src/liballoc/arc.rs4
-rw-r--r--src/liballoc/heap.rs13
-rw-r--r--src/liballoc/lib.rs1
-rw-r--r--src/liballoc/owned.rs84
-rw-r--r--src/liballoc/rc.rs156
5 files changed, 239 insertions, 19 deletions
diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs
index 6af4083edb2..38ed511c458 100644
--- a/src/liballoc/arc.rs
+++ b/src/liballoc/arc.rs
@@ -376,14 +376,14 @@ mod tests {
 
     #[test]
     fn test_live() {
-        let x = Arc::new(5);
+        let x = Arc::new(5i);
         let y = x.downgrade();
         assert!(y.upgrade().is_some());
     }
 
     #[test]
     fn test_dead() {
-        let x = Arc::new(5);
+        let x = Arc::new(5i);
         let y = x.downgrade();
         drop(x);
         assert!(y.upgrade().is_none());
diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs
index b4d0057778a..dc8280e9b83 100644
--- a/src/liballoc/heap.rs
+++ b/src/liballoc/heap.rs
@@ -99,7 +99,7 @@ pub static mut EMPTY: uint = 12345;
 #[inline]
 unsafe fn exchange_malloc(size: uint, align: uint) -> *mut u8 {
     if size == 0 {
-        &EMPTY as *uint as *mut u8
+        &EMPTY as *const uint as *mut u8
     } else {
         allocate(size, align)
     }
@@ -144,9 +144,10 @@ mod imp {
                       flags: c_int) -> size_t;
         fn je_dallocx(ptr: *mut c_void, flags: c_int);
         fn je_nallocx(size: size_t, flags: c_int) -> size_t;
-        fn je_malloc_stats_print(write_cb: Option<extern "C" fn(cbopaque: *mut c_void, *c_char)>,
+        fn je_malloc_stats_print(write_cb: Option<extern "C" fn(cbopaque: *mut c_void,
+                                                                *const c_char)>,
                                  cbopaque: *mut c_void,
-                                 opts: *c_char);
+                                 opts: *const c_char);
     }
 
     // -lpthread needs to occur after -ljemalloc, the earlier argument isn't enough
@@ -226,7 +227,7 @@ mod imp {
         // a block of memory, so we special case everything under `*uint` to
         // just pass it to malloc, which is guaranteed to align to at least the
         // size of `*uint`.
-        if align < mem::size_of::<*uint>() {
+        if align < mem::size_of::<uint>() {
             libc_heap::malloc_raw(size)
         } else {
             let mut out = 0 as *mut libc::c_void;
@@ -244,7 +245,7 @@ mod imp {
     pub unsafe fn reallocate(ptr: *mut u8, size: uint, align: uint,
                              old_size: uint) -> *mut u8 {
         let new_ptr = allocate(size, align);
-        ptr::copy_memory(new_ptr, ptr as *u8, old_size);
+        ptr::copy_memory(new_ptr, ptr as *const u8, old_size);
         deallocate(ptr, old_size, align);
         return new_ptr;
     }
@@ -328,7 +329,7 @@ mod bench {
     #[bench]
     fn alloc_owned_small(b: &mut Bencher) {
         b.iter(|| {
-            box 10
+            box 10i
         })
     }
 }
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index 29293366e50..26b8ccaf573 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -70,7 +70,6 @@
 
 #![no_std]
 #![feature(lang_items, phase, unsafe_destructor)]
-#![allow(unknown_features)] // NOTE: remove after a stage0 snap
 
 #[phase(plugin, link)]
 extern crate core;
diff --git a/src/liballoc/owned.rs b/src/liballoc/owned.rs
index 6f5d3293556..addec396bbe 100644
--- a/src/liballoc/owned.rs
+++ b/src/liballoc/owned.rs
@@ -16,7 +16,9 @@ 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;
 use core::result::{Ok, Err, Result};
 
@@ -36,7 +38,7 @@ pub static HEAP: () = ();
 
 /// A type that represents a uniquely-owned value.
 #[lang="owned_box"]
-pub struct Box<T>(*T);
+pub struct Box<T>(*mut T);
 
 impl<T: Default> Default for Box<T> {
     fn default() -> Box<T> { box Default::default() }
@@ -64,6 +66,10 @@ impl<T:PartialEq> PartialEq for Box<T> {
 }
 impl<T:PartialOrd> PartialOrd for Box<T> {
     #[inline]
+    fn partial_cmp(&self, other: &Box<T>) -> Option<Ordering> {
+        (**self).partial_cmp(*other)
+    }
+    #[inline]
     fn lt(&self, other: &Box<T>) -> bool { *(*self) < *(*other) }
     #[inline]
     fn le(&self, other: &Box<T>) -> bool { *(*self) <= *(*other) }
@@ -106,6 +112,34 @@ impl AnyOwnExt for Box<Any> {
     }
 }
 
+/// 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> {
+    #[inline]
+    fn move_send<T: 'static>(self) -> Result<Box<T>, Box<Any+Send>> {
+        if self.is::<T>() {
+            unsafe {
+                // Get the raw representation of the trait object
+                let to: TraitObject =
+                    *mem::transmute::<&Box<Any+Send>, &TraitObject>(&self);
+
+                // Prevent destructor on self being run
+                intrinsics::forget(self);
+
+                // Extract the data pointer
+                Ok(mem::transmute(to.data))
+            }
+        } else {
+            Err(self)
+        }
+    }
+}
+
 impl<T: fmt::Show> fmt::Show for Box<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         (**self).fmt(f)
@@ -117,3 +151,51 @@ impl fmt::Show for Box<Any> {
         f.pad("Box<Any>")
     }
 }
+
+#[cfg(test)]
+mod test {
+    #[test]
+    fn test_owned_clone() {
+        let a = box 5i;
+        let b: Box<int> = a.clone();
+        assert!(a == b);
+    }
+
+    #[test]
+    fn any_move() {
+        let a = box 8u as Box<Any>;
+        let b = box Test as Box<Any>;
+
+        match a.move::<uint>() {
+            Ok(a) => { assert!(a == box 8u); }
+            Err(..) => fail!()
+        }
+        match b.move::<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());
+    }
+
+    #[test]
+    fn test_show() {
+        let a = box 8u as Box<Any>;
+        let b = box Test as Box<Any>;
+        let a_str = a.to_str();
+        let b_str = b.to_str();
+        assert_eq!(a_str.as_slice(), "Box<Any>");
+        assert_eq!(b_str.as_slice(), "Box<Any>");
+
+        let a = &8u as &Any;
+        let b = &Test as &Any;
+        let s = format!("{}", a);
+        assert_eq!(s.as_slice(), "&Any");
+        let s = format!("{}", b);
+        assert_eq!(s.as_slice(), "&Any");
+    }
+}
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index a3ca72f1547..d97bce39c2d 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -1,4 +1,4 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -10,16 +10,141 @@
 
 /*! Task-local reference-counted boxes (`Rc` type)
 
-The `Rc` type provides shared ownership of an immutable value. Destruction is deterministic, and
-will occur as soon as the last owner is gone. It is marked as non-sendable because it avoids the
-overhead of atomic reference counting.
+The `Rc` type provides shared ownership of an immutable value. Destruction is
+deterministic, and will occur as soon as the last owner is gone. It is marked
+as non-sendable because it avoids the overhead of atomic reference counting.
 
-The `downgrade` method can be used to create a non-owning `Weak` pointer to the box. A `Weak`
-pointer can be upgraded to an `Rc` pointer, but will return `None` if the value has already been
-freed.
+The `downgrade` method can be used to create a non-owning `Weak` pointer to the
+box. A `Weak` pointer can be upgraded to an `Rc` pointer, but will return
+`None` if the value has already been freed.
 
-For example, a tree with parent pointers can be represented by putting the nodes behind `Strong`
-pointers, and then storing the parent pointers as `Weak` pointers.
+For example, a tree with parent pointers can be represented by putting the
+nodes behind strong `Rc` pointers, and then storing the parent pointers as
+`Weak` pointers.
+
+
+## Examples
+
+Consider a scenario where a set of Gadgets are owned by a given Owner.  We want
+to have our Gadgets point to their Owner.  We can't do this with unique
+ownership, because more than one gadget may belong to the same Owner.  Rc
+allows us to share an Owner between multiple Gadgets, and have the Owner kept
+alive as long as any Gadget points at it.
+
+```rust
+use std::rc::Rc;
+
+struct Owner {
+    name: String
+    // ...other fields
+}
+
+struct Gadget {
+    id: int,
+    owner: Rc<Owner>
+    // ...other fields
+}
+
+fn main() {
+    // Create a reference counted Owner.
+    let gadget_owner : Rc<Owner> = Rc::new(
+            Owner { name: String::from_str("Gadget Man") }
+    );
+
+    // Create Gadgets belonging to gadget_owner.  To increment the reference
+    // count we clone the Rc object.
+    let gadget1 = Gadget { id: 1, owner: gadget_owner.clone() };
+    let gadget2 = Gadget { id: 2, owner: gadget_owner.clone() };
+
+    drop(gadget_owner);
+
+    // Despite dropping gadget_owner, we're still able to print out the name of
+    // the Owner of the Gadgets. This is because we've only dropped the
+    // reference count object, not the Owner it wraps. As long as there are
+    // other Rc objects pointing at the same Owner, it will stay alive. Notice
+    // that the Rc wrapper around Gadget.owner gets automatically dereferenced
+    // for us.
+    println!("Gadget {} owned by {}", gadget1.id, gadget1.owner.name);
+    println!("Gadget {} owned by {}", gadget2.id, gadget2.owner.name);
+
+    // At the end of the method, gadget1 and gadget2 get destroyed, and with
+    // them the last counted references to our Owner.  Gadget Man now gets
+    // destroyed as well.
+}
+```
+
+If our requirements change, and we also need to be able to traverse from
+Owner->Gadget, we will run into problems: an Rc pointer from Owner->Gadget
+introduces a cycle between the objects.  This means that their reference counts
+can never reach 0, and the objects will stay alive: a memory leak.  In order to
+get around this, we can use `Weak` pointers.  These are reference counted
+pointers that don't keep an object alive if there are no normal `Rc` (or
+*strong*) pointers left.
+
+Rust actually makes it somewhat difficult to produce this loop in the first
+place: in order to end up with two objects that point at each other, one of
+them needs to be mutable.  This is problematic because Rc enforces memory
+safety by only giving out shared references to the object it wraps, and these
+don't allow direct mutation.  We need to wrap the part of the object we wish to
+mutate in a `RefCell`, which provides *interior mutability*: a method to
+achieve mutability through a shared reference.  `RefCell` enforces Rust's
+borrowing rules at runtime.  Read the `Cell` documentation for more details on
+interior mutability.
+
+```rust
+use std::rc::Rc;
+use std::rc::Weak;
+use std::cell::RefCell;
+
+struct Owner {
+    name: String,
+    gadgets: RefCell<Vec<Weak<Gadget>>>
+    // ...other fields
+}
+
+struct Gadget {
+    id: int,
+    owner: Rc<Owner>
+    // ...other fields
+}
+
+fn main() {
+    // Create a reference counted Owner.  Note the fact that we've put the
+    // Owner's vector of Gadgets inside a RefCell so that we can mutate it
+    // through a shared reference.
+    let gadget_owner : Rc<Owner> = Rc::new(
+            Owner {
+                name: "Gadget Man".to_string(),
+                gadgets: RefCell::new(Vec::new())
+            }
+    );
+
+    // Create Gadgets belonging to gadget_owner as before.
+    let gadget1 = Rc::new(Gadget{id: 1, owner: gadget_owner.clone()});
+    let gadget2 = Rc::new(Gadget{id: 2, owner: gadget_owner.clone()});
+
+    // Add the Gadgets to their Owner.  To do this we mutably borrow from
+    // the RefCell holding the Owner's Gadgets.
+    gadget_owner.gadgets.borrow_mut().push(gadget1.clone().downgrade());
+    gadget_owner.gadgets.borrow_mut().push(gadget2.clone().downgrade());
+
+    // Iterate over our Gadgets, printing their details out
+    for gadget_opt in gadget_owner.gadgets.borrow().iter() {
+
+        // gadget_opt is a Weak<Gadget>.  Since weak pointers can't guarantee
+        // that their object is still alive, we need to call upgrade() on them
+        // to turn them into a strong reference.  This returns an Option, which
+        // contains a reference to our object if it still exists.
+        let gadget = gadget_opt.upgrade().unwrap();
+        println!("Gadget {} owned by {}", gadget.id, gadget.owner.name);
+    }
+
+    // At the end of the method, gadget_owner, gadget1 and gadget2 get
+    // destroyed.  There are now no strong (Rc) references to the gadgets.
+    // Once they get destroyed, the Gadgets get destroyed.  This zeroes the
+    // reference count on Gadget Man, so he gets destroyed as well.
+}
+```
 
 */
 
@@ -27,6 +152,7 @@ use core::mem::transmute;
 use core::cell::Cell;
 use core::clone::Clone;
 use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
+use core::default::Default;
 use core::kinds::marker;
 use core::ops::{Deref, Drop};
 use core::option::{Option, Some, None};
@@ -152,6 +278,13 @@ impl<T> Clone for Rc<T> {
     }
 }
 
+impl<T: Default> Default for Rc<T> {
+    #[inline]
+    fn default() -> Rc<T> {
+        Rc::new(Default::default())
+    }
+}
+
 impl<T: PartialEq> PartialEq for Rc<T> {
     #[inline(always)]
     fn eq(&self, other: &Rc<T>) -> bool { **self == **other }
@@ -163,6 +296,11 @@ impl<T: Eq> Eq for Rc<T> {}
 
 impl<T: PartialOrd> PartialOrd for Rc<T> {
     #[inline(always)]
+    fn partial_cmp(&self, other: &Rc<T>) -> Option<Ordering> {
+        (**self).partial_cmp(&**other)
+    }
+
+    #[inline(always)]
     fn lt(&self, other: &Rc<T>) -> bool { **self < **other }
 
     #[inline(always)]