diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 509068843d193..62e1f9fcb640c 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -112,10 +112,10 @@ //! //! // next() is the only required method //! fn next(&mut self) -> Option<usize> { -//! // increment our count. This is why we started at zero. +//! // Increment our count. This is why we started at zero. //! self.count += 1; //! -//! // check to see if we've finished counting or not. +//! // Check to see if we've finished counting or not. //! if self.count < 6 { //! Some(self.count) //! } else { @@ -339,6 +339,8 @@ pub use self::sources::{RepeatWith, repeat_with}; 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 = "55977")] +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 7fa3a4bcce7bb..f6a4a7a6fa80a 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -386,3 +386,164 @@ impl<T> FusedIterator for Once<T> {} pub fn once<T>(value: T) -> Once<T> { Once { inner: Some(value).into_iter() } } + +/// Creates a new iterator where each iteration calls the provided closure +/// `F: FnMut(&mut St) -> Option<T>`. +/// +/// This allows creating a custom iterator with any behavior +/// without using the more verbose syntax of creating a dedicated type +/// and implementing the `Iterator` trait for it. +/// +/// In addition to its captures and environment, +/// the closure is given a mutable reference to some state +/// that is preserved across iterations. +/// That state starts as the given `initial_state` value. +/// +/// Note that the `Unfold` iterator doesn’t make assumptions about the behavior of the closure, +/// and therefore conservatively does not implement [`FusedIterator`], +/// or override [`Iterator::size_hint`] from its default `(0, None)`. +/// +/// [`FusedIterator`]: trait.FusedIterator.html +/// [`Iterator::size_hint`]: trait.Iterator.html#method.size_hint +/// +/// # Examples +/// +/// Let’s re-implement the counter iterator from [module-level documentation]: +/// +/// [module-level documentation]: index.html +/// +/// ``` +/// #![feature(iter_unfold)] +/// let counter = std::iter::unfold(0, |count| { +/// // Increment our count. This is why we started at zero. +/// *count += 1; +/// +/// // Check to see if we've finished counting or not. +/// if *count < 6 { +/// Some(*count) +/// } else { +/// None +/// } +/// }); +/// assert_eq!(counter.collect::<Vec<_>>(), &[1, 2, 3, 4, 5]); +/// ``` +#[inline] +#[unstable(feature = "iter_unfold", issue = "55977")] +pub fn unfold<St, T, F>(initial_state: St, f: F) -> Unfold<St, F> + where F: FnMut(&mut St) -> Option<T> +{ + Unfold { + state: initial_state, + f, + } +} + +/// An iterator where each iteration calls the provided closure `F: FnMut(&mut St) -> Option<T>`. +/// +/// This `struct` is created by the [`unfold`] function. +/// See its documentation for more. +/// +/// [`unfold`]: fn.unfold.html +#[derive(Clone)] +#[unstable(feature = "iter_unfold", issue = "55977")] +pub struct Unfold<St, F> { + state: St, + f: F, +} + +#[unstable(feature = "iter_unfold", issue = "55977")] +impl<St, T, F> Iterator for Unfold<St, F> + where F: FnMut(&mut St) -> Option<T> +{ + type Item = T; + + #[inline] + fn next(&mut self) -> Option<Self::Item> { + (self.f)(&mut self.state) + } +} + +#[unstable(feature = "iter_unfold", issue = "55977")] +impl<St: fmt::Debug, F> fmt::Debug for Unfold<St, F> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Unfold") + .field("state", &self.state) + .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 = "55977")] +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 = "55977")] +pub struct Successors<T, F> { + next: Option<T>, + succ: F, +} + +#[unstable(feature = "iter_unfold", issue = "55977")] +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 = "55977")] +impl<T, F> FusedIterator for Successors<T, F> + where F: FnMut(&T) -> Option<T> +{} + +#[unstable(feature = "iter_unfold", issue = "55977")] +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 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::<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; 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)]