about summary refs log tree commit diff
diff options
context:
space:
mode:
authorScott McMurray <scottmcm@users.noreply.github.com>2017-04-01 19:33:45 -0700
committerScott McMurray <scottmcm@users.noreply.github.com>2017-04-12 17:21:15 -0700
commit7ec27ae63d762234ad768fb605bd40bbbc52c7a0 (patch)
tree932053cae56ba36ac896ffdfdf6a38e01b83f5b9
parent44855a4cef3e83c76c386fdcf034447a8ee128e4 (diff)
downloadrust-7ec27ae63d762234ad768fb605bd40bbbc52c7a0.tar.gz
rust-7ec27ae63d762234ad768fb605bd40bbbc52c7a0.zip
Add ToOwned::clone_into (unstable as toowned_clone_into)
to_owned generalizes clone; this generalizes clone_from.  Use to_owned to
give it a default impl.  Customize the impl for [T], str, and T:Clone.

Use it in Cow::clone_from to reuse resources when cloning Owned into Owned.
-rw-r--r--src/doc/unstable-book/src/SUMMARY.md1
-rw-r--r--src/doc/unstable-book/src/toowned-clone-into.md7
-rw-r--r--src/libcollections/borrow.rs38
-rw-r--r--src/libcollections/slice.rs13
-rw-r--r--src/libcollections/str.rs6
-rw-r--r--src/libcollections/tests/cow_str.rs10
-rw-r--r--src/libcollections/vec.rs11
7 files changed, 76 insertions, 10 deletions
diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md
index 9ce097e78a4..2e9810c438d 100644
--- a/src/doc/unstable-book/src/SUMMARY.md
+++ b/src/doc/unstable-book/src/SUMMARY.md
@@ -193,6 +193,7 @@
 - [thread_local](thread-local.md)
 - [thread_local_internals](thread-local-internals.md)
 - [thread_local_state](thread-local-state.md)
+- [toowned_clone_into](toowned-clone-into.md)
 - [trace_macros](trace-macros.md)
 - [trusted_len](trusted-len.md)
 - [try_from](try-from.md)
diff --git a/src/doc/unstable-book/src/toowned-clone-into.md b/src/doc/unstable-book/src/toowned-clone-into.md
new file mode 100644
index 00000000000..eccc7e0e4dd
--- /dev/null
+++ b/src/doc/unstable-book/src/toowned-clone-into.md
@@ -0,0 +1,7 @@
+# `toowned_clone_into`
+
+The tracking issue for this feature is: [#41263]
+
+[#41263]: https://github.com/rust-lang/rust/issues/41263
+
+------------------------
diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs
index 65056121f05..0de52b6696f 100644
--- a/src/libcollections/borrow.rs
+++ b/src/libcollections/borrow.rs
@@ -60,6 +60,29 @@ pub trait ToOwned {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     fn to_owned(&self) -> Self::Owned;
+
+    /// Uses borrowed data to replace owned data, usually by cloning.
+    ///
+    /// This is borrow-generalized version of `Clone::clone_from`.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # #![feature(toowned_clone_into)]
+    /// let mut s: String = String::new();
+    /// "hello".clone_into(&mut s);
+    ///
+    /// let mut v: Vec<i32> = Vec::new();
+    /// [1, 2][..].clone_into(&mut v);
+    /// ```
+    #[unstable(feature = "toowned_clone_into",
+               reason = "recently added",
+               issue = "41263")]
+    fn clone_into(&self, target: &mut Self::Owned) {
+        *target = self.to_owned();
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -70,6 +93,10 @@ impl<T> ToOwned for T
     fn to_owned(&self) -> T {
         self.clone()
     }
+
+    fn clone_into(&self, target: &mut T) {
+        target.clone_from(self);
+    }
 }
 
 /// A clone-on-write smart pointer.
@@ -141,6 +168,17 @@ impl<'a, B: ?Sized> Clone for Cow<'a, B>
             }
         }
     }
+
+    fn clone_from(&mut self, source: &Cow<'a, B>) {
+        if let Owned(ref mut dest) = *self {
+            if let Owned(ref o) = *source {
+                o.borrow().clone_into(dest);
+                return;
+            }
+        }
+
+        *self = source.clone();
+    }
 }
 
 impl<'a, B: ?Sized> Cow<'a, B>
diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs
index 6cff315a6cc..f7e0f0395e7 100644
--- a/src/libcollections/slice.rs
+++ b/src/libcollections/slice.rs
@@ -1527,6 +1527,19 @@ impl<T: Clone> ToOwned for [T] {
     fn to_owned(&self) -> Vec<T> {
         panic!("not available with cfg(test)")
     }
+
+    fn clone_into(&self, target: &mut Vec<T>) {
+        // drop anything in target that will not be overwritten
+        target.truncate(self.len());
+        let len = target.len();
+
+        // reuse the contained values' allocations/resources.
+        target.clone_from_slice(&self[..len]);
+
+        // target.len <= self.len due to the truncate above, so the
+        // slice here is always in-bounds.
+        target.extend_from_slice(&self[len..]);
+    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs
index c37a4fa6b55..8d4b3a247e2 100644
--- a/src/libcollections/str.rs
+++ b/src/libcollections/str.rs
@@ -199,6 +199,12 @@ impl ToOwned for str {
     fn to_owned(&self) -> String {
         unsafe { String::from_utf8_unchecked(self.as_bytes().to_owned()) }
     }
+
+    fn clone_into(&self, target: &mut String) {
+        let mut b = mem::replace(target, String::new()).into_bytes();
+        self.as_bytes().clone_into(&mut b);
+        *target = unsafe { String::from_utf8_unchecked(b) }
+    }
 }
 
 /// Methods for string slices.
diff --git a/src/libcollections/tests/cow_str.rs b/src/libcollections/tests/cow_str.rs
index b29245121da..aa87ee84b3e 100644
--- a/src/libcollections/tests/cow_str.rs
+++ b/src/libcollections/tests/cow_str.rs
@@ -139,3 +139,13 @@ fn check_cow_add_assign_str() {
     assert_eq!("Hi, World!", owned);
     assert_eq!("Hello, World!", borrowed);
 }
+
+#[test]
+fn check_cow_clone_from() {
+    let mut c1: Cow<str> = Cow::Owned(String::with_capacity(25));
+    let s: String = "hi".to_string();
+    assert!(s.capacity() < 25);
+    let c2: Cow<str> = Cow::Owned(s);
+    c1.clone_from(&c2);
+    assert!(c1.into_owned().capacity() >= 25);
+}
\ No newline at end of file
diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs
index c258ac2bdea..3d11b4f80fb 100644
--- a/src/libcollections/vec.rs
+++ b/src/libcollections/vec.rs
@@ -1396,16 +1396,7 @@ impl<T: Clone> Clone for Vec<T> {
     }
 
     fn clone_from(&mut self, other: &Vec<T>) {
-        // drop anything in self that will not be overwritten
-        self.truncate(other.len());
-        let len = self.len();
-
-        // reuse the contained values' allocations/resources.
-        self.clone_from_slice(&other[..len]);
-
-        // self.len <= other.len due to the truncate above, so the
-        // slice here is always in-bounds.
-        self.extend_from_slice(&other[len..]);
+        other.as_slice().clone_into(self);
     }
 }