about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSimon Sapin <simon.sapin@exyr.org>2018-11-15 14:23:20 +0100
committerSimon Sapin <simon.sapin@exyr.org>2018-11-20 18:22:40 +0100
commit641c4909e4de0334c83372b4795388d98cfd257a (patch)
tree01dd283299e54bf55d53ed02ccb7e24e5cb63866
parent22228186c0d373774a117375c2c264024bfd4b48 (diff)
downloadrust-641c4909e4de0334c83372b4795388d98cfd257a.tar.gz
rust-641c4909e4de0334c83372b4795388d98cfd257a.zip
Add std::iter::successors
-rw-r--r--src/libcore/iter/mod.rs2
-rw-r--r--src/libcore/iter/sources.rs76
-rw-r--r--src/libcore/tests/iter.rs11
-rw-r--r--src/libcore/tests/lib.rs1
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)]