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