1 //! `GenericArray` iterator implementation.
2 
3 use super::{ArrayLength, GenericArray};
4 use core::iter::FusedIterator;
5 use core::mem::{MaybeUninit, ManuallyDrop};
6 use core::{cmp, fmt, ptr, mem};
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 
send<I: Send>(_iter: I)22     fn send<I: Send>(_iter: I) {}
23 
24     #[test]
test_send_iter()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]
as_slice(&self) -> &[T]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]
as_mut_slice(&mut self) -> &mut [T]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 
into_iter(self) -> Self::IntoIter54     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 {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result68     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69         f.debug_tuple("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]
drop(&mut self)80     fn drop(&mut self) {
81         if mem::needs_drop::<T>() {
82             // Drop values that are still alive.
83             for p in self.as_mut_slice() {
84                 unsafe {
85                     ptr::drop_in_place(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 {
clone(&self) -> Self97     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         unsafe {
101             let mut array: MaybeUninit<GenericArray<T, N>> = MaybeUninit::uninit();
102             let mut index_back = 0;
103 
104             for (dst, src) in (&mut *array.as_mut_ptr()).iter_mut().zip(self.as_slice()) {
105                 ptr::write(dst, src.clone());
106 
107                 index_back += 1;
108             }
109 
110             GenericArrayIter {
111                 array: ManuallyDrop::new(array.assume_init()),
112                 index: 0,
113                 index_back
114             }
115         }
116     }
117 }
118 
119 impl<T, N> Iterator for GenericArrayIter<T, N>
120 where
121     N: ArrayLength<T>,
122 {
123     type Item = T;
124 
125     #[inline]
next(&mut self) -> Option<T>126     fn next(&mut self) -> Option<T> {
127         if self.index < self.index_back {
128             let p = unsafe { Some(ptr::read(self.array.get_unchecked(self.index))) };
129 
130             self.index += 1;
131 
132             p
133         } else {
134             None
135         }
136     }
137 
fold<B, F>(mut self, init: B, mut f: F) -> B where F: FnMut(B, Self::Item) -> B,138     fn fold<B, F>(mut self, init: B, mut f: F) -> B
139     where
140         F: FnMut(B, Self::Item) -> B,
141     {
142         let ret = unsafe {
143             let GenericArrayIter {
144                 ref array,
145                 ref mut index,
146                 index_back,
147             } = self;
148 
149             let remaining = &array[*index..index_back];
150 
151             remaining.iter().fold(init, |acc, src| {
152                 let value = ptr::read(src);
153 
154                 *index += 1;
155 
156                 f(acc, value)
157             })
158         };
159 
160         // ensure the drop happens here after iteration
161         drop(self);
162 
163         ret
164     }
165 
166     #[inline]
size_hint(&self) -> (usize, Option<usize>)167     fn size_hint(&self) -> (usize, Option<usize>) {
168         let len = self.len();
169         (len, Some(len))
170     }
171 
172     #[inline]
count(self) -> usize173     fn count(self) -> usize {
174         self.len()
175     }
176 
nth(&mut self, n: usize) -> Option<T>177     fn nth(&mut self, n: usize) -> Option<T> {
178         // First consume values prior to the nth.
179         let ndrop = cmp::min(n, self.len());
180 
181         for p in &mut self.array[self.index..self.index + ndrop] {
182             self.index += 1;
183 
184             unsafe {
185                 ptr::drop_in_place(p);
186             }
187         }
188 
189         self.next()
190     }
191 
192     #[inline]
last(mut self) -> Option<T>193     fn last(mut self) -> Option<T> {
194         // Note, everything else will correctly drop first as `self` leaves scope.
195         self.next_back()
196     }
197 }
198 
199 impl<T, N> DoubleEndedIterator for GenericArrayIter<T, N>
200 where
201     N: ArrayLength<T>,
202 {
next_back(&mut self) -> Option<T>203     fn next_back(&mut self) -> Option<T> {
204         if self.index < self.index_back {
205             self.index_back -= 1;
206 
207             unsafe { Some(ptr::read(self.array.get_unchecked(self.index_back))) }
208         } else {
209             None
210         }
211     }
212 
rfold<B, F>(mut self, init: B, mut f: F) -> B where F: FnMut(B, Self::Item) -> B,213     fn rfold<B, F>(mut self, init: B, mut f: F) -> B
214     where
215         F: FnMut(B, Self::Item) -> B,
216     {
217         let ret = unsafe {
218             let GenericArrayIter {
219                 ref array,
220                 index,
221                 ref mut index_back,
222             } = self;
223 
224             let remaining = &array[index..*index_back];
225 
226             remaining.iter().rfold(init, |acc, src| {
227                 let value = ptr::read(src);
228 
229                 *index_back -= 1;
230 
231                 f(acc, value)
232             })
233         };
234 
235         // ensure the drop happens here after iteration
236         drop(self);
237 
238         ret
239     }
240 }
241 
242 impl<T, N> ExactSizeIterator for GenericArrayIter<T, N>
243 where
244     N: ArrayLength<T>,
245 {
len(&self) -> usize246     fn len(&self) -> usize {
247         self.index_back - self.index
248     }
249 }
250 
251 impl<T, N> FusedIterator for GenericArrayIter<T, N>
252 where
253     N: ArrayLength<T>,
254 {
255 }
256 
257 // TODO: Implement `TrustedLen` when stabilized
258