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