From 0f789aad2b3cfc0b0925b726295200267130e69d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 08:05:46 +0100 Subject: [PATCH 1/9] add core::iter::repeat_with --- src/libcore/iter/sources.rs | 104 ++++++++++++++++++++++++++++++++++++ src/libcore/tests/iter.rs | 44 +++++++++++++++ 2 files changed, 148 insertions(+) diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index b05a893e661..980f3fc7443 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -57,6 +57,12 @@ unsafe impl TrustedLen for Repeat {} /// /// [`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,104 @@ pub fn repeat(elt: T) -> Repeat { 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 +#[unstable(feature = "iterator_repeat_with", issue = "0")] +pub struct RepeatWith { + repeater: F +} + +#[unstable(feature = "iterator_repeat_with", issue = "0")] +impl A> Iterator for RepeatWith { + type Item = A; + + #[inline] + fn next(&mut self) -> Option { Some((self.repeater)()) } + + #[inline] + fn size_hint(&self) -> (usize, Option) { (usize::MAX, None) } +} + +#[unstable(feature = "iterator_repeat_with", issue = "0")] +impl A> DoubleEndedIterator for RepeatWith { + #[inline] + fn next_back(&mut self) -> Option { self.next() } +} + +#[unstable(feature = "fused", issue = "35602")] +impl A> FusedIterator for RepeatWith {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl A> TrustedLen for RepeatWith {} + +/// Creates a new 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 +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// 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 +/// 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 = "0")] +pub fn repeat_with A>(repeater: F) -> RepeatWith { + 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/tests/iter.rs b/src/libcore/tests/iter.rs index b2a5243d5e6..ca5318d198e 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1549,6 +1549,50 @@ fn test_repeat_take_collect() { assert_eq!(v, vec![42, 42, 42]); } +#[test] +fn test_repeat_with() { + 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!(it.next(), Some(1)); + assert_eq!(it.next(), Some(2)); + assert_eq!(it.next(), Some(4)); + assert_eq!(it.next(), Some(8)); + assert_eq!(it.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_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; From c4099ca4b11acb9949ef0da804a819b4ddfa24a2 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 08:25:39 +0100 Subject: [PATCH 2/9] core::iter::repeat_with: general fixes --- src/libcore/iter/mod.rs | 2 ++ src/libcore/iter/sources.rs | 4 ++++ src/libcore/lib.rs | 1 + 3 files changed, 7 insertions(+) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 29b62c901f3..ac3fb5a57dd 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 = "0")] +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 980f3fc7443..2cf90fd079e 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -162,6 +162,8 @@ unsafe impl A> TrustedLen for RepeatWith {} /// Basic usage: /// /// ``` +/// #![feature("iterator_repeat_with")] +/// /// use std::iter; /// /// // let's assume we have some value of a type that is not `Clone` @@ -182,6 +184,8 @@ unsafe impl A> TrustedLen for RepeatWith {} /// Using mutation and going finite: /// /// ```rust +/// #![feature("iterator_repeat_with")] +/// /// use std::iter; /// /// // From the zeroth to the third power of two: 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)] From 1af9ee1350cc69e7c1873d26637064824d07c2b8 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 08:35:12 +0100 Subject: [PATCH 3/9] core::iter::repeat_with: derive Copy, Clone, Debug --- src/libcore/iter/sources.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index 2cf90fd079e..d77e8d4db04 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -112,6 +112,7 @@ pub fn repeat(elt: T) -> Repeat { /// See its documentation for more. /// /// [`repeat_with`]: fn.repeat_with.html +#[derive(Copy, Clone, Debug)] #[unstable(feature = "iterator_repeat_with", issue = "0")] pub struct RepeatWith { repeater: F From f025eff21d1832fcd3941ae847fec2aaf23d3b0b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 09:13:47 +0100 Subject: [PATCH 4/9] core::iter::repeat_with: fix tests --- src/libcore/tests/iter.rs | 3 ++- src/libcore/tests/lib.rs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index ca5318d198e..f42970685f5 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1551,6 +1551,7 @@ 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))); @@ -1586,7 +1587,7 @@ fn test_repeat_with_take() { } #[test] -fn test_repeat_take_collect() { +fn test_repeat_with_take_collect() { let mut curr = 1; let v: Vec<_> = repeat_with(|| { let tmp = curr; curr *= 2; tmp }) .take(5).collect(); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 9e90313bc0e..2b9fae88bf4 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(raw)] From 55c669c4d9f7b245e2c237dc2b5d0390afe2620d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 09:15:13 +0100 Subject: [PATCH 5/9] core::iter::repeat_with: fix tests some more --- src/libcore/tests/iter.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index f42970685f5..4c33c8440a3 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1565,11 +1565,11 @@ 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!(it.next(), Some(1)); - assert_eq!(it.next(), Some(2)); - assert_eq!(it.next(), Some(4)); - assert_eq!(it.next(), Some(8)); - assert_eq!(it.next(), None); + 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] From efa332038c74931738c44f48622c2a99b5a36cf0 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 09:18:22 +0100 Subject: [PATCH 6/9] core::iter::repeat_with: fix doc tests --- src/libcore/iter/sources.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index d77e8d4db04..b364292f57e 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -163,7 +163,7 @@ unsafe impl A> TrustedLen for RepeatWith {} /// Basic usage: /// /// ``` -/// #![feature("iterator_repeat_with")] +/// #![feature(iterator_repeat_with)] /// /// use std::iter; /// @@ -185,7 +185,7 @@ unsafe impl A> TrustedLen for RepeatWith {} /// Using mutation and going finite: /// /// ```rust -/// #![feature("iterator_repeat_with")] +/// #![feature(iterator_repeat_with)] /// /// use std::iter; /// From 9cee79a7ff09851109f621bd4510909f5740ae28 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 18:03:56 +0100 Subject: [PATCH 7/9] core::iter::repeat_with: document DoubleEndedIterator behavior --- src/libcore/iter/sources.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index b364292f57e..abf2befa9cd 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -158,6 +158,12 @@ unsafe impl A> TrustedLen for RepeatWith {} /// /// [`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::>()` is equivalent to +/// `repeat_with(f).collect::>()`. +/// /// # Examples /// /// Basic usage: From 91a4b9044d7f104516984d1076b04b99cef7a6b9 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 21:47:59 +0100 Subject: [PATCH 8/9] core::iter::repeat_with: tracking issue is #48169 --- src/libcore/iter/mod.rs | 2 +- src/libcore/iter/sources.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index ac3fb5a57dd..d929d1d65a9 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -333,7 +333,7 @@ pub use self::range::Step; #[stable(feature = "rust1", since = "1.0.0")] pub use self::sources::{Repeat, repeat}; -#[unstable(feature = "iterator_repeat_with", issue = "0")] +#[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}; diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index abf2befa9cd..eb8a22709b0 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -113,12 +113,12 @@ pub fn repeat(elt: T) -> Repeat { /// /// [`repeat_with`]: fn.repeat_with.html #[derive(Copy, Clone, Debug)] -#[unstable(feature = "iterator_repeat_with", issue = "0")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] pub struct RepeatWith { repeater: F } -#[unstable(feature = "iterator_repeat_with", issue = "0")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] impl A> Iterator for RepeatWith { type Item = A; @@ -129,7 +129,7 @@ impl A> Iterator for RepeatWith { fn size_hint(&self) -> (usize, Option) { (usize::MAX, None) } } -#[unstable(feature = "iterator_repeat_with", issue = "0")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] impl A> DoubleEndedIterator for RepeatWith { #[inline] fn next_back(&mut self) -> Option { self.next() } @@ -209,7 +209,7 @@ unsafe impl A> TrustedLen for RepeatWith {} /// assert_eq!(None, pow2.next()); /// ``` #[inline] -#[unstable(feature = "iterator_repeat_with", issue = "0")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] pub fn repeat_with A>(repeater: F) -> RepeatWith { RepeatWith { repeater } } From db13296b6fd6b68ab06055bdcb9a22078b11de6a Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 13 Feb 2018 06:20:17 +0100 Subject: [PATCH 9/9] core::iter::repeat_with: fix missing word, see @Pazzaz's review --- src/libcore/iter/sources.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index eb8a22709b0..3e9d799c089 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -141,7 +141,7 @@ impl A> FusedIterator for RepeatWith {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl A> TrustedLen for RepeatWith {} -/// Creates a new that repeats elements of type `A` endlessly by +/// 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