From 75822f2894498025d6a86bcaf30fa56118c7d3ab Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Wed, 15 May 2013 00:45:40 -0400 Subject: [PATCH] add a DeepClone trait for deep copies through shared ownership boundaries --- src/libcore/clone.rs | 52 ++++++++++++++++++++++---- src/libcore/prelude.rs | 2 +- src/libstd/rc.rs | 84 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 126 insertions(+), 12 deletions(-) diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 518ea46f10b..2ff860916c5 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -28,12 +28,6 @@ pub trait Clone { fn clone(&self) -> Self; } -impl Clone for () { - /// Return a copy of the value. - #[inline(always)] - fn clone(&self) -> () { () } -} - impl Clone for ~T { /// Return a deep copy of the owned box. #[inline(always)] @@ -55,7 +49,7 @@ impl 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 } } @@ -78,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 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/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..41fcc1d402e 100644 --- a/src/libstd/rc.rs +++ b/src/libstd/rc.rs @@ -76,6 +76,7 @@ impl Drop for Rc { impl Clone for Rc { + /// Return a shallow copy of the reference counted pointer. #[inline] fn clone(&self) -> Rc { unsafe { @@ -85,9 +86,46 @@ impl Clone for Rc { } } +impl DeepClone for Rc { + /// Return a deep copy of the reference counted pointer. + #[inline] + fn deep_clone(&self) -> Rc { + 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.with_borrow |cell| { + do value.with_mut_ref |inner| { + *inner = 20; + } + } + do y.with_borrow |value| { + assert_eq!(value.take(), 20); + } + } + + #[test] + fn test_deep_clone() { + let x = Rc::new(Cell(5)); + let y = x.deep_clone(); + do x.with_borrow |cell| { + do value.with_mut_ref |inner| { + *inner = 20; + } + } + do y.with_borrow |value| { + assert_eq!(value.take(), 5); + } + } #[test] fn test_simple() { @@ -149,24 +187,26 @@ pub impl RcMut { /// Fails if there is already a mutable borrow of the box #[inline] - fn with_borrow(&self, f: &fn(&T)) { + fn with_borrow(&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(&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 +240,7 @@ impl Drop for RcMut { } impl Clone for RcMut { + /// Return a shallow copy of the reference counted pointer. #[inline] fn clone(&self) -> RcMut { unsafe { @@ -209,10 +250,45 @@ impl Clone for RcMut { } } +impl DeepClone for RcMut { + /// Return a deep copy of the reference counted pointer. + #[inline] + fn deep_clone(&self) -> RcMut { + 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);