about summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/iter/mod.rs2
-rw-r--r--src/libcore/iter/sources.rs115
-rw-r--r--src/libcore/lib.rs1
-rw-r--r--src/libcore/tests/iter.rs45
-rw-r--r--src/libcore/tests/lib.rs1
5 files changed, 164 insertions, 0 deletions
diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs
index 29b62c901f3..d929d1d65a9 100644
--- a/src/libcore/iter/mod.rs
+++ b/src/libcore/iter/mod.rs
@@ -333,6 +333,8 @@ pub use self::range::Step;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::sources::{Repeat, repeat};
+#[unstable(feature = "iterator_repeat_with", issue = "48169")]
+pub use self::sources::{RepeatWith, repeat_with};
 #[stable(feature = "iter_empty", since = "1.2.0")]
 pub use self::sources::{Empty, empty};
 #[stable(feature = "iter_once", since = "1.2.0")]
diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs
index b05a893e661..3e9d799c089 100644
--- a/src/libcore/iter/sources.rs
+++ b/src/libcore/iter/sources.rs
@@ -57,6 +57,12 @@ unsafe impl<A: Clone> TrustedLen for Repeat<A> {}
 ///
 /// [`take`]: trait.Iterator.html#method.take
 ///
+/// If the element type of the iterator you need does not implement `Clone`,
+/// or if you do not want to keep the repeated element in memory, you can
+/// instead use the [`repeat_with`] function.
+///
+/// [`repeat_with`]: fn.repeat_with.html
+///
 /// # Examples
 ///
 /// Basic usage:
@@ -99,6 +105,115 @@ pub fn repeat<T: Clone>(elt: T) -> Repeat<T> {
     Repeat{element: elt}
 }
 
+/// An iterator that repeats elements of type `A` endlessly by
+/// applying the provided closure `F: FnMut() -> A`.
+///
+/// This `struct` is created by the [`repeat_with`] function.
+/// See its documentation for more.
+///
+/// [`repeat_with`]: fn.repeat_with.html
+#[derive(Copy, Clone, Debug)]
+#[unstable(feature = "iterator_repeat_with", issue = "48169")]
+pub struct RepeatWith<F> {
+    repeater: F
+}
+
+#[unstable(feature = "iterator_repeat_with", issue = "48169")]
+impl<A, F: FnMut() -> A> Iterator for RepeatWith<F> {
+    type Item = A;
+
+    #[inline]
+    fn next(&mut self) -> Option<A> { Some((self.repeater)()) }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) { (usize::MAX, None) }
+}
+
+#[unstable(feature = "iterator_repeat_with", issue = "48169")]
+impl<A, F: FnMut() -> A> DoubleEndedIterator for RepeatWith<F> {
+    #[inline]
+    fn next_back(&mut self) -> Option<A> { self.next() }
+}
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<A, F: FnMut() -> A> FusedIterator for RepeatWith<F> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<A, F: FnMut() -> A> TrustedLen for RepeatWith<F> {}
+
+/// Creates a new iterator that repeats elements of type `A` endlessly by
+/// applying the provided closure, the repeater, `F: FnMut() -> A`.
+///
+/// The `repeat_with()` function calls the repeater over and over and over and
+/// over and over and 🔁.
+///
+/// Infinite iterators like `repeat_with()` are often used with adapters like
+/// [`take`], in order to make them finite.
+///
+/// [`take`]: trait.Iterator.html#method.take
+///
+/// If the element type of the iterator you need implements `Clone`, and
+/// it is OK to keep the source element in memory, you should instead use
+/// the [`repeat`] function.
+///
+/// [`repeat`]: fn.repeat.html
+///
+/// An iterator produced by `repeat_with()` is a `DoubleEndedIterator`.
+/// It is important to not that reversing `repeat_with(f)` will produce
+/// the exact same sequence as the non-reversed iterator. In other words,
+/// `repeat_with(f).rev().collect::<Vec<_>>()` is equivalent to
+/// `repeat_with(f).collect::<Vec<_>>()`.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// #![feature(iterator_repeat_with)]
+///
+/// use std::iter;
+///
+/// // let's assume we have some value of a type that is not `Clone`
+/// // or which don't want to have in memory just yet because it is expensive:
+/// #[derive(PartialEq, Debug)]
+/// struct Expensive;
+///
+/// // a particular value forever:
+/// let mut things = iter::repeat_with(|| Expensive);
+///
+/// assert_eq!(Some(Expensive), things.next());
+/// assert_eq!(Some(Expensive), things.next());
+/// assert_eq!(Some(Expensive), things.next());
+/// assert_eq!(Some(Expensive), things.next());
+/// assert_eq!(Some(Expensive), things.next());
+/// ```
+///
+/// Using mutation and going finite:
+///
+/// ```rust
+/// #![feature(iterator_repeat_with)]
+///
+/// use std::iter;
+///
+/// // From the zeroth to the third power of two:
+/// let mut curr = 1;
+/// let mut pow2 = iter::repeat_with(|| { let tmp = curr; curr *= 2; tmp })
+///                     .take(4);
+///
+/// assert_eq!(Some(1), pow2.next());
+/// assert_eq!(Some(2), pow2.next());
+/// assert_eq!(Some(4), pow2.next());
+/// assert_eq!(Some(8), pow2.next());
+///
+/// // ... and now we're done
+/// assert_eq!(None, pow2.next());
+/// ```
+#[inline]
+#[unstable(feature = "iterator_repeat_with", issue = "48169")]
+pub fn repeat_with<A, F: FnMut() -> A>(repeater: F) -> RepeatWith<F> {
+    RepeatWith { repeater }
+}
+
 /// An iterator that yields nothing.
 ///
 /// This `struct` is created by the [`empty`] function. See its documentation for more.
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 59a296c2a76..447e144bf0f 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -92,6 +92,7 @@
 #![feature(unwind_attributes)]
 #![feature(doc_spotlight)]
 #![feature(rustc_const_unstable)]
