Skip to content

Commit c9d53d6

Browse files
committed
Merge pull request #13 from cuviper/into_iter
impl IntoIterator for GenericArray
2 parents 122f450 + 7098dfd commit c9d53d6

File tree

3 files changed

+104
-0
lines changed

3 files changed

+104
-0
lines changed

src/iter.rs

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
use nodrop::NoDrop;
2+
use std::cmp;
3+
use std::ptr;
4+
use super::{GenericArray, ArrayLength};
5+
6+
/// An iterator that moves out of a `GenericArray`
7+
pub struct GenericArrayIter<T, N: ArrayLength<T>> {
8+
// Invariants: index <= index_back <= N
9+
// Only values in array[index..index_back] are alive at any given time.
10+
// Values from array[..index] and array[index_back..] are already moved/dropped.
11+
array: NoDrop<GenericArray<T, N>>,
12+
index: usize,
13+
index_back: usize,
14+
}
15+
16+
impl<T, N> IntoIterator for GenericArray<T, N> where N: ArrayLength<T> {
17+
type Item = T;
18+
type IntoIter = GenericArrayIter<T, N>;
19+
20+
fn into_iter(self) -> Self::IntoIter {
21+
GenericArrayIter {
22+
array: NoDrop::new(self),
23+
index: 0,
24+
index_back: N::to_usize(),
25+
}
26+
}
27+
}
28+
29+
impl<T, N> Drop for GenericArrayIter<T, N> where N: ArrayLength<T> {
30+
fn drop(&mut self) {
31+
// Drop values that are still alive.
32+
for p in &mut self.array[self.index..self.index_back] {
33+
unsafe { ptr::drop_in_place(p); }
34+
}
35+
}
36+
}
37+
38+
impl<T, N> Iterator for GenericArrayIter<T, N> where N: ArrayLength<T> {
39+
type Item = T;
40+
41+
fn next(&mut self) -> Option<T> {
42+
if self.len() > 0 {
43+
unsafe {
44+
let p = self.array.get_unchecked(self.index);
45+
self.index += 1;
46+
Some(ptr::read(p))
47+
}
48+
} else {
49+
None
50+
}
51+
}
52+
53+
fn size_hint(&self) -> (usize, Option<usize>) {
54+
let len = self.len();
55+
(len, Some(len))
56+
}
57+
58+
fn count(self) -> usize {
59+
self.len()
60+
}
61+
62+
fn nth(&mut self, n: usize) -> Option<T> {
63+
// First consume values prior to the nth.
64+
let ndrop = cmp::min(n, self.len());
65+
for p in &mut self.array[self.index..self.index + ndrop] {
66+
self.index += 1;
67+
unsafe { ptr::drop_in_place(p); }
68+
}
69+
70+
self.next()
71+
}
72+
73+
fn last(mut self) -> Option<T> {
74+
// Note, everything else will correctly drop first as `self` leaves scope.
75+
self.next_back()
76+
}
77+
}
78+
79+
impl<T, N> DoubleEndedIterator for GenericArrayIter<T, N> where N: ArrayLength<T> {
80+
fn next_back(&mut self) -> Option<T> {
81+
if self.len() > 0 {
82+
self.index_back -= 1;
83+
unsafe {
84+
let p = self.array.get_unchecked(self.index_back);
85+
Some(ptr::read(p))
86+
}
87+
} else {
88+
None
89+
}
90+
}
91+
}
92+
93+
impl<T, N> ExactSizeIterator for GenericArrayIter<T, N> where N: ArrayLength<T> {
94+
fn len(&self) -> usize {
95+
self.index_back - self.index
96+
}
97+
}

src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ extern crate core as std;
3737
extern crate typenum;
3838
extern crate nodrop;
3939
pub mod arr;
40+
pub mod iter;
41+
pub use iter::GenericArrayIter;
4042
use nodrop::NoDrop;
4143
use typenum::uint::{Unsigned, UTerm, UInt};
4244
use typenum::bit::{B0, B1};

tests/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,8 @@ fn test_arr() {
5050
let test: GenericArray<u32, U3> = arr![u32; 1, 2, 3];
5151
assert_eq!(test[1], 2);
5252
}
53+
54+
#[test]
55+
fn test_iter_flat_map() {
56+
assert!((0..5).flat_map(|i| arr![i32; 2 * i, 2 * i + 1]).eq(0..10));
57+
}

0 commit comments

Comments
 (0)