From 18be986c992d521c6ecdd4ded67c798c1fae172e Mon Sep 17 00:00:00 2001
From: Daniel Micay <danielmicay@gmail.com>
Date: Thu, 10 Oct 2013 11:45:52 -0400
Subject: [PATCH] clean up the `Rc`/`RcMut` types and move to libstd

---
 src/libextra/extra.rs                         |   1 -
 src/{libextra => libstd}/rc.rs                | 178 +++++++++---------
 src/libstd/std.rs                             |   1 +
 src/test/compile-fail/issue-7013.rs           |   5 +-
 src/test/compile-fail/no_send-rc.rs           |  18 ++
 .../rcmut-not-const-and-not-owned.rs          |   8 +-
 6 files changed, 118 insertions(+), 93 deletions(-)
 rename src/{libextra => libstd}/rc.rs (65%)
 create mode 100644 src/test/compile-fail/no_send-rc.rs

diff --git a/src/libextra/extra.rs b/src/libextra/extra.rs
index 45e4fe50f25..1305535dc50 100644
--- a/src/libextra/extra.rs
+++ b/src/libextra/extra.rs
@@ -46,7 +46,6 @@ pub use std::os;
 
 pub mod c_vec;
 pub mod io_util;
-pub mod rc;
 
 // Concurrency
 
diff --git a/src/libextra/rc.rs b/src/libstd/rc.rs
similarity index 65%
rename from src/libextra/rc.rs
rename to src/libstd/rc.rs
index fa7cd9025eb..50dff380f00 100644
--- a/src/libextra/rc.rs
+++ b/src/libstd/rc.rs
@@ -8,31 +8,23 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#[allow(missing_doc)];
+/** Task-local reference counted boxes
 
-/** Task-local reference counted smart pointers
+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.
 
-Task-local reference counted smart pointers are an alternative to managed boxes with deterministic
-destruction. They are restricted to containing types that are either `Send` or `Freeze` (or both) to
-prevent cycles.
-
-Neither `Rc<T>` or `RcMut<T>` is ever `Send` and `RcMut<T>` is never `Freeze`. If `T` is `Freeze`, a
-cycle cannot be created with `Rc<T>` because there is no way to modify it after creation.
+The `RcMut` type provides shared ownership of a mutable value. Since multiple owners prevent
+inherited mutability, a dynamic freezing check is used to maintain the invariant that an `&mut`
+reference is a unique handle and the type is marked as non-`Freeze`.
 
 */
 
