add a DeepClone trait

for deep copies through shared ownership boundaries
This commit is contained in:
Daniel Micay 2013-05-15 00:45:40 -04:00
parent fa45958ec8
commit 75822f2894
3 changed files with 126 additions and 12 deletions

View file

@ -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<T: Clone> Clone for ~T {
/// Return a deep copy of the owned box.
#[inline(always)]
@ -55,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 }
}
@ -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<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;

View file

@ -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;

View file

@ -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,46 @@ 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.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<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 +240,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,10 +250,45 @@ 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);