From edc9295b051296e6e97d990d42f8bae31d2b9e2a Mon Sep 17 00:00:00 2001 From: root Date: Mon, 22 Jun 2015 14:21:23 +0200 Subject: [PATCH] Adopt Unfold from rust, since it is deprecated there Original author credit for Unfold (UnfoldrIterator in the first revision) is @huonw. --- src/lib.rs | 5 ++-- src/sources.rs | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d372354b3..0c4b618a6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,8 +11,8 @@ //! ``` //! //! Some iterators or adaptors are used directly like regular structs, for example -//! [**PutBack**](./struct.PutBack.html), [**Zip**](./struct.Zip.html), -//! [**Stride**](./struct.Stride.html), [**StrideMut**](./struct.StrideMut.html). +//! [**PutBack**](./struct.PutBack.html), [**Unfold**](./struct.Unfold.html), +//! [**Zip**](./struct.Zip.html), [**Stride**](./struct.Stride.html) //! //! To enable the macros in this crate, use the `#[macro_use]` attribute: //! @@ -73,6 +73,7 @@ pub use times::times; pub use linspace::{linspace, Linspace}; pub use sources::{ RepeatCall, + Unfold, }; pub use zip_longest::{ZipLongest, EitherOrBoth}; pub use ziptuple::{Zip}; diff --git a/src/sources.rs b/src/sources.rs index c1299d2ad..e066eca6a 100644 --- a/src/sources.rs +++ b/src/sources.rs @@ -59,3 +59,75 @@ impl DoubleEndedIterator for RepeatCall where } +/// **Unfold** is a general iterator builder: it has a mutable state value, +/// and a closure with access to the state that produces the next value. +/// +/// This more or less equivalent to a regular struct with an **Iterator** +/// implementation, and is useful for one-off iterators. +/// +/// ``` +/// // an example of iterator that yields sequential Fibonacci numbers, and stops +/// // on overflow. +/// use itertools::Unfold; +/// +/// // This iterator will yield up to the last Fibonacci number before the max +/// // value of `u32`. You can simply change `u32` to `u64` in this line if +/// // you want higher values than that. +/// let mut fibonacci = Unfold::new((Some(0u32), Some(1u32)), +/// |&mut (ref mut x2, ref mut x1)| { +/// // Attempt to get the next Fibonacci number +/// // `x1` will be `None` if previously overflowed. +/// let next = match (*x2, *x1) { +/// (Some(x2), Some(x1)) => x2.checked_add(x1), +/// _ => None, +/// }; +/// +/// // Shift left: ret <- x2 <- x1 <- next +/// let ret = *x2; +/// *x2 = *x1; +/// *x1 = next; +/// +/// ret +/// }); +/// +/// itertools::assert_equal(fibonacci.take(8), +/// vec![0, 1, 1, 2, 3, 5, 8, 13]); +/// ``` +#[derive(Clone)] +pub struct Unfold { + f: F, + /// Internal state that will be passed to the closure on the next iteration + pub state: St, +} + +impl Unfold + where F: FnMut(&mut St) -> Option +{ + /// Creates a new iterator with the specified closure as the "iterator + /// function" and an initial state to eventually pass to the closure + #[inline] + pub fn new(initial_state: St, f: F) -> Unfold { + Unfold { + f: f, + state: initial_state + } + } +} + +impl Iterator for Unfold + where F: FnMut(&mut St) -> Option +{ + type Item = A; + + #[inline] + fn next(&mut self) -> Option { + (self.f)(&mut self.state) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + // no possible known bounds at this point + (0, None) + } +} +