-
-use std::cast;
-use std::ptr;
-use std::unstable::intrinsics;
-
-// Convert ~T into *mut T without dropping it
-#[inline]
-unsafe fn owned_to_raw<T>(mut box: ~T) -> *mut T {
-    let ptr = ptr::to_mut_unsafe_ptr(box);
-    intrinsics::forget(box);
-    ptr
-}
+use ptr::RawPtr;
+use unstable::intrinsics::transmute;
+use ops::Drop;
+use kinds::{Freeze, Send};
+use clone::{Clone, DeepClone};
 
 struct RcBox<T> {
     value: T,
@@ -43,50 +35,38 @@ struct RcBox<T> {
 #[unsafe_no_drop_flag]
 #[no_send]
 pub struct Rc<T> {
-    priv ptr: *mut RcBox<T>,
-}
-
-impl<T> Rc<T> {
-    unsafe fn new(value: T) -> Rc<T> {
-        Rc{ptr: owned_to_raw(~RcBox{value: value, count: 1})}
-    }
-}
-
-impl<T: Send> Rc<T> {
-    pub fn from_send(value: T) -> Rc<T> {
-        unsafe { Rc::new(value) }
-    }
+    priv ptr: *mut RcBox<T>
 }
 
 impl<T: Freeze> Rc<T> {
-    pub fn from_freeze(value: T) -> Rc<T> {
-        unsafe { Rc::new(value) }
-    }
-}
-
-impl<T> Rc<T> {
+    /// Construct a new reference-counted box from a `Freeze` value
     #[inline]
-    pub fn borrow<'r>(&'r self) -> &'r T {
-        unsafe { cast::copy_lifetime(self, &(*self.ptr).value) }
-    }
-}
-
-#[unsafe_destructor]
-impl<T> Drop for Rc<T> {
-    fn drop(&mut self) {
+    pub fn new(value: T) -> Rc<T> {
         unsafe {
-            if self.ptr.is_not_null() {
-                (*self.ptr).count -= 1;
-                if (*self.ptr).count == 0 {
-                    let _: ~T = cast::transmute(self.ptr);
-                }
-            }
+            Rc::new_unchecked(value)
         }
     }
 }
 
+impl<T> Rc<T> {
+    /// Unsafety construct a new reference-counted box from any value.
+    ///
+    /// If the type is not `Freeze`, the `Rc` box will incorrectly still be considered as a `Freeze`
+    /// type. It is also possible to create cycles, which will leak, and may interact poorly with
+    /// managed pointers.
+    #[inline]
+    pub unsafe fn new_unchecked(value: T) -> Rc<T> {
+        Rc{ptr: transmute(~RcBox{value: value, count: 1})}
+    }
+
+    /// Borrow the value contained in the reference-counted box
+    #[inline]
+    pub fn borrow<'r>(&'r self) -> &'r T {
+        unsafe { &(*self.ptr).value }
+    }
+}
+
 impl<T> Clone for Rc<T> {
-    /// Return a shallow copy of the reference counted pointer.
     #[inline]
     fn clone(&self) -> Rc<T> {
         unsafe {
@@ -97,47 +77,64 @@ impl<T> Clone for Rc<T> {
 }
 
 impl<T: DeepClone> DeepClone for Rc<T> {
-    /// Return a deep copy of the reference counted pointer.
     #[inline]
     fn deep_clone(&self) -> Rc<T> {
-        unsafe { Rc::new(self.borrow().deep_clone()) }
+        unsafe { Rc::new_unchecked(self.borrow().deep_clone()) }
+    }
+}
+
+#[unsafe_destructor]
+impl<T> Drop for Rc<T> {
+    fn drop(&mut self) {
+        unsafe {
+            if self.ptr.is_not_null() {
+                (*self.ptr).count -= 1;
+                if (*self.ptr).count == 0 {
+                    let _: ~RcBox<T> = transmute(self.ptr);
+                }
+            }
+        }
     }
 }
 
 #[cfg(test)]
 mod test_rc {
     use super::*;
-    use std::cell::Cell;
+    use cell::Cell;
 
     #[test]
     fn test_clone() {
-        let x = Rc::from_send(Cell::new(5));
-        let y = x.clone();
-        do x.borrow().with_mut_ref |inner| {
-            *inner = 20;
+        unsafe {
+            let x = Rc::new_unchecked(Cell::new(5));
+            let y = x.clone();
+            do x.borrow().with_mut_ref |inner| {
+                *inner = 20;
+            }
+            assert_eq!(y.borrow().take(), 20);
         }
-        assert_eq!(y.borrow().take(), 20);
     }
 
     #[test]
     fn test_deep_clone() {
-        let x = Rc::from_send(Cell::new(5));
-        let y = x.deep_clone();
-        do x.borrow().with_mut_ref |inner| {
-            *inner = 20;
+        unsafe {
+            let x = Rc::new_unchecked(Cell::new(5));
+            let y = x.deep_clone();
+            do x.borrow().with_mut_ref |inner| {
+                *inner = 20;
+            }
+            assert_eq!(y.borrow().take(), 5);
         }
-        assert_eq!(y.borrow().take(), 5);
     }
 
     #[test]
     fn test_simple() {
-        let x = Rc::from_freeze(5);
+        let x = Rc::new(5);
         assert_eq!(*x.borrow(), 5);
     }
 
     #[test]
     fn test_simple_clone() {
-        let x = Rc::from_freeze(5);
+        let x = Rc::new(5);
         let y = x.clone();
         assert_eq!(*x.borrow(), 5);
         assert_eq!(*y.borrow(), 5);
@@ -145,8 +142,10 @@ mod test_rc {
 
     #[test]
     fn test_destructor() {
-        let x = Rc::from_send(~5);
-        assert_eq!(**x.borrow(), 5);
+        unsafe {
+            let x = Rc::new_unchecked(~5);
+            assert_eq!(**x.borrow(), 5);
+        }
     }
 }
 
@@ -171,21 +170,30 @@ pub struct RcMut<T> {
     priv ptr: *mut RcMutBox<T>,
 }
 
-impl<T> RcMut<T> {
-    unsafe fn new(value: T) -> RcMut<T> {
-        RcMut{ptr: owned_to_raw(~RcMutBox{value: value, count: 1, borrow: Nothing})}
+impl<T: Freeze> RcMut<T> {
+    /// Construct a new mutable reference-counted box from a `Freeze` value
+    #[inline]
+    pub fn new(value: T) -> RcMut<T> {
+        unsafe { RcMut::new_unchecked(value) }
     }
 }
 
 impl<T: Send> RcMut<T> {
+    /// Construct a new mutable reference-counted box from a `Send` value
+    #[inline]
     pub fn from_send(value: T) -> RcMut<T> {
-        unsafe { RcMut::new(value) }
+        unsafe { RcMut::new_unchecked(value) }
     }
 }
 
-impl<T: Freeze> RcMut<T> {
-    pub fn from_freeze(value: T) -> RcMut<T> {
-        unsafe { RcMut::new(value) }
+impl<T> RcMut<T> {
+    /// Unsafety construct a new mutable reference-counted box from any value.
+    ///
+    /// It is possible to create cycles, which will leak, and may interact
+    /// poorly with managed pointers.
+    #[inline]
+    pub unsafe fn new_unchecked(value: T) -> RcMut<T> {
+        RcMut{ptr: transmute(~RcMutBox{value: value, count: 1, borrow: Nothing})}
     }
 }
 
@@ -223,7 +231,7 @@ impl<T> Drop for RcMut<T> {
             if self.ptr.is_not_null() {
                 (*self.ptr).count -= 1;
                 if (*self.ptr).count == 0 {
-                    let _: ~T = cast::transmute(self.ptr);
+                    let _: ~RcMutBox<T> = transmute(self.ptr);
                 }
             }
         }
@@ -247,7 +255,7 @@ impl<T: DeepClone> DeepClone for RcMut<T> {
     fn deep_clone(&self) -> RcMut<T> {
         do self.with_borrow |x| {
             // FIXME: #6497: should avoid freeze (slow)
-            unsafe { RcMut::new(x.deep_clone()) }
+            unsafe { RcMut::new_unchecked(x.deep_clone()) }
         }
     }
 }
@@ -270,7 +278,7 @@ mod test_rc_mut {
 
     #[test]
     fn test_deep_clone() {
-        let x = RcMut::from_freeze(5);
+        let x = RcMut::new(5);
         let y = x.deep_clone();
         do x.with_mut_borrow |value| {
             *value = 20;
@@ -298,7 +306,7 @@ mod test_rc_mut {
 
     #[test]
     fn modify() {
-        let x = RcMut::from_freeze(5);
+        let x = RcMut::new(5);
         let y = x.clone();
 
         do y.with_mut_borrow |a| {
@@ -320,7 +328,7 @@ mod test_rc_mut {
 
     #[test]
     fn release_mutable() {
-        let x = RcMut::from_freeze(5);
+        let x = RcMut::new(5);
         do x.with_mut_borrow |_| {}
         do x.with_borrow |_| {}
     }
@@ -340,7 +348,7 @@ mod test_rc_mut {
     #[test]
     #[should_fail]
     fn mutable_dupe() {
-        let x = RcMut::from_freeze(5);
+        let x = RcMut::new(5);
         let y = x.clone();
 
         do x.with_mut_borrow |_| {
@@ -364,7 +372,7 @@ mod test_rc_mut {
     #[test]
     #[should_fail]
     fn restore_freeze() {
-        let x = RcMut::from_freeze(5);
+        let x = RcMut::new(5);
         let y = x.clone();
 
         do x.with_borrow |_| {
diff --git a/src/libstd/std.rs b/src/libstd/std.rs
index 53837f96593..d35f26785dc 100644
--- a/src/libstd/std.rs
+++ b/src/libstd/std.rs
@@ -132,6 +132,7 @@ pub mod ptr;
 pub mod owned;
 pub mod managed;
 pub mod borrow;
+pub mod rc;
 
 
 /* Core language traits */
diff --git a/src/test/compile-fail/issue-7013.rs b/src/test/compile-fail/issue-7013.rs
index fa22665e8c3..5f39aac19af 100644
--- a/src/test/compile-fail/issue-7013.rs
+++ b/src/test/compile-fail/issue-7013.rs
@@ -8,8 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-extern mod extra;
-use extra::rc::RcMut;
+use std::rc::RcMut;
 
 trait Foo
 {
@@ -37,7 +36,7 @@ struct A
 fn main()
 {
     let a = A {v: ~B{v: None} as ~Foo}; //~ ERROR cannot pack type `~B`, which does not fulfill `Send`
-    let v = RcMut::from_freeze(a); //~ ERROR instantiating a type parameter with an incompatible type
+    let v = RcMut::new(a); //~ ERROR instantiating a type parameter with an incompatible type
     let w = v.clone();
     v.with_mut_borrow(|p| {p.v.set(w.clone());})
 }
diff --git a/src/test/compile-fail/no_send-rc.rs b/src/test/compile-fail/no_send-rc.rs
new file mode 100644
index 00000000000..d884ff7f231
--- /dev/null
+++ b/src/test/compile-fail/no_send-rc.rs
@@ -0,0 +1,18 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::rc::Rc;
+
+fn bar<T: Send>(_: T) {}
+
+fn main() {
+    let x = Rc::new(5);
+    bar(x); //~ ERROR instantiating a type parameter with an incompatible type `std::rc::Rc<int>`, which does not fulfill `Send`
+}
diff --git a/src/test/compile-fail/rcmut-not-const-and-not-owned.rs b/src/test/compile-fail/rcmut-not-const-and-not-owned.rs
index d645f35d96d..fce1f592c62 100644
--- a/src/test/compile-fail/rcmut-not-const-and-not-owned.rs
+++ b/src/test/compile-fail/rcmut-not-const-and-not-owned.rs
@@ -8,13 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-extern mod extra;
+use std::rc::RcMut;
 
 fn o<T: Send>(_: &T) {}
 fn c<T: Freeze>(_: &T) {}
 
 fn main() {
-    let x = extra::rc::RcMut::from_send(0);
-    o(&x); //~ ERROR instantiating a type parameter with an incompatible type `extra::rc::RcMut<int>`, which does not fulfill `Send`
-    c(&x); //~ ERROR instantiating a type parameter with an incompatible type `extra::rc::RcMut<int>`, which does not fulfill `Freeze`
+    let x = RcMut::from_send(0);
+    o(&x); //~ ERROR instantiating a type parameter with an incompatible type `std::rc::RcMut<int>`, which does not fulfill `Send`
+    c(&x); //~ ERROR instantiating a type parameter with an incompatible type `std::rc::RcMut<int>`, which does not fulfill `Freeze`
 }