diff options
| author | Scott McMurray <scottmcm@users.noreply.github.com> | 2017-04-01 19:33:45 -0700 |
|---|---|---|
| committer | Scott McMurray <scottmcm@users.noreply.github.com> | 2017-04-12 17:21:15 -0700 |
| commit | 7ec27ae63d762234ad768fb605bd40bbbc52c7a0 (patch) | |
| tree | 932053cae56ba36ac896ffdfdf6a38e01b83f5b9 | |
| parent | 44855a4cef3e83c76c386fdcf034447a8ee128e4 (diff) | |
| download | rust-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.md | 1 | ||||
| -rw-r--r-- | src/doc/unstable-book/src/toowned-clone-into.md | 7 | ||||
| -rw-r--r-- | src/libcollections/borrow.rs | 38 | ||||
| -rw-r--r-- | src/libcollections/slice.rs | 13 | ||||
| -rw-r--r-- | src/libcollections/str.rs | 6 | ||||
| -rw-r--r-- | src/libcollections/tests/cow_str.rs | 10 | ||||
| -rw-r--r-- | src/libcollections/vec.rs | 11 |
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); } } |
