about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-05-15 12:22:58 -0700
committerbors <bors@rust-lang.org>2013-05-15 12:22:58 -0700
commit8a15333c06b8ba491e1654c3fca3fa21d21def9b (patch)
treefaba4e5896e4f9c2f200716afa1f4d009a3daae3
parentf4c88c7da0503d4eb1109599a51537f750667320 (diff)
parentcda3ac905a56dc6580429eea259143d30a7f3c02 (diff)
downloadrust-8a15333c06b8ba491e1654c3fca3fa21d21def9b.tar.gz
rust-8a15333c06b8ba491e1654c3fca3fa21d21def9b.zip
auto merge of #6498 : thestinger/rust/deep_clone, r=thestinger
This is mostly for `std::rc` and `std::arc` (but I haven't implemented it for ARC yet).

Implementing it correctly for managed boxes is *very* non-trivial. It would probably require an unholy mix of reflection and TLS.
-rw-r--r--src/libcore/cell.rs7
-rw-r--r--src/libcore/clone.rs57
-rw-r--r--src/libcore/option.rs10
-rw-r--r--src/libcore/prelude.rs2
-rw-r--r--src/libstd/rc.rs78
5 files changed, 139 insertions, 15 deletions
diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs
index cacde5535db..87e8d0525e5 100644
--- a/src/libcore/cell.rs
+++ b/src/libcore/cell.rs
@@ -21,10 +21,17 @@ Similar to a mutable option type, but friendlier.
 */
 
 #[mutable]
+#[deriving(Clone)]
 pub struct Cell<T> {
     priv value: Option<T>
 }
 
+impl<T: DeepClone> DeepClone for Cell<T> {
+    fn deep_clone(&self) -> Cell<T> {
+        Cell{value: self.value.deep_clone()}
+    }
+}
+
 impl<T:cmp::Eq> cmp::Eq for Cell<T> {
     fn eq(&self, other: &Cell<T>) -> bool {
         (self.value) == (other.value)
diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs
index 9da970918b0..2ff860916c5 100644
--- a/src/libcore/clone.rs
+++ b/src/libcore/clone.rs
@@ -23,17 +23,12 @@ by convention implementing the `Clone` trait and calling the
 */
 
 pub trait Clone {
-    /// Return a deep copy of the owned object tree. Managed boxes are cloned with a shallow copy.
+    /// Return a deep copy of the owned object tree. Types with shared ownership like managed boxes
+    /// are cloned with a shallow copy.
     fn clone(&self) -> Self;
 }
 
-impl Clone for () {
-    /// Return a copy of the value.
-    #[inline(always)]
-    fn clone(&self) -> () { () }
-}
-
-impl<T:Clone> Clone for ~T {
+impl<T: Clone> Clone for ~T {
     /// Return a deep copy of the owned box.
     #[inline(always)]
     fn clone(&self) -> ~T { ~(**self).clone() }
@@ -54,7 +49,7 @@ impl<T> Clone for @mut T {
 macro_rules! clone_impl(
     ($t:ty) => {
         impl Clone for $t {
-            /// Return a copy of the value.
+            /// Return a deep copy of the value.
             #[inline(always)]
             fn clone(&self) -> $t { *self }
         }
@@ -77,9 +72,53 @@ clone_impl!(float)
 clone_impl!(f32)
 clone_impl!(f64)
 
+clone_impl!(())
 clone_impl!(bool)
 clone_impl!(char)
 
+pub trait DeepClone {
+    /// Return a deep copy of the object tree. Types with shared ownership are also copied via a
+    /// deep copy, unlike `Clone`. Note that this is currently unimplemented for managed boxes, as
+    /// it would need to handle cycles.
+    fn deep_clone(&self) -> Self;
+}
+
+macro_rules! deep_clone_impl(
+    ($t:ty) => {
+        impl DeepClone for $t {
+            /// Return a deep copy of the value.
+            #[inline(always)]
+            fn deep_clone(&self) -> $t { *self }
+        }
+    }
+)
+
+impl<T: DeepClone> DeepClone for ~T {
+    /// Return a deep copy of the owned box.
+    #[inline(always)]
+    fn deep_clone(&self) -> ~T { ~(**self).deep_clone() }
+}
+
+deep_clone_impl!(int)
+deep_clone_impl!(i8)
+deep_clone_impl!(i16)
+deep_clone_impl!(i32)
+deep_clone_impl!(i64)
+
+deep_clone_impl!(uint)
+deep_clone_impl!(u8)
+deep_clone_impl!(u16)
+deep_clone_impl!(u32)
+deep_clone_impl!(u64)
+
+deep_clone_impl!(float)
+deep_clone_impl!(f32)
+deep_clone_impl!(f64)
+
+deep_clone_impl!(())
+deep_clone_impl!(bool)
+deep_clone_impl!(char)
+
 #[test]
 fn test_owned_clone() {
     let a: ~int = ~5i;
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index 9aaa2921fe7..5aee3077e48 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -49,6 +49,7 @@ use num::Zero;
 use old_iter::{BaseIter, MutableIter, ExtendedIter};
 use old_iter;
 use str::StrSlice;
+use clone::DeepClone;
 
 #[cfg(test)] use str;
 
@@ -59,6 +60,15 @@ pub enum Option<T> {
     Some(T),
 }
 
+impl<T: DeepClone> DeepClone for Option<T> {
+    fn deep_clone(&self) -> Option<T> {
+        match *self {
+            Some(ref x) => Some(x.deep_clone()),
+            None => None
+        }
+    }
+}
+
 impl<T:Ord> Ord for Option<T> {
     fn lt(&self, other: &Option<T>) -> bool {
         match (self, other) {
diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs
index 22172db9302..4ed648161fc 100644
--- a/src/libcore/prelude.rs
+++ b/src/libcore/prelude.rs
@@ -27,7 +27,7 @@ pub use io::{print, println};
 
 /* Reexported types and traits */
 
-pub use clone::Clone;
+pub use clone::{Clone, DeepClone};
 pub use cmp::{Eq, ApproxEq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv};
 pub use container::{Container, Mutable, Map, Set};
 pub use hash::Hash;
diff --git a/src/libstd/rc.rs b/src/libstd/rc.rs
index 8cf2da3a1e8..cb0798f2a39 100644
--- a/src/libstd/rc.rs
+++ b/src/libstd/rc.rs
@@ -76,6 +76,7 @@ impl<T: Owned> Drop for Rc<T> {
 
 
 impl<T: Owned> Clone for Rc<T> {
+    /// Return a shallow copy of the reference counted pointer.
     #[inline]
     fn clone(&self) -> Rc<T> {
         unsafe {
@@ -85,9 +86,38 @@ impl<T: Owned> Clone for Rc<T> {
     }
 }
 
+impl<T: Owned + DeepClone> DeepClone for Rc<T> {
+    /// Return a deep copy of the reference counted pointer.
+    #[inline]
+    fn deep_clone(&self) -> Rc<T> {
+        Rc::new(self.borrow().deep_clone())
+    }
+}
+
 #[cfg(test)]
 mod test_rc {
     use super::*;
+    use core::cell::Cell;
+
+    #[test]
+    fn test_clone() {
+        let x = Rc::new(Cell(5));
+        let y = x.clone();
+        do x.borrow().with_mut_ref |inner| {
+            *inner = 20;
+        }
+        assert_eq!(y.borrow().take(), 20);
+    }
+
+    #[test]
+    fn test_deep_clone() {
+        let x = Rc::new(Cell(5));
+        let y = x.deep_clone();
+        do x.borrow().with_mut_ref |inner| {
+            *inner = 20;
+        }
+        assert_eq!(y.borrow().take(), 5);
+    }
 
     #[test]
     fn test_simple() {
@@ -96,7 +126,7 @@ mod test_rc {
     }
 
     #[test]
-    fn test_clone() {
+    fn test_simple_clone() {
         let x = Rc::new(5);
         let y = x.clone();
         assert_eq!(*x.borrow(), 5);
@@ -149,24 +179,26 @@ pub impl<T: Owned> RcMut<T> {
 
     /// Fails if there is already a mutable borrow of the box
     #[inline]
-    fn with_borrow(&self, f: &fn(&T)) {
+    fn with_borrow<U>(&self, f: &fn(&T) -> U) -> U {
         unsafe {
             assert!((*self.ptr).borrow != Mutable);
             let previous = (*self.ptr).borrow;
             (*self.ptr).borrow = Immutable;
-            f(&(*self.ptr).value);
+            let res = f(&(*self.ptr).value);
             (*self.ptr).borrow = previous;
+            res
         }
     }
 
     /// Fails if there is already a mutable or immutable borrow of the box
     #[inline]
-    fn with_mut_borrow(&self, f: &fn(&mut T)) {
+    fn with_mut_borrow<U>(&self, f: &fn(&mut T) -> U) -> U {
         unsafe {
             assert!((*self.ptr).borrow == Nothing);
             (*self.ptr).borrow = Mutable;
-            f(&mut (*self.ptr).value);
+            let res = f(&mut (*self.ptr).value);
             (*self.ptr).borrow = Nothing;
+            res
         }
     }
 }
@@ -200,6 +232,7 @@ impl<T: Owned> Drop for RcMut<T> {
 }
 
 impl<T: Owned> Clone for RcMut<T> {
+    /// Return a shallow copy of the reference counted pointer.
     #[inline]
     fn clone(&self) -> RcMut<T> {
         unsafe {
@@ -209,11 +242,46 @@ impl<T: Owned> Clone for RcMut<T> {
     }
 }
 
+impl<T: Owned + DeepClone> DeepClone for RcMut<T> {
+    /// Return a deep copy of the reference counted pointer.
+    #[inline]
+    fn deep_clone(&self) -> RcMut<T> {
+        do self.with_borrow |x| {
+            // FIXME: #6497: should avoid freeze (slow)
+            RcMut::new(x.deep_clone())
+        }
+    }
+}
+
 #[cfg(test)]
 mod test_rc_mut {
     use super::*;
 
     #[test]
+    fn test_clone() {
+        let x = RcMut::new(5);
+        let y = x.clone();
+        do x.with_mut_borrow |value| {
+            *value = 20;
+        }
+        do y.with_borrow |value| {
+            assert_eq!(*value, 20);
+        }
+    }
+
+    #[test]
+    fn test_deep_clone() {
+        let x = RcMut::new(5);
+        let y = x.deep_clone();
+        do x.with_mut_borrow |value| {
+            *value = 20;
+        }
+        do y.with_borrow |value| {
+            assert_eq!(*value, 5);
+        }
+    }
+
+    #[test]
     fn borrow_many() {
         let x = RcMut::new(5);
         let y = x.clone();