From 04c74f46f0a0ecf886f1c12b51483d38690fac22 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Sun, 13 Jan 2019 11:16:14 +0100 Subject: [PATCH 1/6] Add core::iter::once_with --- src/libcore/iter/mod.rs | 2 + src/libcore/iter/sources.rs | 108 ++++++++++++++++++++++++++++++++++++ src/libcore/lib.rs | 1 + src/libcore/tests/iter.rs | 17 ++++++ src/libcore/tests/lib.rs | 1 + 5 files changed, 129 insertions(+) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 03369d6c8f3fd..f647a61a584c6 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -329,6 +329,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_once_with", issue = "0")] +pub use self::sources::{OnceWith, once_with}; #[unstable(feature = "iter_unfold", issue = "55977")] pub use self::sources::{Unfold, unfold, Successors, successors}; diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index 2a39089a8a229..d183fa3a7c233 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -377,6 +377,114 @@ pub fn once(value: T) -> Once { Once { inner: Some(value).into_iter() } } +/// An iterator that repeats elements of type `A` endlessly by +/// applying the provided closure `F: FnMut() -> A`. +/// +/// This `struct` is created by the [`once_with`] function. +/// See its documentation for more. +/// +/// [`once_with`]: fn.once_with.html +#[derive(Copy, Clone, Debug)] +#[unstable(feature = "iter_once_with", issue = "0")] +pub struct OnceWith { + gen: Option, +} + +#[unstable(feature = "iter_once_with", issue = "0")] +impl A> Iterator for OnceWith { + type Item = A; + + #[inline] + fn next(&mut self) -> Option { + self.gen.take().map(|f| f()) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.gen.iter().size_hint() + } +} + +#[unstable(feature = "iter_once_with", issue = "0")] +impl A> DoubleEndedIterator for OnceWith { + fn next_back(&mut self) -> Option { + self.next() + } +} + +#[unstable(feature = "iter_once_with", issue = "0")] +impl A> ExactSizeIterator for OnceWith { + fn len(&self) -> usize { + self.gen.iter().len() + } +} + +#[unstable(feature = "iter_once_with", issue = "0")] +impl A> FusedIterator for OnceWith {} + +#[unstable(feature = "iter_once_with", issue = "0")] +unsafe impl A> TrustedLen for OnceWith {} + +/// Creates an iterator that lazily generates a value exactly once by invoking +/// the provided closure. +/// +/// This is commonly used to adapt a single value generator into a [`chain`] of +/// other kinds of iteration. Maybe you have an iterator that covers almost +/// everything, but you need an extra special case. Maybe you have a function +/// which works on iterators, but you only need to process one value. +/// +/// Unlike [`once`], this function will lazily generate the value on request. +/// +/// [`once`]: fn.once.html +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::iter; +/// +/// // one is the loneliest number +/// let mut one = iter::once_with(|| 1); +/// +/// assert_eq!(Some(1), one.next()); +/// +/// // just one, that's all we get +/// assert_eq!(None, one.next()); +/// ``` +/// +/// Chaining together with another iterator. Let's say that we want to iterate +/// over each file of the `.foo` directory, but also a configuration file, +/// `.foorc`: +/// +/// ```no_run +/// use std::iter; +/// use std::fs; +/// use std::path::PathBuf; +/// +/// let dirs = fs::read_dir(".foo").unwrap(); +/// +/// // we need to convert from an iterator of DirEntry-s to an iterator of +/// // PathBufs, so we use map +/// let dirs = dirs.map(|file| file.unwrap().path()); +/// +/// // now, our iterator just for our config file +/// let config = iter::once_with(|| PathBuf::from(".foorc")); +/// +/// // chain the two iterators together into one big iterator +/// let files = dirs.chain(config); +/// +/// // this will give us all of the files in .foo as well as .foorc +/// for f in files { +/// println!("{:?}", f); +/// } +/// ``` +#[inline] +#[unstable(feature = "iter_once_with", issue = "0")] +pub fn once_with A>(gen: F) -> OnceWith { + OnceWith { gen: Some(gen) } +} + /// Creates a new iterator where each iteration calls the provided closure /// `F: FnMut(&mut St) -> Option`. /// diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index a5f20d08e47be..598e7fd706a24 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -79,6 +79,7 @@ #![feature(extern_types)] #![feature(fundamental)] #![feature(intrinsics)] +#![feature(iter_once_with)] #![feature(lang_items)] #![feature(link_llvm_intrinsics)] #![feature(never_type)] diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index cf19851c17b35..b62f55b2cd003 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1906,6 +1906,23 @@ fn test_once() { assert_eq!(it.next(), None); } +#[test] +fn test_once_with() { + let mut count = 0; + let mut it = once_with(|| { + count += 1; + 42 + }); + + assert_eq!(count, 0); + assert_eq!(it.next(), Some(42)); + assert_eq!(count, 1); + assert_eq!(it.next(), None); + assert_eq!(count, 1); + assert_eq!(it.next(), None); + assert_eq!(count, 1); +} + #[test] fn test_empty() { let mut it = empty::(); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 72846daf16a6b..a9b8decfd0262 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -12,6 +12,7 @@ #![feature(hashmap_internals)] #![feature(iter_copied)] #![feature(iter_nth_back)] +#![feature(iter_once_with)] #![feature(iter_unfold)] #![feature(pattern)] #![feature(range_is_empty)] From 791573271415a1f07c274d676da4fe39963ac92c Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Sun, 13 Jan 2019 21:24:15 +0100 Subject: [PATCH 2/6] Fix intradoc link and update issue number --- src/libcore/iter/mod.rs | 2 +- src/libcore/iter/sources.rs | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index f647a61a584c6..cc173eff03e03 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -329,7 +329,7 @@ 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_once_with", issue = "0")] +#[unstable(feature = "iter_once_with", issue = "57581")] pub use self::sources::{OnceWith, once_with}; #[unstable(feature = "iter_unfold", issue = "55977")] pub use self::sources::{Unfold, unfold, Successors, successors}; diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index d183fa3a7c233..103d02da22f0e 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -385,12 +385,12 @@ pub fn once(value: T) -> Once { /// /// [`once_with`]: fn.once_with.html #[derive(Copy, Clone, Debug)] -#[unstable(feature = "iter_once_with", issue = "0")] +#[unstable(feature = "iter_once_with", issue = "57581")] pub struct OnceWith { gen: Option, } -#[unstable(feature = "iter_once_with", issue = "0")] +#[unstable(feature = "iter_once_with", issue = "57581")] impl A> Iterator for OnceWith { type Item = A; @@ -405,24 +405,24 @@ impl A> Iterator for OnceWith { } } -#[unstable(feature = "iter_once_with", issue = "0")] +#[unstable(feature = "iter_once_with", issue = "57581")] impl A> DoubleEndedIterator for OnceWith { fn next_back(&mut self) -> Option { self.next() } } -#[unstable(feature = "iter_once_with", issue = "0")] +#[unstable(feature = "iter_once_with", issue = "57581")] impl A> ExactSizeIterator for OnceWith { fn len(&self) -> usize { self.gen.iter().len() } } -#[unstable(feature = "iter_once_with", issue = "0")] +#[unstable(feature = "iter_once_with", issue = "57581")] impl A> FusedIterator for OnceWith {} -#[unstable(feature = "iter_once_with", issue = "0")] +#[unstable(feature = "iter_once_with", issue = "57581")] unsafe impl A> TrustedLen for OnceWith {} /// Creates an iterator that lazily generates a value exactly once by invoking @@ -436,6 +436,7 @@ unsafe impl A> TrustedLen for OnceWith {} /// Unlike [`once`], this function will lazily generate the value on request. /// /// [`once`]: fn.once.html +/// [`chain`]: trait.Iterator.html#method.chain /// /// # Examples /// @@ -480,7 +481,7 @@ unsafe impl A> TrustedLen for OnceWith {} /// } /// ``` #[inline] -#[unstable(feature = "iter_once_with", issue = "0")] +#[unstable(feature = "iter_once_with", issue = "57581")] pub fn once_with A>(gen: F) -> OnceWith { OnceWith { gen: Some(gen) } } From e449f3d62927887c01fe8b16bfcb4282d007fca2 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Mon, 14 Jan 2019 00:45:57 +0100 Subject: [PATCH 3/6] Fix failing test --- src/libcore/tests/iter.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index b62f55b2cd003..e2242ecc8cfbb 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1,3 +1,4 @@ +use core::cell::Cell; use core::iter::*; use core::{i8, i16, isize}; use core::usize; @@ -1908,19 +1909,19 @@ fn test_once() { #[test] fn test_once_with() { - let mut count = 0; + let mut count = Cell::new(0); let mut it = once_with(|| { - count += 1; + count.set(count.get() + 1); 42 }); - assert_eq!(count, 0); + assert_eq!(count.get(), 0); assert_eq!(it.next(), Some(42)); - assert_eq!(count, 1); + assert_eq!(count.get(), 1); assert_eq!(it.next(), None); - assert_eq!(count, 1); + assert_eq!(count.get(), 1); assert_eq!(it.next(), None); - assert_eq!(count, 1); + assert_eq!(count.get(), 1); } #[test] From 7c083a8fede186f2fc39a1d0e30ee156417473b0 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Mon, 14 Jan 2019 12:23:50 +0100 Subject: [PATCH 4/6] Remove unnecessary mut --- src/libcore/tests/iter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index e2242ecc8cfbb..3944bc749d029 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1909,7 +1909,7 @@ fn test_once() { #[test] fn test_once_with() { - let mut count = Cell::new(0); + let count = Cell::new(0); let mut it = once_with(|| { count.set(count.get() + 1); 42 From 84718c1999482f703ab7fc58a70ffc86269efac8 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Mon, 14 Jan 2019 17:20:41 +0100 Subject: [PATCH 5/6] Add feature(iter_once_with) --- src/libcore/iter/sources.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index 103d02da22f0e..59220b320918b 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -443,6 +443,8 @@ unsafe impl A> TrustedLen for OnceWith {} /// Basic usage: /// /// ``` +/// #![feature(iter_once_with)] +/// /// use std::iter; /// /// // one is the loneliest number From 3a1f0131a63a32a82f22b1c4ae04f8177730588f Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Mon, 14 Jan 2019 17:36:34 +0100 Subject: [PATCH 6/6] Add another feature(iter_once_with) --- src/libcore/iter/sources.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index 59220b320918b..2590fa6023a53 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -461,6 +461,8 @@ unsafe impl A> TrustedLen for OnceWith {} /// `.foorc`: /// /// ```no_run +/// #![feature(iter_once_with)] +/// /// use std::iter; /// use std::fs; /// use std::path::PathBuf;