+#![feature(iterator_repeat_with)]
 
 #[prelude_import]
 #[allow(unused)]
diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs
index d8c9dcd8664..f91c919d744 100644
--- a/src/libcore/tests/iter.rs
+++ b/src/libcore/tests/iter.rs
@@ -1593,6 +1593,51 @@ fn test_repeat_take_collect() {
 }
 
 #[test]
+fn test_repeat_with() {
+    #[derive(PartialEq, Debug)]
+    struct NotClone(usize);
+    let mut it = repeat_with(|| NotClone(42));
+    assert_eq!(it.next(), Some(NotClone(42)));
+    assert_eq!(it.next(), Some(NotClone(42)));
+    assert_eq!(it.next(), Some(NotClone(42)));
+    assert_eq!(repeat_with(|| NotClone(42)).size_hint(), (usize::MAX, None));
+}
+
+#[test]
+fn test_repeat_with_rev() {
+    let mut curr = 1;
+    let mut pow2 = repeat_with(|| { let tmp = curr; curr *= 2; tmp })
+                    .rev().take(4);
+    assert_eq!(pow2.next(), Some(1));
+    assert_eq!(pow2.next(), Some(2));
+    assert_eq!(pow2.next(), Some(4));
+    assert_eq!(pow2.next(), Some(8));
+    assert_eq!(pow2.next(), None);
+}
+
+#[test]
+fn test_repeat_with_take() {
+    let mut it = repeat_with(|| 42).take(3);
+    assert_eq!(it.next(), Some(42));
+    assert_eq!(it.next(), Some(42));
+    assert_eq!(it.next(), Some(42));
+    assert_eq!(it.next(), None);
+    is_trusted_len(repeat_with(|| 42).take(3));
+    assert_eq!(repeat_with(|| 42).take(3).size_hint(), (3, Some(3)));
+    assert_eq!(repeat_with(|| 42).take(0).size_hint(), (0, Some(0)));
+    assert_eq!(repeat_with(|| 42).take(usize::MAX).size_hint(),
+               (usize::MAX, Some(usize::MAX)));
+}
+
+#[test]
+fn test_repeat_with_take_collect() {
+    let mut curr = 1;
+    let v: Vec<_> = repeat_with(|| { let tmp = curr; curr *= 2; tmp })
+                      .take(5).collect();
+    assert_eq!(v, vec![1, 2, 4, 8, 16]);
+}
+
+#[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 0d55e6eeeb1..3e901a9d442 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -27,6 +27,7 @@
 #![feature(iterator_try_fold)]
 #![feature(iter_rfind)]
 #![feature(iter_rfold)]
+#![feature(iterator_repeat_with)]
 #![feature(nonzero)]
 #![feature(pattern)]
 #![feature(range_is_empty)]