Skip to content

Commit 7c5398b

Browse files
committed
auto merge of #8276 : kballard/rust/iterator-protocol, r=cmr
r? @thestinger
2 parents 66593a7 + a3d18bc commit 7c5398b

File tree

2 files changed

+157
-8
lines changed

2 files changed

+157
-8
lines changed

doc/tutorial-container.md

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,18 @@ impl Iterator<int> for ZeroStream {
105105
}
106106
~~~
107107
108+
In general, you cannot rely on the behavior of the `next()` method after it has
109+
returned `None`. Some iterators may return `None` forever. Others may behave
110+
differently.
111+
108112
## Container iterators
109113
110114
Containers implement iteration over the contained elements by returning an
111115
iterator object. For example, vector slices several iterators available:
112116
113117
* `iter()` and `rev_iter()`, for immutable references to the elements
114118
* `mut_iter()` and `mut_rev_iter()`, for mutable references to the elements
115-
* `move_iter()` and `move_rev_iter`, to move the elements out by-value
119+
* `move_iter()` and `move_rev_iter()`, to move the elements out by-value
116120
117121
A typical mutable container will implement at least `iter()`, `mut_iter()` and
118122
`move_iter()` along with the reverse variants if it maintains an order.
@@ -149,7 +153,7 @@ let result = xs.iter().fold(0, |accumulator, item| accumulator - *item);
149153
assert_eq!(result, -41);
150154
~~~
151155
152-
Some adaptors return an adaptor object implementing the `Iterator` trait itself:
156+
Most adaptors return an adaptor object implementing the `Iterator` trait itself:
153157
154158
~~~
155159
let xs = [1, 9, 2, 3, 14, 12];
@@ -158,6 +162,35 @@ let sum = xs.iter().chain(ys.iter()).fold(0, |a, b| a + *b);
158162
assert_eq!(sum, 57);
159163
~~~
160164
165+
Some iterator adaptors may return `None` before exhausting the underlying
166+
iterator. Additionally, if these iterator adaptors are called again after
167+
returning `None`, they may call their underlying iterator again even if the
168+
adaptor will continue to return `None` forever. This may not be desired if the
169+
underlying iterator has side-effects.
170+
171+
In order to provide a guarantee about behavior once `None` has been returned, an
172+
iterator adaptor named `fuse()` is provided. This returns an iterator that will
173+
never call its underlying iterator again once `None` has been returned:
174+
175+
~~~
176+
let xs = [1,2,3,4,5];
177+
let mut calls = 0;
178+
let it = xs.iter().scan((), |_, x| {
179+
calls += 1;
180+
if *x < 3 { Some(x) } else { None }});
181+
// the iterator will only yield 1 and 2 before returning None
182+
// If we were to call it 5 times, calls would end up as 5, despite only 2 values
183+
// being yielded (and therefore 3 unique calls being made). The fuse() adaptor
184+
// can fix this.
185+
let mut it = it.fuse();
186+
it.next();
187+
it.next();
188+
it.next();
189+
it.next();
190+
it.next();
191+
assert_eq!(calls, 3);
192+
~~~
193+
161194
## For loops
162195
163196
The function `range` (or `range_inclusive`) allows to simply iterate through a given range:

src/libstd/iterator.rs

