From 04c74f46f0a0ecf886f1c12b51483d38690fac22 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Sun, 13 Jan 2019 11:16:14 +0100 Subject: [PATCH] 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)]