Skip to main content

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