about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJonathan Reem <jonathan.reem@gmail.com>2015-07-26 22:12:00 -0700
committerJonathan Reem <jonathan.reem@gmail.com>2015-07-28 01:43:17 -0700
commite24423091f0690a83e63ee234bee5627a86b51f0 (patch)
tree3868b0ef0e26c53144c05e699acd757c2fe46ede
parent184267cac6488c2f164dba469df5ef85533e148f (diff)
downloadrust-e24423091f0690a83e63ee234bee5627a86b51f0.tar.gz
rust-e24423091f0690a83e63ee234bee5627a86b51f0.zip
Implement Clone for Box<[T]> where T: Clone
Closes #25097
-rw-r--r--src/liballoc/boxed.rs55
-rw-r--r--src/liballoc/lib.rs1
-rw-r--r--src/libcollectionstest/slice.rs53
-rw-r--r--src/libstd/ffi/c_str.rs10
4 files changed, 109 insertions, 10 deletions
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index acf22094233..2b0aec5b727 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -56,6 +56,7 @@
 use core::prelude::*;
 
 use heap;
+use raw_vec::RawVec;
 
 use core::any::Any;
 use core::cmp::Ordering;
@@ -65,7 +66,7 @@ use core::marker::{self, Unsize};
 use core::mem;
 use core::ops::{CoerceUnsized, Deref, DerefMut};
 use core::ops::{Placer, Boxed, Place, InPlace, BoxPlace};
-use core::ptr::Unique;
+use core::ptr::{self, Unique};
 use core::raw::{TraitObject};
 
 /// A value that represents the heap. This is the default place that the `box`
@@ -511,3 +512,55 @@ impl<'a,A,R> FnOnce<A> for Box<FnBox<A,Output=R>+Send+'a> {
 }
 
 impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {}
+
+#[stable(feature = "box_slice_clone", since = "1.3.0")]
+impl<T: Clone> Clone for Box<[T]> {
+    fn clone(&self) -> Self {
+        let mut new = BoxBuilder {
+            data: RawVec::with_capacity(self.len()),
+            len: 0
+        };
+
+        let mut target = new.data.ptr();
+
+        for item in self.iter() {
+            unsafe {
+                ptr::write(target, item.clone());
+                target = target.offset(1);
+            };
+
+            new.len += 1;
+        }
+
+        return unsafe { new.into_box() };
+
+        // Helper type for responding to panics correctly.
+        struct BoxBuilder<T> {
+            data: RawVec<T>,
+            len: usize,
+        }
+
+        impl<T> BoxBuilder<T> {
+            unsafe fn into_box(self) -> Box<[T]> {
+                let raw = ptr::read(&self.data);
+                mem::forget(self);
+                raw.into_box()
+            }
+        }
+
+        impl<T> Drop for BoxBuilder<T> {
+            fn drop(&mut self) {
+                let mut data = self.data.ptr();
+                let max = unsafe { data.offset(self.len as isize) };
+
+                while data != max {
+                    unsafe {
+                        ptr::read(data);
+                        data = data.offset(1);
+                    }
+                }
+            }
+        }
+    }
+}
+
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index f66495c4057..d49d209955e 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -78,6 +78,7 @@
 #![feature(core)]
 #![feature(core_intrinsics)]
 #![feature(core_prelude)]
+#![feature(core_slice_ext)]
 #![feature(custom_attribute)]
 #![feature(fundamental)]
 #![feature(lang_items)]
diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs
index c0ab11380d9..65706b292c6 100644
--- a/src/libcollectionstest/slice.rs
+++ b/src/libcollectionstest/slice.rs
@@ -1270,6 +1270,59 @@ fn test_to_vec() {
     assert_eq!(ys, [1, 2, 3]);
 }
 
+#[test]
+fn test_box_slice_clone() {
+    let data = vec![vec![0, 1], vec![0], vec![1]];
+    let data2 = data.clone().into_boxed_slice().clone().to_vec();
+
+    assert_eq!(data, data2);
+}
+
+#[test]
+fn test_box_slice_clone_panics() {
+    use std::sync::Arc;
+    use std::sync::atomic::{AtomicUsize, Ordering};
+    use std::thread::spawn;
+
+    struct Canary {
+        count: Arc<AtomicUsize>,
+        panics: bool
+    }
+
+    impl Drop for Canary {
+        fn drop(&mut self) {
+            self.count.fetch_add(1, Ordering::SeqCst);
+        }
+    }
+
+    impl Clone for Canary {
+        fn clone(&self) -> Self {
+            if self.panics { panic!() }
+
+            Canary {
+                count: self.count.clone(),
+                panics: self.panics
+            }
+        }
+    }
+
+    let drop_count = Arc::new(AtomicUsize::new(0));
+    let canary = Canary { count: drop_count.clone(), panics: false };
+    let panic = Canary { count: drop_count.clone(), panics: true };
+
+    spawn(move || {
+        // When xs is dropped, +5.
+        let xs = vec![canary.clone(), canary.clone(), canary.clone(),
+                      panic, canary].into_boxed_slice();
+
+        // When panic is cloned, +3.
+        xs.clone();
+    }).join().unwrap_err();
+
+    // Total = 8
+    assert_eq!(drop_count.load(Ordering::SeqCst), 8);
+}
+
 mod bench {
     use std::iter::repeat;
     use std::{mem, ptr};
diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs
index c9fe6e7e0b1..6eb0719d9f6 100644
--- a/src/libstd/ffi/c_str.rs
+++ b/src/libstd/ffi/c_str.rs
@@ -11,7 +11,6 @@
 use ascii;
 use borrow::{Cow, ToOwned, Borrow};
 use boxed::Box;
-use clone::Clone;
 use convert::{Into, From};
 use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
 use error::Error;
@@ -62,7 +61,7 @@ use vec::Vec;
 /// }
 /// # }
 /// ```
-#[derive(PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct CString {
     inner: Box<[u8]>,
@@ -251,13 +250,6 @@ impl CString {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl Clone for CString {
-    fn clone(&self) -> Self {
-        CString { inner: self.inner.to_owned().into_boxed_slice() }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
 impl Deref for CString {
     type Target = CStr;