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