diff options
| author | Simon Sapin <simon.sapin@exyr.org> | 2018-11-15 14:23:20 +0100 |
|---|---|---|
| committer | Simon Sapin <simon.sapin@exyr.org> | 2018-11-20 18:22:40 +0100 |
| commit | 641c4909e4de0334c83372b4795388d98cfd257a (patch) | |
| tree | 01dd283299e54bf55d53ed02ccb7e24e5cb63866 | |
| parent | 22228186c0d373774a117375c2c264024bfd4b48 (diff) | |
| download | rust-641c4909e4de0334c83372b4795388d98cfd257a.tar.gz rust-641c4909e4de0334c83372b4795388d98cfd257a.zip | |
Add std::iter::successors
| -rw-r--r-- | src/libcore/iter/mod.rs | 2 | ||||
| -rw-r--r-- | src/libcore/iter/sources.rs | 76 | ||||
| -rw-r--r-- | src/libcore/tests/iter.rs | 11 | ||||
| -rw-r--r-- | src/libcore/tests/lib.rs | 1 |
4 files changed, 89 insertions, 1 deletions
diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 5ac8b2d2895..5f45cd927b8 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -340,7 +340,7 @@ pub use self::sources::{Empty, empty}; #[stable(feature = "iter_once", since = "1.2.0")] pub use self::sources::{Once, once}; #[unstable(feature = "iter_unfold", issue = /* FIXME */ "0")] -pub use self::sources::{Unfold, unfold}; +pub use self::sources::{Unfold, unfold, Successors, successors}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::traits::{FromIterator, IntoIterator, DoubleEndedIterator, Extend}; diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index 93c64c748c9..7f559652392 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -471,3 +471,79 @@ impl<St: fmt::Debug, F> fmt::Debug for Unfold<St, F> { .finish() } } + +/// Creates a new iterator where each successive item is computed based on the preceding one. +/// +/// The iterator starts with the given first item (if any) +/// and calls the given `FnMut(&T) -> Option<T>` closure to compute each item’s successor. +/// +/// ``` +/// #![feature(iter_unfold)] +/// use std::iter::successors; +/// +/// let powers_of_10 = successors(Some(1_u16), |n| n.checked_mul(10)); +/// assert_eq!(powers_of_10.collect::<Vec<_>>(), &[1, 10, 100, 1_000, 10_000]); +/// ``` +#[unstable(feature = "iter_unfold", issue = /* FIXME */ "0")] +pub fn successors<T, F>(first: Option<T>, succ: F) -> Successors<T, F> + where F: FnMut(&T) -> Option<T> +{ + // If this function returned `impl Iterator<Item=T>` + // it could be based on `unfold` and not need a dedicated type. + // However having a named `Successors<T, F>` type allows it to be `Clone` when `T` and `F` are. + Successors { + next: first, + succ, + } +} + +/// An new iterator where each successive item is computed based on the preceding one. +/// +/// This `struct` is created by the [`successors`] function. +/// See its documentation for more. +/// +/// [`successors`]: fn.successors.html +#[derive(Clone)] +#[unstable(feature = "iter_unfold", issue = /* FIXME */ "0")] +pub struct Successors<T, F> { + next: Option<T>, + succ: F, +} + +#[unstable(feature = "iter_unfold", issue = /* FIXME */ "0")] +impl<T, F> Iterator for Successors<T, F> + where F: FnMut(&T) -> Option<T> +{ + type Item = T; + + #[inline] + fn next(&mut self) -> Option<Self::Item> { + self.next.take().map(|item| { + self.next = (self.succ)(&item); + item + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + if self.next.is_some() { + (1, None) + } else { + (0, Some(0)) + } + } +} + +#[unstable(feature = "iter_unfold", issue = /* FIXME */ "0")] +impl<T, F> FusedIterator for Successors<T, F> + where F: FnMut(&T) -> Option<T> +{} + +#[unstable(feature = "iter_unfold", issue = /* FIXME */ "0")] +impl<T: fmt::Debug, F> fmt::Debug for Successors<T, F> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Successors") + .field("next", &self.next) + .finish() + } +} diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index ec09071b3d0..495483db555 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1760,6 +1760,17 @@ fn test_repeat_with_take_collect() { } #[test] +fn test_successors() { + let mut powers_of_10 = successors(Some(1_u16), |n| n.checked_mul(10)); + assert_eq!(powers_of_10.by_ref().collect::<Vec<_>>(), &[1, 10, 100, 1_000, 10_000]); + assert_eq!(powers_of_10.next(), None); + + let mut empty = successors(None::<u32>, |_| unimplemented!()); + assert_eq!(empty.next(), None); + assert_eq!(empty.next(), None); +} + +#[test] fn test_fuse() { let mut it = 0..3; assert_eq!(it.len(), 3); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 5ac89912268..7d62b4fa90f 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -19,6 +19,7 @@ #![feature(flt2dec)] #![feature(fmt_internals)] #![feature(hashmap_internals)] +#![feature(iter_unfold)] #![feature(pattern)] #![feature(range_is_empty)] #![feature(raw)] |
