Skip to content

Commit 7ec27ae

Browse files
committed
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.
1 parent 44855a4 commit 7ec27ae

File tree

7 files changed

+76
-10
lines changed

7 files changed

+76
-10
lines changed

src/doc/unstable-book/src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@
193193
- [thread_local](thread-local.md)
194194
- [thread_local_internals](thread-local-internals.md)
195195
- [thread_local_state](thread-local-state.md)
196+
- [toowned_clone_into](toowned-clone-into.md)
196197
- [trace_macros](trace-macros.md)
197198
- [trusted_len](trusted-len.md)
198199
- [try_from](try-from.md)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# `toowned_clone_into`
2+
3+
The tracking issue for this feature is: [#41263]
4+
5+
[#41263]: https://github.com/rust-lang/rust/issues/41263
6+
7+
------------------------

src/libcollections/borrow.rs

+38
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,29 @@ pub trait ToOwned {
6060
/// ```
6161
#[stable(feature = "rust1", since = "1.0.0")]
6262
fn to_owned(&self) -> Self::Owned;
63+
64+
/// Uses borrowed data to replace owned data, usually by cloning.
65+
///
66+
/// This is borrow-generalized version of `Clone::clone_from`.
67+
///
68+
/// # Examples
69+
///
70+
/// Basic usage:
71+
///
72+
/// ```
73+
/// # #![feature(toowned_clone_into)]
74+
/// let mut s: String = String::new();
75+
/// "hello".clone_into(&mut s);
76+
///
77+
/// let mut v: Vec<i32> = Vec::new();
78+
/// [1, 2][..].clone_into(&mut v);
79+
/// ```
80+
#[unstable(feature = "toowned_clone_into",
81+
reason = "recently added",
82+
issue = "41263")]
83+
fn clone_into(&self, target: &mut Self::Owned) {
84+
*target = self.to_owned();
85+
}
6386
}
6487

6588
#[stable(feature = "rust1", since = "1.0.0")]
@@ -70,6 +93,10 @@ impl<T> ToOwned for T
7093
fn to_owned(&self) -> T {
7194
self.clone()
7295
}
96+
97+
fn clone_into(&self, target: &mut T) {
98+
target.clone_from(self);
99+
}
73100
}
74101

75102
/// A clone-on-write smart pointer.
@@ -141,6 +168,17 @@ impl<'a, B: ?Sized> Clone for Cow<'a, B>
141168
}
142169
}
143170
}
171+
172+
fn clone_from(&mut self, source: &Cow<'a, B>) {
173+
if let Owned(ref mut dest) = *self {
174+
if let Owned(ref o) = *source {
175+
o.borrow().clone_into(dest);
176+
return;
177+
}
178+
}
179+
180+
*self = source.clone();
181+
}
144182
}
145183

146184
impl<'a, B: ?Sized> Cow<'a, B>

src/libcollections/slice.rs

+13
Original file line numberDiff line numberDiff line change
@@ -1527,6 +1527,19 @@ impl<T: Clone> ToOwned for [T] {
15271527
fn to_owned(&self) -> Vec<T> {
15281528
panic!("not available with cfg(test)")
15291529
}
1530+
1531+
fn clone_into(&self, target: &mut Vec<T>) {
1532+
// drop anything in target that will not be overwritten
1533+
target.truncate(self.len());
1534+
let len = target.len();
1535+
1536+
// reuse the contained values' allocations/resources.
1537+
target.clone_from_slice(&self[..len]);
1538+
1539+
// target.len <= self.len due to the truncate above, so the
1540+
// slice here is always in-bounds.
1541+
target.extend_from_slice(&self[len..]);
1542+
}
15301543
}
15311544

15321545
////////////////////////////////////////////////////////////////////////////////

src/libcollections/str.rs

+6
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,12 @@ impl ToOwned for str {
199199
fn to_owned(&self) -> String {
200200
unsafe { String::from_utf8_unchecked(self.as_bytes().to_owned()) }
201201
}
202+
203+
fn clone_into(&self, target: &mut String) {
204+
let mut b = mem::replace(target, String::new()).into_bytes();
205+
self.as_bytes().clone_into(&mut b);
206+
*target = unsafe { String::from_utf8_unchecked(b) }
207+
}
202208
}
203209

204210
/// Methods for string slices.

src/libcollections/tests/cow_str.rs

+10
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,13 @@ fn check_cow_add_assign_str() {
139139
assert_eq!("Hi, World!", owned);
140140
assert_eq!("Hello, World!", borrowed);
141141
}
142+
143+
#[test]
144+
fn check_cow_clone_from() {
145+
let mut c1: Cow<str> = Cow::Owned(String::with_capacity(25));
146+
let s: String = "hi".to_string();
147+
assert!(s.capacity() < 25);
148+
let c2: Cow<str> = Cow::Owned(s);
149+
c1.clone_from(&c2);
150+
assert!(c1.into_owned().capacity() >= 25);
151+
}

src/libcollections/vec.rs

+1-10
Original file line numberDiff line numberDiff line change
@@ -1396,16 +1396,7 @@ impl<T: Clone> Clone for Vec<T> {
13961396
}
13971397

13981398
fn clone_from(&mut self, other: &Vec<T>) {
1399-
// drop anything in self that will not be overwritten
1400-
self.truncate(other.len());
1401-
let len = self.len();
1402-
1403-
// reuse the contained values' allocations/resources.
1404-
self.clone_from_slice(&other[..len]);
1405-
1406-
// self.len <= other.len due to the truncate above, so the
1407-
// slice here is always in-bounds.
1408-
self.extend_from_slice(&other[len..]);
1399+
other.as_slice().clone_into(self);
14091400
}
14101401
}
14111402

0 commit comments

Comments
 (0)