diff --git a/src/doc/unstable-book/src/library-features/iterator-step-by.md b/src/doc/unstable-book/src/library-features/iterator-step-by.md new file mode 100644 index 00000000000..8467cb68862 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/iterator-step-by.md @@ -0,0 +1,7 @@ +# `iterator_step_by` + +The tracking issue for this feature is: [#27741] + +[#27741]: https://github.com/rust-lang/rust/issues/27741 + +------------------------ diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 67b97afb976..77cbdb98c83 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -11,7 +11,7 @@ use cmp::Ordering; use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, FlatMap, Fuse}; -use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, Take, TakeWhile, Rev}; +use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile, Rev}; use super::{Zip, Sum, Product}; use super::{ChainState, FromIterator, ZipImpl}; @@ -258,6 +258,39 @@ fn nth(&mut self, mut n: usize) -> Option { None } + /// Creates an iterator starting at the same point, but stepping by + /// the given amount at each iteration. + /// + /// Note that it will always return the first element of the range, + /// regardless of the step given. + /// + /// # Panics + /// + /// The method will panic if the given step is `0`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(iterator_step_by)] + /// let a = [0, 1, 2, 3, 4, 5]; + /// let mut iter = a.into_iter().step_by(2); + /// + /// assert_eq!(iter.next(), Some(&0)); + /// assert_eq!(iter.next(), Some(&2)); + /// assert_eq!(iter.next(), Some(&4)); + /// assert_eq!(iter.next(), None); + /// ``` + #[inline] + #[unstable(feature = "iterator_step_by", + reason = "unstable replacement of Range::step_by", + issue = "27741")] + fn step_by(self, step: usize) -> StepBy where Self: Sized { + assert!(step != 0); + StepBy{iter: self, step: step - 1, first_take: true} + } + /// Takes two iterators and creates a new iterator over both in sequence. /// /// `chain()` will return a new iterator which will first iterate over diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 273f9d0e6f6..420ff0f7119 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -313,7 +313,7 @@ pub use self::range::Step; #[unstable(feature = "step_by", reason = "recent addition", issue = "27741")] -pub use self::range::StepBy; +pub use self::range::StepBy as DeprecatedStepBy; #[stable(feature = "rust1", since = "1.0.0")] pub use self::sources::{Repeat, repeat}; @@ -520,6 +520,41 @@ fn size_hint(&self) -> (usize, Option) { #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for Cycle where I: Clone + Iterator {} +/// An iterator that steps by n elements every iteration. +/// +/// This `struct` is created by the [`step_by`] method on [`Iterator`]. See +/// its documentation for more. +/// +/// [`step_by`]: trait.Iterator.html#method.step_by +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +#[unstable(feature = "iterator_step_by", + reason = "unstable replacement of Range::step_by", + issue = "27741")] +#[derive(Clone, Debug)] +pub struct StepBy { + iter: I, + step: usize, + first_take: bool, +} + +#[unstable(feature = "iterator_step_by", + reason = "unstable replacement of Range::step_by", + issue = "27741")] +impl Iterator for StepBy where I: Iterator { + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + if self.first_take { + self.first_take = false; + self.iter.next() + } else { + self.iter.nth(self.step) + } + } +} + /// An iterator that strings two iterators together. /// /// This `struct` is created by the [`chain`] method on [`Iterator`]. See its diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 001fa304cd0..ad91ba9be58 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -144,6 +144,33 @@ fn test_iterator_chain_find() { assert_eq!(iter.next(), None); } +#[test] +fn test_iterator_step_by() { + // Identity + // Replace with (0..).step_by(1) after Range::step_by gets removed + let mut it = Iterator::step_by((0..), 1).take(3); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next(), Some(1)); + assert_eq!(it.next(), Some(2)); + assert_eq!(it.next(), None); + + // Replace with (0..).step_by(3) after Range::step_by gets removed + let mut it = Iterator::step_by((0..), 3).take(4); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next(), Some(3)); + assert_eq!(it.next(), Some(6)); + assert_eq!(it.next(), Some(9)); + assert_eq!(it.next(), None); +} + +#[test] +#[should_panic] +fn test_iterator_step_by_zero() { + // Replace with (0..).step_by(0) after Range::step_by gets removed + let mut it = Iterator::step_by((0..), 0); + it.next(); +} + #[test] fn test_filter_map() { let it = (0..).step_by(1).take(10) @@ -1119,4 +1146,4 @@ fn test_step_replace_no_between() { let y = x.replace_one(); assert_eq!(x, 1); assert_eq!(y, 5); -} \ No newline at end of file +} diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index f0c46a6f194..c52155ead4f 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -20,6 +20,7 @@ #![feature(fixed_size_array)] #![feature(flt2dec)] #![feature(fmt_internals)] +#![feature(iterator_step_by)] #![feature(i128_type)] #![feature(iter_rfind)] #![feature(libc)]