core/iter/adapters/
copied.rs

1use crate::iter::adapters::zip::try_get_unchecked;
2use crate::iter::adapters::{SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
3use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen};
4use crate::mem::{MaybeUninit, SizedTypeProperties};
5use crate::num::NonZero;
6use crate::ops::Try;
7use crate::{array, ptr};
8
9/// An iterator that copies the elements of an underlying iterator.
10///
11/// This `struct` is created by the [`copied`] method on [`Iterator`]. See its
12/// documentation for more.
13///
14/// [`copied`]: Iterator::copied
15/// [`Iterator`]: trait.Iterator.html
16#[stable(feature = "iter_copied", since = "1.36.0")]
17#[must_use = "iterators are lazy and do nothing unless consumed"]
18#[derive(Clone, Debug)]
19pub struct Copied<I> {
20    it: I,
21}
22
23impl<I> Copied<I> {
24    pub(in crate::iter) fn new(it: I) -> Copied<I> {
25        Copied { it }
26    }
27}
28
29fn copy_fold<T: Copy, Acc>(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, &T) -> Acc {
30    move |acc, &elt| f(acc, elt)
31}
32
33fn copy_try_fold<T: Copy, Acc, R>(mut f: impl FnMut(Acc, T) -> R) -> impl FnMut(Acc, &T) -> R {
34    move |acc, &elt| f(acc, elt)
35}
36
37#[stable(feature = "iter_copied", since = "1.36.0")]
38impl<'a, I, T: 'a> Iterator for Copied<I>
39where
40    I: Iterator<Item = &'a T>,
41    T: Copy,
42{
43    type Item = T;
44
45    fn next(&mut self) -> Option<T> {
46        self.it.next().copied()
47    }
48
49    fn next_chunk<const N: usize>(
50        &mut self,
51    ) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>>
52    where
53        Self: Sized,
54    {
55        <I as SpecNextChunk<'_, N, T>>::spec_next_chunk(&mut self.it)
56    }
57
58    fn size_hint(&self) -> (usize, Option<usize>) {
59        self.it.size_hint()
60    }
61
62    fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
63    where
64        Self: Sized,
65        F: FnMut(B, Self::Item) -> R,
66        R: Try<Output = B>,
67    {
68        self.it.try_fold(init, copy_try_fold(f))
69    }
70
71    fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
72    where
73        F: FnMut(Acc, Self::Item) -> Acc,
74    {
75        self.it.fold(init, copy_fold(f))
76    }
77
78    fn nth(&mut self, n: usize) -> Option<T> {
79        self.it.nth(n).copied()
80    }
81
82    fn last(self) -> Option<T> {
83        self.it.last().copied()
84    }
85
86    fn count(self) -> usize {
87        self.it.count()
88    }
89
90    #[inline]
91    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
92        self.it.advance_by(n)
93    }
94
95    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
96    where
97        Self: TrustedRandomAccessNoCoerce,
98    {
99        // SAFETY: the caller must uphold the contract for
100        // `Iterator::__iterator_get_unchecked`.
101        *unsafe { try_get_unchecked(&mut self.it, idx) }
102    }
103}
104
105#[stable(feature = "iter_copied", since = "1.36.0")]
106impl<'a, I, T: 'a> DoubleEndedIterator for Copied<I>
107where
108    I: DoubleEndedIterator<Item = &'a T>,
109    T: Copy,
110{
111    fn next_back(&mut self) -> Option<T> {
112        self.it.next_back().copied()
113    }
114
115    fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
116    where
117        Self: Sized,
118        F: FnMut(B, Self::Item) -> R,
119        R: Try<Output = B>,
120    {
121        self.it.try_rfold(init, copy_try_fold(f))
122    }
123
124    fn rfold<Acc, F>(self, init: Acc, f: F) -> Acc
125    where
126        F: FnMut(Acc, Self::Item) -> Acc,
127    {
128        self.it.rfold(init, copy_fold(f))
129    }
130
131    #[inline]
132    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
133        self.it.advance_back_by(n)
134    }
135}
136
137#[stable(feature = "iter_copied", since = "1.36.0")]
138impl<'a, I, T: 'a> ExactSizeIterator for Copied<I>
139where
140    I: ExactSizeIterator<Item = &'a T>,
141    T: Copy,
142{
143    fn len(&self) -> usize {
144        self.it.len()
145    }
146
147    fn is_empty(&self) -> bool {
148        self.it.is_empty()
149    }
150}
151
152#[stable(feature = "iter_copied", since = "1.36.0")]
153impl<'a, I, T: 'a> FusedIterator for Copied<I>
154where
155    I: FusedIterator<Item = &'a T>,
156    T: Copy,
157{
158}
159
160#[doc(hidden)]
161#[unstable(feature = "trusted_random_access", issue = "none")]
162unsafe impl<I> TrustedRandomAccess for Copied<I> where I: TrustedRandomAccess {}
163
164#[doc(hidden)]
165#[unstable(feature = "trusted_random_access", issue = "none")]
166unsafe impl<I> TrustedRandomAccessNoCoerce for Copied<I>
167where
168    I: TrustedRandomAccessNoCoerce,
169{
170    const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT;
171}
172
173#[stable(feature = "iter_copied", since = "1.36.0")]
174unsafe impl<'a, I, T: 'a> TrustedLen for Copied<I>
175where
176    I: TrustedLen<Item = &'a T>,
177    T: Copy,
178{
179}
180
181trait SpecNextChunk<'a, const N: usize, T: 'a>: Iterator<Item = &'a T>
182where
183    T: Copy,
184{
185    fn spec_next_chunk(&mut self) -> Result<[T; N], array::IntoIter<T, N>>;
186}
187
188impl<'a, const N: usize, I, T: 'a> SpecNextChunk<'a, N, T> for I
189where
190    I: Iterator<Item = &'a T>,
191    T: Copy,
192{
193    default fn spec_next_chunk(&mut self) -> Result<[T; N], array::IntoIter<T, N>> {
194        array::iter_next_chunk(&mut self.copied())
195    }
196}
197
198impl<'a, const N: usize, T: 'a> SpecNextChunk<'a, N, T> for crate::slice::Iter<'a, T>
199where
200    T: Copy,
201{
202    fn spec_next_chunk(&mut self) -> Result<[T; N], array::IntoIter<T, N>> {
203        let mut raw_array = [const { MaybeUninit::uninit() }; N];
204
205        let len = self.len();
206
207        if T::IS_ZST {
208            if len < N {
209                let _ = self.advance_by(len);
210                // SAFETY: ZSTs can be conjured ex nihilo; only the amount has to be correct
211                return Err(unsafe { array::IntoIter::new_unchecked(raw_array, 0..len) });
212            }
213
214            let _ = self.advance_by(N);
215            // SAFETY: ditto
216            return Ok(unsafe { MaybeUninit::array_assume_init(raw_array) });
217        }
218
219        if len < N {
220            // SAFETY: `len` indicates that this many elements are available and we just checked that
221            // it fits into the array.
222            unsafe {
223                ptr::copy_nonoverlapping(
224                    self.as_ref().as_ptr(),
225                    raw_array.as_mut_ptr() as *mut T,
226                    len,
227                );
228                let _ = self.advance_by(len);
229                return Err(array::IntoIter::new_unchecked(raw_array, 0..len));
230            }
231        }
232
233        // SAFETY: `len` is larger than the array size. Copy a fixed amount here to fully initialize
234        // the array.
235        unsafe {
236            ptr::copy_nonoverlapping(self.as_ref().as_ptr(), raw_array.as_mut_ptr() as *mut T, N);
237            let _ = self.advance_by(N);
238            Ok(MaybeUninit::array_assume_init(raw_array))
239        }
240    }
241}
242
243#[stable(feature = "default_iters", since = "1.70.0")]
244impl<I: Default> Default for Copied<I> {
245    /// Creates a `Copied` iterator from the default value of `I`
246    /// ```
247    /// # use core::slice;
248    /// # use core::iter::Copied;
249    /// let iter: Copied<slice::Iter<'_, u8>> = Default::default();
250    /// assert_eq!(iter.len(), 0);
251    /// ```
252    fn default() -> Self {
253        Self::new(Default::default())
254    }
255}
256
257#[unstable(issue = "none", feature = "inplace_iteration")]
258unsafe impl<I> SourceIter for Copied<I>
259where
260    I: SourceIter,
261{
262    type Source = I::Source;
263
264    #[inline]
265    unsafe fn as_inner(&mut self) -> &mut I::Source {
266        // SAFETY: unsafe function forwarding to unsafe function with the same requirements
267        unsafe { SourceIter::as_inner(&mut self.it) }
268    }
269}
270
271#[unstable(issue = "none", feature = "inplace_iteration")]
272unsafe impl<I: InPlaceIterable> InPlaceIterable for Copied<I> {
273    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
274    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
275}