From ba80c662f448c69cbd184d18630b8824f0169b2e Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Sat, 28 Jan 2023 14:19:01 +0100 Subject: [PATCH 1/2] slice: Add a specialization for clone_into when T is Copy The implementation for the ToOwned::clone_into method on [T] is a copy of the code for vec::clone_from. In 361398009be6 the code for vec::clone_from gained a specialization for when T is Copy. This commit copies that specialization over to the clone_into implementation. --- library/alloc/src/slice.rs | 43 +++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index fecacc2bb63..093dcbbe8bf 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -782,6 +782,38 @@ fn borrow_mut(&mut self) -> &mut [T] { } } +// Specializable trait for implementing ToOwned::clone_into. This is +// public in the crate and has the Allocator parameter so that +// vec::clone_from use it too. +#[cfg(not(no_global_oom_handling))] +pub(crate) trait SpecCloneIntoVec { + fn clone_into(&self, target: &mut Vec); +} + +#[cfg(not(no_global_oom_handling))] +impl SpecCloneIntoVec for [T] { + default fn clone_into(&self, target: &mut Vec) { + // drop anything in target that will not be overwritten + target.truncate(self.len()); + + // target.len <= self.len due to the truncate above, so the + // slices here are always in-bounds. + let (init, tail) = self.split_at(target.len()); + + // reuse the contained values' allocations/resources. + target.clone_from_slice(init); + target.extend_from_slice(tail); + } +} + +#[cfg(not(no_global_oom_handling))] +impl SpecCloneIntoVec for [T] { + fn clone_into(&self, target: &mut Vec) { + target.clear(); + target.extend_from_slice(self); + } +} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl ToOwned for [T] { @@ -797,16 +829,7 @@ fn to_owned(&self) -> Vec { } fn clone_into(&self, target: &mut Vec) { - // drop anything in target that will not be overwritten - target.truncate(self.len()); - - // target.len <= self.len due to the truncate above, so the - // slices here are always in-bounds. - let (init, tail) = self.split_at(target.len()); - - // reuse the contained values' allocations/resources. - target.clone_from_slice(init); - target.extend_from_slice(tail); + SpecCloneIntoVec::clone_into(self, target); } } From a34f11c006936f0935c0f3484f9a292901d0eade Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Sat, 28 Jan 2023 14:52:31 +0100 Subject: [PATCH 2/2] vec: Use SpecCloneIntoVec::clone_into to implement Vec::clone_from In the past, Vec::clone_from was implemented using slice::clone_into. The code from clone_into was later duplicated into clone_from in 8725e4c337, which is the commit that adds custom allocator support to Vec. Presumably this was done because the slice::clone_into only works for vecs with the default allocator so it would have the wrong type to clone into Vec. Now that the clone_into implementation is moved out into a specializable trait anyway we might as well use that to share the code between the two methods. --- library/alloc/src/vec/mod.rs | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 36b0b3c9e7c..a07f3da78d3 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2646,35 +2646,6 @@ fn deref_mut(&mut self) -> &mut [T] { } } -#[cfg(not(no_global_oom_handling))] -trait SpecCloneFrom { - fn clone_from(this: &mut Self, other: &Self); -} - -#[cfg(not(no_global_oom_handling))] -impl SpecCloneFrom for Vec { - default fn clone_from(this: &mut Self, other: &Self) { - // drop anything that will not be overwritten - this.truncate(other.len()); - - // self.len <= other.len due to the truncate above, so the - // slices here are always in-bounds. - let (init, tail) = other.split_at(this.len()); - - // reuse the contained values' allocations/resources. - this.clone_from_slice(init); - this.extend_from_slice(tail); - } -} - -#[cfg(not(no_global_oom_handling))] -impl SpecCloneFrom for Vec { - fn clone_from(this: &mut Self, other: &Self) { - this.clear(); - this.extend_from_slice(other); - } -} - #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Vec { @@ -2695,7 +2666,7 @@ fn clone(&self) -> Self { } fn clone_from(&mut self, other: &Self) { - SpecCloneFrom::clone_from(self, other) + crate::slice::SpecCloneIntoVec::clone_into(other.as_slice(), self); } }