]> git.lizzy.rs Git - rust.git/commitdiff
Add core::iter::once_with
authorStjepan Glavina <stjepang@gmail.com>
Sun, 13 Jan 2019 10:16:14 +0000 (11:16 +0100)
committerStjepan Glavina <stjepang@gmail.com>
Sun, 13 Jan 2019 15:58:08 +0000 (16:58 +0100)
src/libcore/iter/mod.rs
src/libcore/iter/sources.rs
src/libcore/lib.rs
src/libcore/tests/iter.rs
src/libcore/tests/lib.rs

index 03369d6c8f3fd60959ca670a185e8d250a16203b..f647a61a584c69e77dac5972b46b24392d593b6b 100644 (file)
 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};
 
index 2a39089a8a229cc35615dc50f79ca2c2c0b91480..d183fa3a7c233640d857f3d1ae3e585a64f6ead2 100644 (file)
@@ -377,6 +377,114 @@ 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 = "0")]
+pub struct OnceWith<F> {
+    gen: Option<F>,
+}
+
+#[unstable(feature = "iter_once_with", issue = "0")]
+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 = "0")]
+impl<A, F: FnOnce() -> A> DoubleEndedIterator for OnceWith<F> {
+    fn next_back(&mut self) -> Option<A> {
+        self.next()
+    }
+}
+
+#[unstable(feature = "iter_once_with", issue = "0")]
+impl<A, F: FnOnce() -> A> ExactSizeIterator for OnceWith<F> {
+    fn len(&self) -> usize {
+        self.gen.iter().len()
+    }
+}
+
+#[unstable(feature = "iter_once_with", issue = "0")]
+impl<A, F: FnOnce() -> A> FusedIterator for OnceWith<F> {}
+
+#[unstable(feature = "iter_once_with", issue = "0")]
+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
+///
+/// # 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, 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>`.
 ///
index a5f20d08e47bee6256736bc693e0911bec30d053..598e7fd706a24c3d17159d7bd474dd654b6fffa0 100644 (file)
@@ -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)]
index cf19851c17b35ccc579a574d745aeb1582bff29f..b62f55b2cd0034d09519a250349ec82ab55dfc0e 100644 (file)
@@ -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::<i32>();
index 72846daf16a6b92beebb5c593542884be986ca40..a9b8decfd0262beb381f0bffbf55e1b5a0c1a2da 100644 (file)
@@ -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)]