1//! `GenericArray` iterator implementation.
2
3use super::{ArrayLength, GenericArray};
4use core::iter::FusedIterator;
5use core::mem::ManuallyDrop;
6use core::{cmp, fmt, mem, ptr};
7
8/// An iterator that moves out of a `GenericArray`
9pub 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)]
19mod 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
30impl<T, N> GenericArrayIter<T, N>
31where
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
47impl<T, N> IntoIterator for GenericArray<T, N>
48where
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
64impl<T: fmt::Debug, N> fmt::Debug for GenericArrayIter<T, N>
65where
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
75impl<T, N> Drop for GenericArrayIter<T, N>
76where
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
93impl<T: Clone, N> Clone for GenericArrayIter<T, N>
94where
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
117impl<T, N> Iterator for GenericArrayIter<T, N>
118where
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
197impl<T, N> DoubleEndedIterator for GenericArrayIter<T, N>
198where
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
240impl<T, N> ExactSizeIterator for GenericArrayIter<T, N>
241where
242 N: ArrayLength<T>,
243{
244 fn len(&self) -> usize {
245 self.index_back - self.index
246 }
247}
248
249impl<T, N> FusedIterator for GenericArrayIter<T, N> where N: ArrayLength<T> {}
250
251// TODO: Implement `TrustedLen` when stabilized
252