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