Skip to content

Commit

Permalink
Add std::iter::successors
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonSapin committed Nov 20, 2018
1 parent 2222818 commit 641c490
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/libcore/iter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down
76 changes: 76 additions & 0 deletions src/libcore/iter/sources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}
11 changes: 11 additions & 0 deletions src/libcore/tests/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/libcore/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#![feature(flt2dec)]
#![feature(fmt_internals)]
#![feature(hashmap_internals)]
#![feature(iter_unfold)]
#![feature(pattern)]
#![feature(range_is_empty)]
#![feature(raw)]
Expand Down

0 comments on commit 641c490

Please sign in to comment.