Skip to content

Commit ef2cbec

Browse files
authored
Rollup merge of rust-lang#55869 - SimonSapin:iterate, r=alexcrichton
Add std::iter::unfold This adds an **unstable** ~`std::iter::iterate`~ `std::iter::unfold` function and ~`std::iter::Iterate`~ `std::iter::Unfold` type that trivially wrap a ~`FnMut() -> Option<T>`~ `FnMut(&mut State) -> Option<T>` closure to create an iterator. ~Iterator state can be kept in the closure’s environment or captures.~ This is intended to help reduce amount of boilerplate needed when defining an iterator that is only created in one place. Compare the existing example of the `std::iter` module: (explanatory comments elided) ```rust struct Counter { count: usize, } impl Counter { fn new() -> Counter { Counter { count: 0 } } } impl Iterator for Counter { type Item = usize; fn next(&mut self) -> Option<usize> { self.count += 1; if self.count < 6 { Some(self.count) } else { None } } } ``` … with the same algorithm rewritten to use this new API: ```rust fn counter() -> impl Iterator<Item=usize> { std::iter::unfold(0, |count| { *count += 1; if *count < 6 { Some(*count) } else { None } }) } ``` ----- This also add unstable `std::iter::successors` which takes an (optional) initial item and a closure that takes an item and computes the next one (its successor). ```rust let powers_of_10 = successors(Some(1_u16), |n| n.checked_mul(10)); assert_eq!(powers_of_10.collect::<Vec<_>>(), &[1, 10, 100, 1_000, 10_000]); ```
2 parents 738afd4 + a4279a0 commit ef2cbec

File tree

4 files changed

+177
-2
lines changed

4 files changed

+177
-2
lines changed

src/libcore/iter/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,10 @@
112112
//!
113113
//! // next() is the only required method
114114
//! fn next(&mut self) -> Option<usize> {
115-
//! // increment our count. This is why we started at zero.
115+
//! // Increment our count. This is why we started at zero.
116116
//! self.count += 1;
117117
//!
118-
//! // check to see if we've finished counting or not.
118+
//! // Check to see if we've finished counting or not.
119119
//! if self.count < 6 {
120120
//! Some(self.count)
121121
//! } else {
@@ -339,6 +339,8 @@ pub use self::sources::{RepeatWith, repeat_with};
339339
pub use self::sources::{Empty, empty};
340340
#[stable(feature = "iter_once", since = "1.2.0")]
341341
pub use self::sources::{Once, once};
342+
#[unstable(feature = "iter_unfold", issue = "55977")]
343+
pub use self::sources::{Unfold, unfold, Successors, successors};
342344

343345
#[stable(feature = "rust1", since = "1.0.0")]
344346
pub use self::traits::{FromIterator, IntoIterator, DoubleEndedIterator, Extend};

src/libcore/iter/sources.rs

