diff --git a/library/core/src/array/iter/iter_inner.rs b/library/core/src/array/iter/iter_inner.rs index fa4ccf507e2f..d93cbf32c016 100644 --- a/library/core/src/array/iter/iter_inner.rs +++ b/library/core/src/array/iter/iter_inner.rs @@ -1,9 +1,10 @@ //! Defines the `IntoIter` owned iterator for arrays. +use crate::clone::TrivialClone; use crate::mem::MaybeUninit; use crate::num::NonZero; use crate::ops::{IndexRange, NeverShortCircuit, Try}; -use crate::{fmt, iter}; +use crate::{fmt, iter, ptr}; #[allow(private_bounds)] trait PartialDrop { @@ -99,9 +100,26 @@ pub(super) const fn empty() -> Self { impl Clone for PolymorphicIter<[MaybeUninit; N]> { #[inline] fn clone(&self) -> Self { + SpecPolymorphicIterClone::::spec_clone(self) + } +} + +trait SpecPolymorphicIterClone { + fn spec_clone( + this: &PolymorphicIter<[MaybeUninit; N]>, + ) -> PolymorphicIter<[MaybeUninit; N]> + where + Self: Sized; +} + +impl SpecPolymorphicIterClone for T { + #[inline] + default fn spec_clone( + this: &PolymorphicIter<[MaybeUninit; N]>, + ) -> PolymorphicIter<[MaybeUninit; N]> { // Note, we don't really need to match the exact same alive range, so // we can just clone into offset 0 regardless of where `self` is. - let mut new = Self::empty(); + let mut new = PolymorphicIter::<[MaybeUninit; N]>::empty(); fn clone_into_new( source: &PolymorphicIter<[MaybeUninit]>, @@ -118,7 +136,33 @@ fn clone_into_new( } } - clone_into_new(self, &mut new); + clone_into_new(this, &mut new); + new + } +} + +impl SpecPolymorphicIterClone for T { + #[inline] + fn spec_clone( + this: &PolymorphicIter<[MaybeUninit; N]>, + ) -> PolymorphicIter<[MaybeUninit; N]> { + // Note, we don't really need to match the exact same alive range, so + // we can just clone into offset 0 regardless of where `self` is. + let mut new = PolymorphicIter::<[MaybeUninit; N]>::empty(); + + let len = this.alive.len(); + + // SAFETY: These two allocations can not overlap since `new` is allocated + // on the stack of this function. + unsafe { + ptr::copy_nonoverlapping( + this.data.as_ptr().add(this.alive.start()), + new.data.as_mut_ptr(), + len, + ); + new.alive = IndexRange::zero_to(len); + } + new } } diff --git a/library/coretests/tests/array.rs b/library/coretests/tests/array.rs index a3b0e59278f7..20c7a392f17d 100644 --- a/library/coretests/tests/array.rs +++ b/library/coretests/tests/array.rs @@ -106,6 +106,34 @@ fn iterator_clone() { assert_eq!(clone.next_back(), Some(4)); assert_eq!(it.next(), Some(2)); assert_eq!(clone.next(), Some(2)); + assert_eq!(it.next(), None); + assert_eq!(clone.next(), None); +} + +#[test] +fn iterator_clone_spec() { + #[derive(Debug, PartialEq)] + struct Foo(i32); + + impl Clone for Foo { + fn clone(&self) -> Self { + // nontrivial clone + Foo(-self.0) + } + } + + let mut it = IntoIterator::into_iter([Foo(0), Foo(2), Foo(4), Foo(6), Foo(8)]); + assert_eq!(it.next(), Some(Foo(0))); + assert_eq!(it.next_back(), Some(Foo(8))); + let mut clone = it.clone(); + assert_eq!(it.next_back(), Some(Foo(6))); + assert_eq!(clone.next_back(), Some(Foo(-6))); + assert_eq!(it.next_back(), Some(Foo(4))); + assert_eq!(clone.next_back(), Some(Foo(-4))); + assert_eq!(it.next(), Some(Foo(2))); + assert_eq!(clone.next(), Some(Foo(-2))); + assert_eq!(it.next(), None); + assert_eq!(clone.next(), None); } #[test]