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.
This commit is contained in:
commit
8a15333c06
5 changed files with 139 additions and 15 deletions
|
@ -21,10 +21,17 @@ Similar to a mutable option type, but friendlier.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#[mutable]
|
#[mutable]
|
||||||
|
#[deriving(Clone)]
|
||||||
pub struct Cell<T> {
|
pub struct Cell<T> {
|
||||||
priv value: Option<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> {
|
impl<T:cmp::Eq> cmp::Eq for Cell<T> {
|
||||||
fn eq(&self, other: &Cell<T>) -> bool {
|
fn eq(&self, other: &Cell<T>) -> bool {
|
||||||
(self.value) == (other.value)
|
(self.value) == (other.value)
|
||||||
|
|
|
@ -23,17 +23,12 @@ by convention implementing the `Clone` trait and calling the
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub trait Clone {
|
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;
|
fn clone(&self) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for () {
|
impl<T: Clone> Clone for ~T {
|
||||||
/// 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.
|
/// Return a deep copy of the owned box.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn clone(&self) -> ~T { ~(**self).clone() }
|
fn clone(&self) -> ~T { ~(**self).clone() }
|
||||||
|
@ -54,7 +49,7 @@ impl<T> Clone for @mut T {
|
||||||
macro_rules! clone_impl(
|
macro_rules! clone_impl(
|
||||||
($t:ty) => {
|
($t:ty) => {
|
||||||
impl Clone for $t {
|
impl Clone for $t {
|
||||||
/// Return a copy of the value.
|
/// Return a deep copy of the value.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn clone(&self) -> $t { *self }
|
fn clone(&self) -> $t { *self }
|
||||||
}
|
}
|
||||||
|
@ -77,9 +72,53 @@ clone_impl!(float)
|
||||||
clone_impl!(f32)
|
clone_impl!(f32)
|
||||||
clone_impl!(f64)
|
clone_impl!(f64)
|
||||||
|
|
||||||
|
clone_impl!(())
|
||||||
clone_impl!(bool)
|
clone_impl!(bool)
|
||||||
clone_impl!(char)
|
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]
|
#[test]
|
||||||
fn test_owned_clone() {
|
fn test_owned_clone() {
|
||||||
let a: ~int = ~5i;
|
let a: ~int = ~5i;
|
||||||
|
|
|
@ -49,6 +49,7 @@ use num::Zero;
|
||||||
use old_iter::{BaseIter, MutableIter, ExtendedIter};
|
use old_iter::{BaseIter, MutableIter, ExtendedIter};
|
||||||
use old_iter;
|
use old_iter;
|
||||||
use str::StrSlice;
|
use str::StrSlice;
|
||||||
|
use clone::DeepClone;
|
||||||
|
|
||||||
#[cfg(test)] use str;
|
#[cfg(test)] use str;
|
||||||
|
|
||||||
|
@ -59,6 +60,15 @@ pub enum Option<T> {
|
||||||
Some(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> {
|
impl<T:Ord> Ord for Option<T> {
|
||||||
fn lt(&self, other: &Option<T>) -> bool {
|
fn lt(&self, other: &Option<T>) -> bool {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
|
|
|
@ -27,7 +27,7 @@ pub use io::{print, println};
|
||||||
|
|
||||||
/* Reexported types and traits */
|
/* 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 cmp::{Eq, ApproxEq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv};
|
||||||
pub use container::{Container, Mutable, Map, Set};
|
pub use container::{Container, Mutable, Map, Set};
|
||||||
pub use hash::Hash;
|
pub use hash::Hash;
|
||||||
|
|
|
@ -76,6 +76,7 @@ impl<T: Owned> Drop for Rc<T> {
|
||||||
|
|
||||||
|
|
||||||
impl<T: Owned> Clone for Rc<T> {
|
impl<T: Owned> Clone for Rc<T> {
|
||||||
|
/// Return a shallow copy of the reference counted pointer.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> Rc<T> {
|
fn clone(&self) -> Rc<T> {
|
||||||
unsafe {
|
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)]
|
#[cfg(test)]
|
||||||
mod test_rc {
|
mod test_rc {
|
||||||
use super::*;
|
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]
|
#[test]
|
||||||
fn test_simple() {
|
fn test_simple() {
|
||||||
|
@ -96,7 +126,7 @@ mod test_rc {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_clone() {
|
fn test_simple_clone() {
|
||||||
let x = Rc::new(5);
|
let x = Rc::new(5);
|
||||||
let y = x.clone();
|
let y = x.clone();
|
||||||
assert_eq!(*x.borrow(), 5);
|
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
|
/// Fails if there is already a mutable borrow of the box
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_borrow(&self, f: &fn(&T)) {
|
fn with_borrow<U>(&self, f: &fn(&T) -> U) -> U {
|
||||||
unsafe {
|
unsafe {
|
||||||
assert!((*self.ptr).borrow != Mutable);
|
assert!((*self.ptr).borrow != Mutable);
|
||||||
let previous = (*self.ptr).borrow;
|
let previous = (*self.ptr).borrow;
|
||||||
(*self.ptr).borrow = Immutable;
|
(*self.ptr).borrow = Immutable;
|
||||||
f(&(*self.ptr).value);
|
let res = f(&(*self.ptr).value);
|
||||||
(*self.ptr).borrow = previous;
|
(*self.ptr).borrow = previous;
|
||||||
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fails if there is already a mutable or immutable borrow of the box
|
/// Fails if there is already a mutable or immutable borrow of the box
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_mut_borrow(&self, f: &fn(&mut T)) {
|
fn with_mut_borrow<U>(&self, f: &fn(&mut T) -> U) -> U {
|
||||||
unsafe {
|
unsafe {
|
||||||
assert!((*self.ptr).borrow == Nothing);
|
assert!((*self.ptr).borrow == Nothing);
|
||||||
(*self.ptr).borrow = Mutable;
|
(*self.ptr).borrow = Mutable;
|
||||||
f(&mut (*self.ptr).value);
|
let res = f(&mut (*self.ptr).value);
|
||||||
(*self.ptr).borrow = Nothing;
|
(*self.ptr).borrow = Nothing;
|
||||||
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,6 +232,7 @@ impl<T: Owned> Drop for RcMut<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Owned> Clone for RcMut<T> {
|
impl<T: Owned> Clone for RcMut<T> {
|
||||||
|
/// Return a shallow copy of the reference counted pointer.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> RcMut<T> {
|
fn clone(&self) -> RcMut<T> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -209,10 +242,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)]
|
#[cfg(test)]
|
||||||
mod test_rc_mut {
|
mod test_rc_mut {
|
||||||
use super::*;
|
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]
|
#[test]
|
||||||
fn borrow_many() {
|
fn borrow_many() {
|
||||||
let x = RcMut::new(5);
|
let x = RcMut::new(5);
|
||||||
|
|
Loading…
Reference in a new issue