Lines changed: 122 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ pub trait Extendable<A>: FromIterator<A> {
4141
/// An interface for dealing with "external iterators". These types of iterators
4242
/// can be resumed at any time as all state is stored internally as opposed to
4343
/// being located on the call stack.
44+
///
45+
/// The Iterator protocol states that an iterator yields a (potentially-empty,
46+
/// potentially-infinite) sequence of values, and returns `None` to signal that
47+
/// it's finished. The Iterator protocol does not define behavior after `None`
48+
/// is returned. A concrete Iterator implementation may choose to behave however
49+
/// it wishes, either by returning `None` infinitely, or by doing something
50+
/// else.
4451
pub trait Iterator<A> {
4552
/// Advance the iterator and return the next value. Return `None` when the end is reached.
4653
fn next(&mut self) -> Option<A>;
@@ -300,6 +307,36 @@ pub trait Iterator<A> {
300307
FlatMap{iter: self, f: f, frontiter: None, backiter: None }
301308
}
302309

310+
/// Creates an iterator that yields `None` forever after the underlying
311+
/// iterator yields `None`. Random-access iterator behavior is not
312+
/// affected, only single and double-ended iterator behavior.
313+
///
314+
/// # Example
315+
///
316+
/// ~~~ {.rust}
317+
/// fn process<U: Iterator<int>>(it: U) -> int {
318+
/// let mut it = it.fuse();
319+
/// let mut sum = 0;
320+
/// for x in it {
321+
/// if x > 5 {
322+
/// break;
323+
/// }
324+
/// sum += x;
325+
/// }
326+
/// // did we exhaust the iterator?
327+
/// if it.next().is_none() {
328+
/// sum += 1000;
329+
/// }
330+
/// sum
331+
/// }
332+
/// let x = ~[1,2,3,7,8,9];
333+
/// assert_eq!(process(x.move_iter()), 1006);
334+
/// ~~~
335+
#[inline]
336+
fn fuse(self) -> Fuse<Self> {
337+
Fuse{iter: self, done: false}
338+
}
339+
303340
/// Creates an iterator that calls a function with a reference to each
304341
/// element before yielding it. This is often useful for debugging an
305342
/// iterator pipeline.
@@ -892,9 +929,12 @@ pub struct Zip<T, U> {
892929
impl<A, B, T: Iterator<A>, U: Iterator<B>> Iterator<(A, B)> for Zip<T, U> {
893930
#[inline]
894931
fn next(&mut self) -> Option<(A, B)> {
895-
match (self.a.next(), self.b.next()) {
896-
(Some(x), Some(y)) => Some((x, y)),
897-
_ => None
932+
match self.a.next() {
933+
None => None,
934+
Some(x) => match self.b.next() {
935+
None => None,
936+
Some(y) => Some((x, y))
937+
}
898938
}
899939
}
900940

@@ -925,9 +965,12 @@ RandomAccessIterator<(A, B)> for Zip<T, U> {
925965

926966
#[inline]
927967
fn idx(&self, index: uint) -> Option<(A, B)> {
928-
match (self.a.idx(index), self.b.idx(index)) {
929-
(Some(x), Some(y)) => Some((x, y)),
930-
_ => None
968+
match self.a.idx(index) {
969+
None => None,
970+
Some(x) => match self.b.idx(index) {
971+
None => None,
972+
Some(y) => Some((x, y))
973+
}
931974
}
932975
}
933976
}
@@ -1421,6 +1464,79 @@ impl<'self,
14211464
}
14221465
}
14231466

1467+
/// An iterator that yields `None` forever after the underlying iterator
1468+
/// yields `None` once.
1469+
#[deriving(Clone, DeepClone)]
1470+
pub struct Fuse<T> {
1471+
priv iter: T,
1472+
priv done: bool
1473+
}
1474+
1475+
impl<A, T: Iterator<A>> Iterator<A> for Fuse<T> {
1476+
#[inline]
1477+
fn next(&mut self) -> Option<A> {
1478+
if self.done {
1479+
None
1480+
} else {
1481+
match self.iter.next() {
1482+
None => {
1483+
self.done = true;
1484+
None
1485+
}
1486+
x => x
1487+
}
1488+
}
1489+
}
1490+
1491+
#[inline]
1492+
fn size_hint(&self) -> (uint, Option<uint>) {
1493+
if self.done {
1494+
(0, Some(0))
1495+
} else {
1496+
self.iter.size_hint()
1497+
}
1498+
}
1499+
}
1500+
1501+
impl<A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for Fuse<T> {
1502+
#[inline]
1503+
fn next_back(&mut self) -> Option<A> {
1504+
if self.done {
1505+
None
1506+
} else {
1507+
match self.iter.next_back() {
1508+
None => {
1509+
self.done = true;
1510+
None
1511+
}
1512+
x => x
1513+
}
1514+
}
1515+
}
1516+
}
1517+
1518+
// Allow RandomAccessIterators to be fused without affecting random-access behavior
1519+
impl<A, T: RandomAccessIterator<A>> RandomAccessIterator<A> for Fuse<T> {
1520+
#[inline]
1521+
fn indexable(&self) -> uint {
1522+
self.iter.indexable()
1523+
}
1524+
1525+
#[inline]
1526+
fn idx(&self, index: uint) -> Option<A> {
1527+
self.iter.idx(index)
1528+
}
1529+
}
1530+
1531+
impl<T> Fuse<T> {
1532+
/// Resets the fuse such that the next call to .next() or .next_back() will
1533+
/// call the underlying iterator again even if it prevously returned None.
1534+
#[inline]
1535+
fn reset_fuse(&mut self) {
1536+
self.done = false
1537+
}
1538+
}
1539+
14241540
/// An iterator that calls a function with a reference to each
14251541
/// element before yielding it.
14261542
pub struct Inspect<'self, A, T> {

0 commit comments

Comments
 (0)