diff options
Diffstat (limited to 'third_party/rust/generic-array/src/iter.rs')
-rw-r--r-- | third_party/rust/generic-array/src/iter.rs | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/third_party/rust/generic-array/src/iter.rs b/third_party/rust/generic-array/src/iter.rs new file mode 100644 index 0000000000..784ffa9068 --- /dev/null +++ b/third_party/rust/generic-array/src/iter.rs @@ -0,0 +1,251 @@ +//! `GenericArray` iterator implementation.
+
+use super::{ArrayLength, GenericArray};
+use core::iter::FusedIterator;
+use core::mem::ManuallyDrop;
+use core::{cmp, fmt, mem, ptr};
+
+/// An iterator that moves out of a `GenericArray`
+pub struct GenericArrayIter<T, N: ArrayLength<T>> {
+ // Invariants: index <= index_back <= N
+ // Only values in array[index..index_back] are alive at any given time.
+ // Values from array[..index] and array[index_back..] are already moved/dropped.
+ array: ManuallyDrop<GenericArray<T, N>>,
+ index: usize,
+ index_back: usize,
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ fn send<I: Send>(_iter: I) {}
+
+ #[test]
+ fn test_send_iter() {
+ send(GenericArray::from([1, 2, 3, 4]).into_iter());
+ }
+}
+
+impl<T, N> GenericArrayIter<T, N>
+where
+ N: ArrayLength<T>,
+{
+ /// Returns the remaining items of this iterator as a slice
+ #[inline]
+ pub fn as_slice(&self) -> &[T] {
+ &self.array.as_slice()[self.index..self.index_back]
+ }
+
+ /// Returns the remaining items of this iterator as a mutable slice
+ #[inline]
+ pub fn as_mut_slice(&mut self) -> &mut [T] {
+ &mut self.array.as_mut_slice()[self.index..self.index_back]
+ }
+}
+
+impl<T, N> IntoIterator for GenericArray<T, N>
+where
+ N: ArrayLength<T>,
+{
+ type Item = T;
+ type IntoIter = GenericArrayIter<T, N>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ GenericArrayIter {
+ array: ManuallyDrop::new(self),
+ index: 0,
+ index_back: N::USIZE,
+ }
+ }
+}
+
+// Based on work in rust-lang/rust#49000
+impl<T: fmt::Debug, N> fmt::Debug for GenericArrayIter<T, N>
+where
+ N: ArrayLength<T>,
+{
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_tuple("GenericArrayIter")
+ .field(&self.as_slice())
+ .finish()
+ }
+}
+
+impl<T, N> Drop for GenericArrayIter<T, N>
+where
+ N: ArrayLength<T>,
+{
+ #[inline]
+ fn drop(&mut self) {
+ if mem::needs_drop::<T>() {
+ // Drop values that are still alive.
+ for p in self.as_mut_slice() {
+ unsafe {
+ ptr::drop_in_place(p);
+ }
+ }
+ }
+ }
+}
+
+// Based on work in rust-lang/rust#49000
+impl<T: Clone, N> Clone for GenericArrayIter<T, N>
+where
+ N: ArrayLength<T>,
+{
+ fn clone(&self) -> Self {
+ // This places all cloned elements at the start of the new array iterator,
+ // not at their original indices.
+
+ let mut array = unsafe { ptr::read(&self.array) };
+ let mut index_back = 0;
+
+ for (dst, src) in array.as_mut_slice().into_iter().zip(self.as_slice()) {
+ unsafe { ptr::write(dst, src.clone()) };
+ index_back += 1;
+ }
+
+ GenericArrayIter {
+ array,
+ index: 0,
+ index_back,
+ }
+ }
+}
+
+impl<T, N> Iterator for GenericArrayIter<T, N>
+where
+ N: ArrayLength<T>,
+{
+ type Item = T;
+
+ #[inline]
+ fn next(&mut self) -> Option<T> {
+ if self.index < self.index_back {
+ let p = unsafe { Some(ptr::read(self.array.get_unchecked(self.index))) };
+
+ self.index += 1;
+
+ p
+ } else {
+ None
+ }
+ }
+
+ fn fold<B, F>(mut self, init: B, mut f: F) -> B
+ where
+ F: FnMut(B, Self::Item) -> B,
+ {
+ let ret = unsafe {
+ let GenericArrayIter {
+ ref array,
+ ref mut index,
+ index_back,
+ } = self;
+
+ let remaining = &array[*index..index_back];
+
+ remaining.iter().fold(init, |acc, src| {
+ let value = ptr::read(src);
+
+ *index += 1;
+
+ f(acc, value)
+ })
+ };
+
+ // ensure the drop happens here after iteration
+ drop(self);
+
+ ret
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let len = self.len();
+ (len, Some(len))
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.len()
+ }
+
+ fn nth(&mut self, n: usize) -> Option<T> {
+ // First consume values prior to the nth.
+ let ndrop = cmp::min(n, self.len());
+
+ for p in &mut self.array[self.index..self.index + ndrop] {
+ self.index += 1;
+
+ unsafe {
+ ptr::drop_in_place(p);
+ }
+ }
+
+ self.next()
+ }
+
+ #[inline]
+ fn last(mut self) -> Option<T> {
+ // Note, everything else will correctly drop first as `self` leaves scope.
+ self.next_back()
+ }
+}
+
+impl<T, N> DoubleEndedIterator for GenericArrayIter<T, N>
+where
+ N: ArrayLength<T>,
+{
+ fn next_back(&mut self) -> Option<T> {
+ if self.index < self.index_back {
+ self.index_back -= 1;
+
+ unsafe { Some(ptr::read(self.array.get_unchecked(self.index_back))) }
+ } else {
+ None
+ }
+ }
+
+ fn rfold<B, F>(mut self, init: B, mut f: F) -> B
+ where
+ F: FnMut(B, Self::Item) -> B,
+ {
+ let ret = unsafe {
+ let GenericArrayIter {
+ ref array,
+ index,
+ ref mut index_back,
+ } = self;
+
+ let remaining = &array[index..*index_back];
+
+ remaining.iter().rfold(init, |acc, src| {
+ let value = ptr::read(src);
+
+ *index_back -= 1;
+
+ f(acc, value)
+ })
+ };
+
+ // ensure the drop happens here after iteration
+ drop(self);
+
+ ret
+ }
+}
+
+impl<T, N> ExactSizeIterator for GenericArrayIter<T, N>
+where
+ N: ArrayLength<T>,
+{
+ fn len(&self) -> usize {
+ self.index_back - self.index
+ }
+}
+
+impl<T, N> FusedIterator for GenericArrayIter<T, N> where N: ArrayLength<T> {}
+
+// TODO: Implement `TrustedLen` when stabilized
|