1 //! `GenericArray` iterator implementation.
2 
3 use super::{ArrayLength, GenericArray};
4 use core::{cmp, ptr, fmt, mem};
5 use core::mem::ManuallyDrop;
6 
7 /// An iterator that moves out of a `GenericArray`
8 pub struct GenericArrayIter<T, N: ArrayLength<T>> {
9     // Invariants: index <= index_back <= N
10     // Only values in array[index..index_back] are alive at any given time.
11     // Values from array[..index] and array[index_back..] are already moved/dropped.
12     array: ManuallyDrop<GenericArray<T, N>>,
13     index: usize,
14     index_back: usize,
15 }
16 
17 #[cfg(test)]
18 mod test {
19     use super::*;
20 
send<I: Send>(_iter: I)21     fn send<I: Send>(_iter: I) {}
22 
23     #[test]
test_send_iter()24     fn test_send_iter() {
25         send(GenericArray::from([1, 2, 3, 4]).into_iter());
26     }
27 }
28 
29 impl<T, N> GenericArrayIter<T, N>
30 where
31     N: ArrayLength<T>,
32 {
33     /// Returns the remaining items of this iterator as a slice
34     #[inline]
as_slice(&self) -> &[T]35     pub fn as_slice(&self) -> &[T] {
36         &self.array.as_slice()[self.index..self.index_back]
37     }
38 
39     /// Returns the remaining items of this iterator as a mutable slice
40     #[inline]
as_mut_slice(&mut self) -> &mut [T]41     pub fn as_mut_slice(&mut self) -> &mut [T] {
42         &mut self.array.as_mut_slice()[self.index..self.index_back]
43     }
44 }
45 
46 impl<T, N> IntoIterator for GenericArray<T, N>
47 where
48     N: ArrayLength<T>,
49 {
50     type Item = T;
51     type IntoIter = GenericArrayIter<T, N>;
52 
into_iter(self) -> Self::IntoIter53     fn into_iter(self) -> Self::IntoIter {
54         GenericArrayIter {
55             array: ManuallyDrop::new(self),
56             index: 0,
57             index_back: N::to_usize(),
58         }
59     }
60 }
61 
62 // Based on work in rust-lang/rust#49000
63 impl<T: fmt::Debug, N> fmt::Debug for GenericArrayIter<T, N>
64 where
65     N: ArrayLength<T>,
66 {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result67     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68         f.debug_tuple("GenericArrayIter")
69             .field(&self.as_slice())
70             .finish()
71     }
72 }
73 
74 impl<T, N> Drop for GenericArrayIter<T, N>
75 where
76     N: ArrayLength<T>,
77 {
78     #[inline]
drop(&mut self)79     fn drop(&mut self) {
80         // Drop values that are still alive.
81         for p in self.as_mut_slice() {
82             unsafe {
83                 ptr::drop_in_place(p);
84             }
85         }
86     }
87 }
88 
89 // Based on work in rust-lang/rust#49000
90 impl<T: Clone, N> Clone for GenericArrayIter<T, N>
91 where
92     N: ArrayLength<T>,
93 {
clone(&self) -> Self94     fn clone(&self) -> Self {
95         // This places all cloned elements at the start of the new array iterator,
96         // not at their original indices.
97         unsafe {
98             let mut iter = GenericArrayIter {
99                 array: ManuallyDrop::new(mem::uninitialized()),
100                 index: 0,
101                 index_back: 0,
102             };
103 
104             for (dst, src) in iter.array.iter_mut().zip(self.as_slice()) {
105                 ptr::write(dst, src.clone());
106 
107                 iter.index_back += 1;
108             }
109 
110             iter
111         }
112     }
113 }
114 
115 impl<T, N> Iterator for GenericArrayIter<T, N>
116 where
117     N: ArrayLength<T>,
118 {
119     type Item = T;
120 
121     #[inline]
next(&mut self) -> Option<T>122     fn next(&mut self) -> Option<T> {
123         if self.index < self.index_back {
124             let p = unsafe { Some(ptr::read(self.array.get_unchecked(self.index))) };
125 
126             self.index += 1;
127 
128             p
129         } else {
130             None
131         }
132     }
133 
134     #[inline]
size_hint(&self) -> (usize, Option<usize>)135     fn size_hint(&self) -> (usize, Option<usize>) {
136         let len = self.len();
137         (len, Some(len))
138     }
139 
140     #[inline]
count(self) -> usize141     fn count(self) -> usize {
142         self.len()
143     }
144 
nth(&mut self, n: usize) -> Option<T>145     fn nth(&mut self, n: usize) -> Option<T> {
146         // First consume values prior to the nth.
147         let ndrop = cmp::min(n, self.len());
148 
149         for p in &mut self.array[self.index..self.index + ndrop] {
150             self.index += 1;
151 
152             unsafe {
153                 ptr::drop_in_place(p);
154             }
155         }
156 
157         self.next()
158     }
159 
last(mut self) -> Option<T>160     fn last(mut self) -> Option<T> {
161         // Note, everything else will correctly drop first as `self` leaves scope.
162         self.next_back()
163     }
164 }
165 
166 impl<T, N> DoubleEndedIterator for GenericArrayIter<T, N>
167 where
168     N: ArrayLength<T>,
169 {
next_back(&mut self) -> Option<T>170     fn next_back(&mut self) -> Option<T> {
171         if self.index < self.index_back {
172             self.index_back -= 1;
173 
174             unsafe { Some(ptr::read(self.array.get_unchecked(self.index_back))) }
175         } else {
176             None
177         }
178     }
179 }
180 
181 impl<T, N> ExactSizeIterator for GenericArrayIter<T, N>
182 where
183     N: ArrayLength<T>,
184 {
len(&self) -> usize185     fn len(&self) -> usize {
186         self.index_back - self.index
187     }
188 }
189 
190 // TODO: Implement `FusedIterator` and `TrustedLen` when stabilized