1 | //! `GenericArray` iterator implementation.
|
2 |
|
3 | use super::{ArrayLength, GenericArray};
|
4 | use core::iter::FusedIterator;
|
5 | use core::mem::ManuallyDrop;
|
6 | use core::{cmp, fmt, mem, ptr};
|
7 |
|
8 | /// An iterator that moves out of a `GenericArray`
|
9 | pub struct GenericArrayIter<T, N: ArrayLength<T>> {
|
10 | // Invariants: index <= index_back <= N
|
11 | // Only values in array[index..index_back] are alive at any given time.
|
12 | // Values from array[..index] and array[index_back..] are already moved/dropped.
|
13 | array: ManuallyDrop<GenericArray<T, N>>,
|
14 | index: usize,
|
15 | index_back: usize,
|
16 | }
|
17 |
|
18 | #[cfg (test)]
|
19 | mod test {
|
20 | use super::*;
|
21 |
|
22 | fn send<I: Send>(_iter: I) {}
|
23 |
|
24 | #[test ]
|
25 | fn test_send_iter() {
|
26 | send(GenericArray::from([1, 2, 3, 4]).into_iter());
|
27 | }
|
28 | }
|
29 |
|
30 | impl<T, N> GenericArrayIter<T, N>
|
31 | where
|
32 | N: ArrayLength<T>,
|
33 | {
|
34 | /// Returns the remaining items of this iterator as a slice
|
35 | #[inline ]
|
36 | pub fn as_slice(&self) -> &[T] {
|
37 | &self.array.as_slice()[self.index..self.index_back]
|
38 | }
|
39 |
|
40 | /// Returns the remaining items of this iterator as a mutable slice
|
41 | #[inline ]
|
42 | pub fn as_mut_slice(&mut self) -> &mut [T] {
|
43 | &mut self.array.as_mut_slice()[self.index..self.index_back]
|
44 | }
|
45 | }
|
46 |
|
47 | impl<T, N> IntoIterator for GenericArray<T, N>
|
48 | where
|
49 | N: ArrayLength<T>,
|
50 | {
|
51 | type Item = T;
|
52 | type IntoIter = GenericArrayIter<T, N>;
|
53 |
|
54 | fn into_iter(self) -> Self::IntoIter {
|
55 | GenericArrayIter {
|
56 | array: ManuallyDrop::new(self),
|
57 | index: 0,
|
58 | index_back: N::USIZE,
|
59 | }
|
60 | }
|
61 | }
|
62 |
|
63 | // Based on work in rust-lang/rust#49000
|
64 | impl<T: fmt::Debug, N> fmt::Debug for GenericArrayIter<T, N>
|
65 | where
|
66 | N: ArrayLength<T>,
|
67 | {
|
68 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
69 | f&mut DebugTuple<'_, '_>.debug_tuple(name:"GenericArrayIter" )
|
70 | .field(&self.as_slice())
|
71 | .finish()
|
72 | }
|
73 | }
|
74 |
|
75 | impl<T, N> Drop for GenericArrayIter<T, N>
|
76 | where
|
77 | N: ArrayLength<T>,
|
78 | {
|
79 | #[inline ]
|
80 | fn drop(&mut self) {
|
81 | if mem::needs_drop::<T>() {
|
82 | // Drop values that are still alive.
|
83 | for p: &mut T in self.as_mut_slice() {
|
84 | unsafe {
|
85 | ptr::drop_in_place(to_drop:p);
|
86 | }
|
87 | }
|
88 | }
|
89 | }
|
90 | }
|
91 |
|
92 | // Based on work in rust-lang/rust#49000
|
93 | impl<T: Clone, N> Clone for GenericArrayIter<T, N>
|
94 | where
|
95 | N: ArrayLength<T>,
|
96 | {
|
97 | fn clone(&self) -> Self {
|
98 | // This places all cloned elements at the start of the new array iterator,
|
99 | // not at their original indices.
|
100 |
|
101 | let mut array: ManuallyDrop> = unsafe { ptr::read(&self.array) };
|
102 | let mut index_back: usize = 0;
|
103 |
|
104 | for (dst: &mut T, src: &T) in array.as_mut_slice().into_iter().zip(self.as_slice()) {
|
105 | unsafe { ptr::write(dst, src.clone()) };
|
106 | index_back += 1;
|
107 | }
|
108 |
|
109 | GenericArrayIter {
|
110 | array,
|
111 | index: 0,
|
112 | index_back,
|
113 | }
|
114 | }
|
115 | }
|
116 |
|
117 | impl<T, N> Iterator for GenericArrayIter<T, N>
|
118 | where
|
119 | N: ArrayLength<T>,
|
120 | {
|
121 | type Item = T;
|
122 |
|
123 | #[inline ]
|
124 | fn next(&mut self) -> Option<T> {
|
125 | if self.index < self.index_back {
|
126 | let p = unsafe { Some(ptr::read(self.array.get_unchecked(self.index))) };
|
127 |
|
128 | self.index += 1;
|
129 |
|
130 | p
|
131 | } else {
|
132 | None
|
133 | }
|
134 | }
|
135 |
|
136 | fn fold<B, F>(mut self, init: B, mut f: F) -> B
|
137 | where
|
138 | F: FnMut(B, Self::Item) -> B,
|
139 | {
|
140 | let ret = unsafe {
|
141 | let GenericArrayIter {
|
142 | ref array,
|
143 | ref mut index,
|
144 | index_back,
|
145 | } = self;
|
146 |
|
147 | let remaining = &array[*index..index_back];
|
148 |
|
149 | remaining.iter().fold(init, |acc, src| {
|
150 | let value = ptr::read(src);
|
151 |
|
152 | *index += 1;
|
153 |
|
154 | f(acc, value)
|
155 | })
|
156 | };
|
157 |
|
158 | // ensure the drop happens here after iteration
|
159 | drop(self);
|
160 |
|
161 | ret
|
162 | }
|
163 |
|
164 | #[inline ]
|
165 | fn size_hint(&self) -> (usize, Option<usize>) {
|
166 | let len = self.len();
|
167 | (len, Some(len))
|
168 | }
|
169 |
|
170 | #[inline ]
|
171 | fn count(self) -> usize {
|
172 | self.len()
|
173 | }
|
174 |
|
175 | fn nth(&mut self, n: usize) -> Option<T> {
|
176 | // First consume values prior to the nth.
|
177 | let ndrop = cmp::min(n, self.len());
|
178 |
|
179 | for p in &mut self.array[self.index..self.index + ndrop] {
|
180 | self.index += 1;
|
181 |
|
182 | unsafe {
|
183 | ptr::drop_in_place(p);
|
184 | }
|
185 | }
|
186 |
|
187 | self.next()
|
188 | }
|
189 |
|
190 | #[inline ]
|
191 | fn last(mut self) -> Option<T> {
|
192 | // Note, everything else will correctly drop first as `self` leaves scope.
|
193 | self.next_back()
|
194 | }
|
195 | }
|
196 |
|
197 | impl<T, N> DoubleEndedIterator for GenericArrayIter<T, N>
|
198 | where
|
199 | N: ArrayLength<T>,
|
200 | {
|
201 | fn next_back(&mut self) -> Option<T> {
|
202 | if self.index < self.index_back {
|
203 | self.index_back -= 1;
|
204 |
|
205 | unsafe { Some(ptr::read(self.array.get_unchecked(self.index_back))) }
|
206 | } else {
|
207 | None
|
208 | }
|
209 | }
|
210 |
|
211 | fn rfold<B, F>(mut self, init: B, mut f: F) -> B
|
212 | where
|
213 | F: FnMut(B, Self::Item) -> B,
|
214 | {
|
215 | let ret = unsafe {
|
216 | let GenericArrayIter {
|
217 | ref array,
|
218 | index,
|
219 | ref mut index_back,
|
220 | } = self;
|
221 |
|
222 | let remaining = &array[index..*index_back];
|
223 |
|
224 | remaining.iter().rfold(init, |acc, src| {
|
225 | let value = ptr::read(src);
|
226 |
|
227 | *index_back -= 1;
|
228 |
|
229 | f(acc, value)
|
230 | })
|
231 | };
|
232 |
|
233 | // ensure the drop happens here after iteration
|
234 | drop(self);
|
235 |
|
236 | ret
|
237 | }
|
238 | }
|
239 |
|
240 | impl<T, N> ExactSizeIterator for GenericArrayIter<T, N>
|
241 | where
|
242 | N: ArrayLength<T>,
|
243 | {
|
244 | fn len(&self) -> usize {
|
245 | self.index_back - self.index
|
246 | }
|
247 | }
|
248 |
|
249 | impl<T, N> FusedIterator for GenericArrayIter<T, N> where N: ArrayLength<T> {}
|
250 |
|
251 | // TODO: Implement `TrustedLen` when stabilized
|
252 | |