Skip to content

Commit 04c74f4

Browse files
author
Stjepan Glavina
committed
Add core::iter::once_with
1 parent 75a369c commit 04c74f4

File tree

5 files changed

+129
-0
lines changed

5 files changed

+129
-0
lines changed

src/libcore/iter/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,8 @@ pub use self::sources::{RepeatWith, repeat_with};
329329
pub use self::sources::{Empty, empty};
330330
#[stable(feature = "iter_once", since = "1.2.0")]
331331
pub use self::sources::{Once, once};
332+
#[unstable(feature = "iter_once_with", issue = "0")]
333+
pub use self::sources::{OnceWith, once_with};
332334
#[unstable(feature = "iter_unfold", issue = "55977")]
333335
pub use self::sources::{Unfold, unfold, Successors, successors};
334336

src/libcore/iter/sources.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,114 @@ pub fn once<T>(value: T) -> Once<T> {
377377
Once { inner: Some(value).into_iter() }
378378
}
379379

380+
/// An iterator that repeats elements of type `A` endlessly by
381+
/// applying the provided closure `F: FnMut() -> A`.
382+
///
383+
/// This `struct` is created by the [`once_with`] function.
384+
/// See its documentation for more.
385+
///
386+
/// [`once_with`]: fn.once_with.html
387+
#[derive(Copy, Clone, Debug)]
388+
#[unstable(feature = "iter_once_with", issue = "0")]
389+
pub struct OnceWith<F> {
390+
gen: Option<F>,
391+
}
392+
393+
#[unstable(feature = "iter_once_with", issue = "0")]
394+
impl<A, F: FnOnce() -> A> Iterator for OnceWith<F> {
395+
type Item = A;
396+
397+
#[inline]
398+
fn next(&mut self) -> Option<A> {
399+
self.gen.take().map(|f| f())
400+
}
401+
402+
#[inline]
403+
fn size_hint(&self) -> (usize, Option<usize>) {
404+
self.gen.iter().size_hint()
405+
}
406+
}
407+
408+
#[unstable(feature = "iter_once_with", issue = "0")]
409+
impl<A, F: FnOnce() -> A> DoubleEndedIterator for OnceWith<F> {
410+
fn next_back(&mut self) -> Option<A> {
411+
self.next()
412+
}
413+
}
414+
415+
#[unstable(feature = "iter_once_with", issue = "0")]
416+
impl<A, F: FnOnce() -> A> ExactSizeIterator for OnceWith<F> {
417+
fn len(&self) -> usize {
418+
self.gen.iter().len()
419+
}
420+
}
421+
422+
#[unstable(feature = "iter_once_with", issue = "0")]
423+
impl<A, F: FnOnce() -> A> FusedIterator for OnceWith<F> {}
424+
425+
#[unstable(feature = "iter_once_with", issue = "0")]
426+
unsafe impl<A, F: FnOnce() -> A> TrustedLen for OnceWith<F> {}
427+
428+
/// Creates an iterator that lazily generates a value exactly once by invoking
429+
/// the provided closure.
430+
///
431+
/// This is commonly used to adapt a single value generator into a [`chain`] of
432+
/// other kinds of iteration. Maybe you have an iterator that covers almost
433+
/// everything, but you need an extra special case. Maybe you have a function
434+
/// which works on iterators, but you only need to process one value.
435+
///
436+
/// Unlike [`once`], this function will lazily generate the value on request.
437+
///
438+
/// [`once`]: fn.once.html
439+
///
440+
/// # Examples
441+
///
442+
/// Basic usage:
443+
///
444+
/// ```
445+
/// use std::iter;
446+
///
447+
/// // one is the loneliest number
448+
/// let mut one = iter::once_with(|| 1);
449+
///
450+
/// assert_eq!(Some(1), one.next());
451+
///
452+
/// // just one, that's all we get
453+
/// assert_eq!(None, one.next());
454+
/// ```
455+
///
456+
/// Chaining together with another iterator. Let's say that we want to iterate
457+
/// over each file of the `.foo` directory, but also a configuration file,
458+
/// `.foorc`:
459+
///
460+
/// ```no_run
461+
/// use std::iter;
462+
/// use std::fs;
463+
/// use std::path::PathBuf;
464+
///
465+
/// let dirs = fs::read_dir(".foo").unwrap();
466+
///
467+
/// // we need to convert from an iterator of DirEntry-s to an iterator of
468+
/// // PathBufs, so we use map
469+
/// let dirs = dirs.map(|file| file.unwrap().path());
470+
///
471+
/// // now, our iterator just for our config file
472+
/// let config = iter::once_with(|| PathBuf::from(".foorc"));
473+
///
474+
/// // chain the two iterators together into one big iterator
475+
/// let files = dirs.chain(config);
476+
///
477+
/// // this will give us all of the files in .foo as well as .foorc
478+
/// for f in files {
479+
/// println!("{:?}", f);
480+
/// }
481+
/// ```
482+
#[inline]
483+
#[unstable(feature = "iter_once_with", issue = "0")]
484+
pub fn once_with<A, F: FnOnce() -> A>(gen: F) -> OnceWith<F> {
485+
OnceWith { gen: Some(gen) }
486+
}
487+
380488
/// Creates a new iterator where each iteration calls the provided closure
381489
/// `F: FnMut(&mut St) -> Option<T>`.
382490
///

src/libcore/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
#![feature(extern_types)]
8080
#![feature(fundamental)]
8181
#![feature(intrinsics)]
82+
#![feature(iter_once_with)]
8283
#![feature(lang_items)]
8384
#![feature(link_llvm_intrinsics)]
8485
#![feature(never_type)]

src/libcore/tests/iter.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1906,6 +1906,23 @@ fn test_once() {
19061906
assert_eq!(it.next(), None);
19071907
}
19081908

1909+
#[test]
1910+
fn test_once_with() {
1911+
let mut count = 0;
1912+
let mut it = once_with(|| {
1913+
count += 1;
1914+
42
1915+
});
1916+
1917+
assert_eq!(count, 0);
1918+
assert_eq!(it.next(), Some(42));
1919+
assert_eq!(count, 1);
1920+
assert_eq!(it.next(), None);
1921+
assert_eq!(count, 1);
1922+
assert_eq!(it.next(), None);
1923+
assert_eq!(count, 1);
1924+
}
1925+
19091926
#[test]
19101927
fn test_empty() {
19111928
let mut it = empty::<i32>();

src/libcore/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#![feature(hashmap_internals)]
1313
#![feature(iter_copied)]
1414
#![feature(iter_nth_back)]
15+
#![feature(iter_once_with)]
1516
#![feature(iter_unfold)]
1617
#![feature(pattern)]
1718
#![feature(range_is_empty)]

0 commit comments

Comments
 (0)