diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-01-15 12:42:10 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-01-15 12:42:10 +0100 |
| commit | ae1ab8afa9bd93a07872aa6ac281ee62d72c49d6 (patch) | |
| tree | bc0b5188b4e3d9d4fafc2d8e8ad2604c1489d4bb /src | |
| parent | e8cfae4140ca237b277b3e5afac61f6504c54191 (diff) | |
| parent | 3a1f0131a63a32a82f22b1c4ae04f8177730588f (diff) | |
| download | rust-ae1ab8afa9bd93a07872aa6ac281ee62d72c49d6.tar.gz rust-ae1ab8afa9bd93a07872aa6ac281ee62d72c49d6.zip | |
Rollup merge of #57579 - stjepang:once-with, r=SimonSapin
Add core::iter::once_with() Functions `iter::once()` and `iter::repeat()` construct iterators from values. The latter has the lazy variant `iter::repeat_with()`, but the former doesn't. This PR therefore adds `iter::once_with()`. Another way to think of `iter::once_with()` is that it's a function that converts `FnOnce() -> T` into `Iterator<Item = T>`. If this seems like a reasonable addition, I'll open a tracking issue and update the `#[feature(...)]` attributes.
Diffstat (limited to 'src')
| -rw-r--r-- | src/libcore/iter/mod.rs | 2 | ||||
| -rw-r--r-- | src/libcore/iter/sources.rs | 113 | ||||
| -rw-r--r-- | src/libcore/lib.rs | 1 | ||||
| -rw-r--r-- | src/libcore/tests/iter.rs | 18 | ||||
| -rw-r--r-- | src/libcore/tests/lib.rs | 1 |
5 files changed, 135 insertions, 0 deletions
diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 1ef5428a789..974906b682d 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 = "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 2a39089a8a2..2590fa6023a 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -377,6 +377,119 @@ pub fn once<T>(value: T) -> Once<T> { 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 = "57581")] +pub struct OnceWith<F> { + gen: Option<F>, +} + +#[unstable(feature = "iter_once_with", issue = "57581")] +impl<A, F: FnOnce() -> A> Iterator for OnceWith<F> { + type Item = A; + + #[inline] + fn next(&mut self) -> Option<A> { + self.gen.take().map(|f| f()) + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.gen.iter().size_hint() + } +} + +#[unstable(feature = "iter_once_with", issue = "57581")] +impl<A, F: FnOnce() -> A> DoubleEndedIterator for OnceWith<F> { + fn next_back(&mut self) -> Option<A> { + self.next() + } +} + +#[unstable(feature = "iter_once_with", issue = "57581")] +impl<A, F: FnOnce() -> A> ExactSizeIterator for OnceWith<F> { + fn len(&self) -> usize { + self.gen.iter().len() + } +} + +#[unstable(feature = "iter_once_with", issue = "57581")] +impl<A, F: FnOnce() -> A> FusedIterator for OnceWith<F> {} + +#[unstable(feature = "iter_once_with", issue = "57581")] +unsafe impl<A, F: FnOnce() -> A> TrustedLen for OnceWith<F> {} + +/// 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 +/// [`chain`]: trait.Iterator.html#method.chain +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// #![feature(iter_once_with)] +/// +/// 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 +/// #![feature(iter_once_with)] +/// +/// 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 = "57581")] +pub fn once_with<A, F: FnOnce() -> A>(gen: F) -> OnceWith<F> { + OnceWith { gen: Some(gen) } +} + /// Creates a new iterator where each iteration calls the provided closure /// `F: FnMut(&mut St) -> Option<T>`. /// diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 8879112fcf0..33c0da8a540 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 cf19851c17b..3944bc749d0 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; @@ -1907,6 +1908,23 @@ fn test_once() { } #[test] +fn test_once_with() { + let count = Cell::new(0); + let mut it = once_with(|| { + count.set(count.get() + 1); + 42 + }); + + assert_eq!(count.get(), 0); + assert_eq!(it.next(), Some(42)); + assert_eq!(count.get(), 1); + assert_eq!(it.next(), None); + assert_eq!(count.get(), 1); + assert_eq!(it.next(), None); + assert_eq!(count.get(), 1); +} + +#[test] fn test_empty() { let mut it = empty::<i32>(); assert_eq!(it.next(), None); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 72846daf16a..a9b8decfd02 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)] |