+161
Original file line numberDiff line numberDiff line change
@@ -386,3 +386,164 @@ impl<T> FusedIterator for Once<T> {}
386386
pub fn once<T>(value: T) -> Once<T> {
387387
Once { inner: Some(value).into_iter() }
388388
}
389+
390+
/// Creates a new iterator where each iteration calls the provided closure
391+
/// `F: FnMut(&mut St) -> Option<T>`.
392+
///
393+
/// This allows creating a custom iterator with any behavior
394+
/// without using the more verbose syntax of creating a dedicated type
395+
/// and implementing the `Iterator` trait for it.
396+
///
397+
/// In addition to its captures and environment,
398+
/// the closure is given a mutable reference to some state
399+
/// that is preserved across iterations.
400+
/// That state starts as the given `initial_state` value.
401+
///
402+
/// Note that the `Unfold` iterator doesn’t make assumptions about the behavior of the closure,
403+
/// and therefore conservatively does not implement [`FusedIterator`],
404+
/// or override [`Iterator::size_hint`] from its default `(0, None)`.
405+
///
406+
/// [`FusedIterator`]: trait.FusedIterator.html
407+
/// [`Iterator::size_hint`]: trait.Iterator.html#method.size_hint
408+
///
409+
/// # Examples
410+
///
411+
/// Let’s re-implement the counter iterator from [module-level documentation]:
412+
///
413+
/// [module-level documentation]: index.html
414+
///
415+
/// ```
416+
/// #![feature(iter_unfold)]
417+
/// let counter = std::iter::unfold(0, |count| {
418+
/// // Increment our count. This is why we started at zero.
419+
/// *count += 1;
420+
///
421+
/// // Check to see if we've finished counting or not.
422+
/// if *count < 6 {
423+
/// Some(*count)
424+
/// } else {
425+
/// None
426+
/// }
427+
/// });
428+
/// assert_eq!(counter.collect::<Vec<_>>(), &[1, 2, 3, 4, 5]);
429+
/// ```
430+
#[inline]
431+
#[unstable(feature = "iter_unfold", issue = "55977")]
432+
pub fn unfold<St, T, F>(initial_state: St, f: F) -> Unfold<St, F>
433+
where F: FnMut(&mut St) -> Option<T>
434+
{
435+
Unfold {
436+
state: initial_state,
437+
f,
438+
}
439+
}
440+
441+
/// An iterator where each iteration calls the provided closure `F: FnMut(&mut St) -> Option<T>`.
442+
///
443+
/// This `struct` is created by the [`unfold`] function.
444+
/// See its documentation for more.
445+
///
446+
/// [`unfold`]: fn.unfold.html
447+
#[derive(Clone)]
448+
#[unstable(feature = "iter_unfold", issue = "55977")]
449+
pub struct Unfold<St, F> {
450+
state: St,
451+
f: F,
452+
}
453+
454+
#[unstable(feature = "iter_unfold", issue = "55977")]
455+
impl<St, T, F> Iterator for Unfold<St, F>
456+
where F: FnMut(&mut St) -> Option<T>
457+
{
458+
type Item = T;
459+
460+
#[inline]
461+
fn next(&mut self) -> Option<Self::Item> {
462+
(self.f)(&mut self.state)
463+
}
464+
}
465+
466+
#[unstable(feature = "iter_unfold", issue = "55977")]
467+
impl<St: fmt::Debug, F> fmt::Debug for Unfold<St, F> {
468+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
469+
f.debug_struct("Unfold")
470+
.field("state", &self.state)
471+
.finish()
472+
}
473+
}
474+
475+
/// Creates a new iterator where each successive item is computed based on the preceding one.
476+
///
477+
/// The iterator starts with the given first item (if any)
478+
/// and calls the given `FnMut(&T) -> Option<T>` closure to compute each item’s successor.
479+
///
480+
/// ```
481+
/// #![feature(iter_unfold)]
482+
/// use std::iter::successors;
483+
///
484+
/// let powers_of_10 = successors(Some(1_u16), |n| n.checked_mul(10));
485+
/// assert_eq!(powers_of_10.collect::<Vec<_>>(), &[1, 10, 100, 1_000, 10_000]);
486+
/// ```
487+
#[unstable(feature = "iter_unfold", issue = "55977")]
488+
pub fn successors<T, F>(first: Option<T>, succ: F) -> Successors<T, F>
489+
where F: FnMut(&T) -> Option<T>
490+
{
491+
// If this function returned `impl Iterator<Item=T>`
492+
// it could be based on `unfold` and not need a dedicated type.
493+
// However having a named `Successors<T, F>` type allows it to be `Clone` when `T` and `F` are.
494+
Successors {
495+
next: first,
496+
succ,
497+
}
498+
}
499+
500+
/// An new iterator where each successive item is computed based on the preceding one.
501+
///
502+
/// This `struct` is created by the [`successors`] function.
503+
/// See its documentation for more.
504+
///
505+
/// [`successors`]: fn.successors.html
506+
#[derive(Clone)]
507+
#[unstable(feature = "iter_unfold", issue = "55977")]
508+
pub struct Successors<T, F> {
509+
next: Option<T>,
510+
succ: F,
511+
}
512+
513+
#[unstable(feature = "iter_unfold", issue = "55977")]
514+
impl<T, F> Iterator for Successors<T, F>
515+
where F: FnMut(&T) -> Option<T>
516+
{
517+
type Item = T;
518+
519+
#[inline]
520+
fn next(&mut self) -> Option<Self::Item> {
521+
self.next.take().map(|item| {
522+
self.next = (self.succ)(&item);
523+
item
524+
})
525+
}
526+
527+
#[inline]
528+
fn size_hint(&self) -> (usize, Option<usize>) {
529+
if self.next.is_some() {
530+
(1, None)
531+
} else {
532+
(0, Some(0))
533+
}
534+
}
535+
}
536+
537+
#[unstable(feature = "iter_unfold", issue = "55977")]
538+
impl<T, F> FusedIterator for Successors<T, F>
539+
where F: FnMut(&T) -> Option<T>
540+
{}
541+
542+
#[unstable(feature = "iter_unfold", issue = "55977")]
543+
impl<T: fmt::Debug, F> fmt::Debug for Successors<T, F> {
544+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
545+
f.debug_struct("Successors")
546+
.field("next", &self.next)
547+
.finish()
548+
}
549+
}

src/libcore/tests/iter.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1759,6 +1759,17 @@ fn test_repeat_with_take_collect() {
17591759
assert_eq!(v, vec![1, 2, 4, 8, 16]);
17601760
}
17611761

1762+
#[test]
1763+
fn test_successors() {
1764+
let mut powers_of_10 = successors(Some(1_u16), |n| n.checked_mul(10));
1765+
assert_eq!(powers_of_10.by_ref().collect::<Vec<_>>(), &[1, 10, 100, 1_000, 10_000]);
1766+
assert_eq!(powers_of_10.next(), None);
1767+
1768+
let mut empty = successors(None::<u32>, |_| unimplemented!());
1769+
assert_eq!(empty.next(), None);
1770+
assert_eq!(empty.next(), None);
1771+
}
1772+
17621773
#[test]
17631774
fn test_fuse() {
17641775
let mut it = 0..3;

src/libcore/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#![feature(flt2dec)]
2020
#![feature(fmt_internals)]
2121
#![feature(hashmap_internals)]
22+
#![feature(iter_unfold)]
2223
#![feature(pattern)]
2324
#![feature(range_is_empty)]
2425
#![feature(raw)]

0 commit comments

Comments
 (0)