| 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 | |