Skip to content

Commit 543691d

Browse files
committed
Auto merge of #41439 - ivandardi:master, r=BurntSushi
Stabilize step_by by adding it to Iterator (issue #27741) Inspired by itertools' `take()` method. See issue #27741
2 parents b21577e + 4955517 commit 543691d

File tree

5 files changed

+106
-3
lines changed

5 files changed

+106
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# `iterator_step_by`
2+
3+
The tracking issue for this feature is: [#27741]
4+
5+
[#27741]: https://github.com/rust-lang/rust/issues/27741
6+
7+
------------------------

src/libcore/iter/iterator.rs

+34-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use cmp::Ordering;
1212

1313
use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, FlatMap, Fuse};
14-
use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, Take, TakeWhile, Rev};
14+
use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile, Rev};
1515
use super::{Zip, Sum, Product};
1616
use super::{ChainState, FromIterator, ZipImpl};
1717

@@ -258,6 +258,39 @@ pub trait Iterator {
258258
None
259259
}
260260

261+
/// Creates an iterator starting at the same point, but stepping by
262+
/// the given amount at each iteration.
263+
///
264+
/// Note that it will always return the first element of the range,
265+
/// regardless of the step given.
266+
///
267+
/// # Panics
268+
///
269+
/// The method will panic if the given step is `0`.
270+
///
271+
/// # Examples
272+
///
273+
/// Basic usage:
274+
///
275+
/// ```
276+
/// #![feature(iterator_step_by)]
277+
/// let a = [0, 1, 2, 3, 4, 5];
278+
/// let mut iter = a.into_iter().step_by(2);
279+
///
280+
/// assert_eq!(iter.next(), Some(&0));
281+
/// assert_eq!(iter.next(), Some(&2));
282+
/// assert_eq!(iter.next(), Some(&4));
283+
/// assert_eq!(iter.next(), None);
284+
/// ```
285+
#[inline]
286+
#[unstable(feature = "iterator_step_by",
287+
reason = "unstable replacement of Range::step_by",
288+
issue = "27741")]
289+
fn step_by(self, step: usize) -> StepBy<Self> where Self: Sized {
290+
assert!(step != 0);
291+
StepBy{iter: self, step: step - 1, first_take: true}
292+
}
293+
261294
/// Takes two iterators and creates a new iterator over both in sequence.
262295
///
263296
/// `chain()` will return a new iterator which will first iterate over

src/libcore/iter/mod.rs

+36-1
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ pub use self::iterator::Iterator;
313313
pub use self::range::Step;
314314
#[unstable(feature = "step_by", reason = "recent addition",
315315
issue = "27741")]
316-
pub use self::range::StepBy;
316+
pub use self::range::StepBy as DeprecatedStepBy;
317317

318318
#[stable(feature = "rust1", since = "1.0.0")]
319319
pub use self::sources::{Repeat, repeat};
@@ -520,6 +520,41 @@ impl<I> Iterator for Cycle<I> where I: Clone + Iterator {
520520
#[unstable(feature = "fused", issue = "35602")]
521521
impl<I> FusedIterator for Cycle<I> where I: Clone + Iterator {}
522522

523+
/// An iterator that steps by n elements every iteration.
524+
///
525+
/// This `struct` is created by the [`step_by`] method on [`Iterator`]. See
526+
/// its documentation for more.
527+
///
528+
/// [`step_by`]: trait.Iterator.html#method.step_by
529+
/// [`Iterator`]: trait.Iterator.html
530+
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
531+
#[unstable(feature = "iterator_step_by",
532+
reason = "unstable replacement of Range::step_by",
533+
issue = "27741")]
534+
#[derive(Clone, Debug)]
535+
pub struct StepBy<I> {
536+
iter: I,
537+
step: usize,
538+
first_take: bool,
539+
}
540+
541+
#[unstable(feature = "iterator_step_by",
542+
reason = "unstable replacement of Range::step_by",
543+
issue = "27741")]
544+
impl<I> Iterator for StepBy<I> where I: Iterator {
545+
type Item = I::Item;
546+
547+
#[inline]
548+
fn next(&mut self) -> Option<Self::Item> {
549+
if self.first_take {
550+
self.first_take = false;
551+
self.iter.next()
552+
} else {
553+
self.iter.nth(self.step)
554+
}
555+
}
556+
}
557+
523558
/// An iterator that strings two iterators together.
524559
///
525560
/// This `struct` is created by the [`chain`] method on [`Iterator`]. See its

src/libcore/tests/iter.rs

+28-1
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,33 @@ fn test_iterator_chain_find() {
144144
assert_eq!(iter.next(), None);
145145
}
146146

147+
#[test]
148+
fn test_iterator_step_by() {
149+
// Identity
150+
// Replace with (0..).step_by(1) after Range::step_by gets removed
151+
let mut it = Iterator::step_by((0..), 1).take(3);
152+
assert_eq!(it.next(), Some(0));
153+
assert_eq!(it.next(), Some(1));
154+
assert_eq!(it.next(), Some(2));
155+
assert_eq!(it.next(), None);
156+
157+
// Replace with (0..).step_by(3) after Range::step_by gets removed
158+
let mut it = Iterator::step_by((0..), 3).take(4);
159+
assert_eq!(it.next(), Some(0));
160+
assert_eq!(it.next(), Some(3));
161+
assert_eq!(it.next(), Some(6));
162+
assert_eq!(it.next(), Some(9));
163+
assert_eq!(it.next(), None);
164+
}
165+
166+
#[test]
167+
#[should_panic]
168+
fn test_iterator_step_by_zero() {
169+
// Replace with (0..).step_by(0) after Range::step_by gets removed
170+
let mut it = Iterator::step_by((0..), 0);
171+
it.next();
172+
}
173+
147174
#[test]
148175
fn test_filter_map() {
149176
let it = (0..).step_by(1).take(10)
@@ -1119,4 +1146,4 @@ fn test_step_replace_no_between() {
11191146
let y = x.replace_one();
11201147
assert_eq!(x, 1);
11211148
assert_eq!(y, 5);
1122-
}
1149+
}

src/libcore/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#![feature(fixed_size_array)]
2121
#![feature(flt2dec)]
2222
#![feature(fmt_internals)]
23+
#![feature(iterator_step_by)]
2324
#![feature(i128_type)]
2425
#![feature(iter_rfind)]
2526
#![feature(libc)]

0 commit comments

Comments
 (0)