From 641c4909e4de0334c83372b4795388d98cfd257a Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 15 Nov 2018 14:23:20 +0100 Subject: [PATCH] Add std::iter::successors --- src/libcore/iter/mod.rs | 2 +- src/libcore/iter/sources.rs | 76 +++++++++++++++++++++++++++++++++++++ src/libcore/tests/iter.rs | 11 ++++++ src/libcore/tests/lib.rs | 1 + 4 files changed, 89 insertions(+), 1 deletion(-) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 5ac8b2d28956a..5f45cd927b897 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 93c64c748c97b..7f55965239222 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -471,3 +471,79 @@ impl fmt::Debug for Unfold { .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` 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::>(), &[1, 10, 100, 1_000, 10_000]); +/// ``` +#[unstable(feature = "iter_unfold", issue = /* FIXME */ "0")] +pub fn successors(first: Option, succ: F) -> Successors + where F: FnMut(&T) -> Option +{ + // If this function returned `impl Iterator` + // it could be based on `unfold` and not need a dedicated type. + // However having a named `Successors` 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 { + next: Option, + succ: F, +} + +#[unstable(feature = "iter_unfold", issue = /* FIXME */ "0")] +impl Iterator for Successors + where F: FnMut(&T) -> Option +{ + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + self.next.take().map(|item| { + self.next = (self.succ)(&item); + item + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.next.is_some() { + (1, None) + } else { + (0, Some(0)) + } + } +} + +#[unstable(feature = "iter_unfold", issue = /* FIXME */ "0")] +impl FusedIterator for Successors + where F: FnMut(&T) -> Option +{} + +#[unstable(feature = "iter_unfold", issue = /* FIXME */ "0")] +impl fmt::Debug for Successors { + 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 ec09071b3d0f0..495483db5551c 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1759,6 +1759,17 @@ fn test_repeat_with_take_collect() { assert_eq!(v, vec![1, 2, 4, 8, 16]); } +#[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::>(), &[1, 10, 100, 1_000, 10_000]); + assert_eq!(powers_of_10.next(), None); + + let mut empty = successors(None::, |_| unimplemented!()); + assert_eq!(empty.next(), None); + assert_eq!(empty.next(), None); +} + #[test] fn test_fuse() { let mut it = 0..3; diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 5ac8991226898..7d62b4fa90f20 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)]