Skip to content

Commit

Permalink
Port some improvements from rust-lang/rust#49000
Browse files Browse the repository at this point in the history
  • Loading branch information
novacrazy committed Mar 15, 2018
1 parent 8f5dc5d commit 6cec843
Show file tree
Hide file tree
Showing 3 changed files with 224 additions and 7 deletions.
62 changes: 60 additions & 2 deletions src/iter.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! `GenericArray` iterator implementation.
use super::{ArrayLength, GenericArray};
use core::{cmp, ptr};
use core::{cmp, ptr, fmt, mem};
use core::mem::ManuallyDrop;

/// An iterator that moves out of a `GenericArray`
Expand All @@ -26,6 +26,23 @@ mod test {
}
}

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>,
Expand All @@ -42,21 +59,58 @@ where
}
}

// Based on work in rust-land/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) {
// Drop values that are still alive.
for p in &mut self.array[self.index..self.index_back] {
for p in self.as_mut_slice() {
unsafe {
ptr::drop_in_place(p);
}
}
}
}

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.
unsafe {
let mut iter = GenericArrayIter {
array: ManuallyDrop::new(mem::uninitialized()),
index: 0,
index_back: 0,
};

for (dst, src) in iter.array.iter_mut().zip(self.as_slice()) {
ptr::write(dst, src.clone());

iter.index_back += 1;
}

iter
}
}
}

impl<T, N> Iterator for GenericArrayIter<T, N>
where
N: ArrayLength<T>,
Expand Down Expand Up @@ -90,8 +144,10 @@ where
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);
}
Expand Down Expand Up @@ -129,3 +185,5 @@ where
self.index_back - self.index
}
}

// TODO: Implement `FusedIterator` and `TrustedLen` when stabilized
164 changes: 164 additions & 0 deletions tests/iter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
#[macro_use]
extern crate generic_array;

use std::cell::Cell;
use std::ops::Drop;

use generic_array::GenericArray;
use generic_array::typenum::consts::U5;

#[test]
fn test_into_iter_as_slice() {
let array = arr![char; 'a', 'b', 'c'];
let mut into_iter = array.into_iter();
assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
let _ = into_iter.next().unwrap();
assert_eq!(into_iter.as_slice(), &['b', 'c']);
let _ = into_iter.next().unwrap();
let _ = into_iter.next().unwrap();
assert_eq!(into_iter.as_slice(), &[]);
}

#[test]
fn test_into_iter_as_mut_slice() {
let array = arr![char; 'a', 'b', 'c'];
let mut into_iter = array.into_iter();
assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
into_iter.as_mut_slice()[0] = 'x';
into_iter.as_mut_slice()[1] = 'y';
assert_eq!(into_iter.next().unwrap(), 'x');
assert_eq!(into_iter.as_slice(), &['y', 'c']);
}

#[test]
fn test_into_iter_debug() {
let array = arr![char; 'a', 'b', 'c'];
let into_iter = array.into_iter();
let debug = format!("{:?}", into_iter);
assert_eq!(debug, "GenericArrayIter(['a', 'b', 'c'])");
}

#[test]
fn test_into_iter_clone() {
fn iter_equal<I: Iterator<Item = i32>>(it: I, slice: &[i32]) {
let v: Vec<i32> = it.collect();
assert_eq!(&v[..], slice);
}
let mut it = arr![i32; 1, 2, 3].into_iter();
iter_equal(it.clone(), &[1, 2, 3]);
assert_eq!(it.next(), Some(1));
let mut it = it.rev();
iter_equal(it.clone(), &[3, 2]);
assert_eq!(it.next(), Some(3));
iter_equal(it.clone(), &[2]);
assert_eq!(it.next(), Some(2));
iter_equal(it.clone(), &[]);
assert_eq!(it.next(), None);
}

#[test]
fn test_into_iter_nth() {
let v = arr![i32; 0, 1, 2, 3, 4];
for i in 0..v.len() {
assert_eq!(v.clone().into_iter().nth(i).unwrap(), v[i]);
}
assert_eq!(v.clone().into_iter().nth(v.len()), None);

let mut iter = v.into_iter();
assert_eq!(iter.nth(2).unwrap(), v[2]);
assert_eq!(iter.nth(1).unwrap(), v[4]);
}

#[test]
fn test_into_iter_last() {
let v = arr![i32; 0, 1, 2, 3, 4];
assert_eq!(v.into_iter().last().unwrap(), 4);
assert_eq!(arr![i32; 0].into_iter().last().unwrap(), 0);
}

#[test]
fn test_into_iter_count() {
let v = arr![i32; 0, 1, 2, 3, 4];
assert_eq!(v.clone().into_iter().count(), 5);

let mut iter2 = v.into_iter();
iter2.next();
iter2.next();
assert_eq!(iter2.count(), 3);
}

#[test]
fn test_into_iter_flat_map() {
assert!((0..5).flat_map(|i| arr![i32; 2 * i, 2 * i + 1]).eq(0..10));
}

#[test]
fn test_into_iter_drops() {
struct R<'a> {
i: &'a Cell<usize>,
}

impl<'a> Drop for R<'a> {
fn drop(&mut self) {
self.i.set(self.i.get() + 1);
}
}

fn r(i: &Cell<usize>) -> R {
R {
i: i
}
}

fn v(i: &Cell<usize>) -> GenericArray<R, U5> {
arr![R; r(i), r(i), r(i), r(i), r(i)]
}

let i = Cell::new(0);
{
v(&i).into_iter();
}
assert_eq!(i.get(), 5);

let i = Cell::new(0);
{
let mut iter = v(&i).into_iter();
let _x = iter.next();
assert_eq!(i.get(), 0);
assert_eq!(iter.count(), 4);
assert_eq!(i.get(), 4);
}
assert_eq!(i.get(), 5);

let i = Cell::new(0);
{
let mut iter = v(&i).into_iter();
let _x = iter.nth(2);
assert_eq!(i.get(), 2);
let _y = iter.last();
assert_eq!(i.get(), 3);
}
assert_eq!(i.get(), 5);

let i = Cell::new(0);
for (index, _x) in v(&i).into_iter().enumerate() {
assert_eq!(i.get(), index);
}
assert_eq!(i.get(), 5);

let i = Cell::new(0);
for (index, _x) in v(&i).into_iter().rev().enumerate() {
assert_eq!(i.get(), index);
}
assert_eq!(i.get(), 5);
}

/*
//TODO: Cover this
#[allow(dead_code)]
fn assert_covariance() {
fn into_iter<'new>(i: GenericArrayIter<&'static str, U10>) -> GenericArrayIter<&'new str, U10> {
i
}
}
*/
5 changes: 0 additions & 5 deletions tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,6 @@ fn test_copy() {
assert_eq!(test2[0], 1);
}

#[test]
fn test_iter_flat_map() {
assert!((0..5).flat_map(|i| arr![i32; 2 * i, 2 * i + 1]).eq(0..10));
}

#[derive(Debug, PartialEq, Eq)]
struct NoClone<T>(T);

Expand Down

0 comments on commit 6cec843

Please sign in to comment.