iter_utils/delay.rs
1//! Lazy iterator creation for recursive or deferred iteration patterns.
2
3/// Wraps an iterator of type I by creating it on the first call to `next()`.
4enum DelayState<I: Iterator, F: FnOnce() -> I> {
5 New(Option<F>),
6 Old(I),
7}
8
9pub struct Delayed<I: Iterator, F: FnOnce() -> I>(DelayState<I, F>);
10
11impl<I: Iterator, F: FnOnce() -> I> Iterator for Delayed<I, F> {
12 type Item = I::Item;
13
14 fn next(&mut self) -> Option<Self::Item> {
15 match &mut self.0 {
16 DelayState::New(new) => {
17 let new = new
18 .take()
19 .expect("Delay to have either a function or an iterator");
20 let mut old = new();
21 let next = old.next();
22 self.0 = DelayState::Old(old);
23 next
24 }
25 DelayState::Old(old) => old.next(),
26 }
27 }
28}
29
30/// Wraps an iterator created by `new` on the first call to
31/// [`next()`][Iterator::next()].
32///
33/// For example, consider Haskell's [canonical zipWith implementation][hs]:
34/// ```hs
35/// fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
36/// ```
37///
38/// A naive translation to Rust would cause infinite recursion. We can emulate
39/// Haskell's lazy evaluation by delaying the recursive calls:
40/// ```
41/// use iter_utils::delay;
42///
43/// /// Returns an inefficient iterator over the Fibonacci numbers.
44/// fn fibs() -> Box<dyn Iterator<Item = u32>> {
45/// Box::new(
46/// [0, 1]
47/// .into_iter()
48/// .chain(delay(fibs).zip(delay(fibs).skip(1)).map(|(x, y)| x + y)),
49/// )
50/// }
51///
52/// for (got, want) in fibs().zip([0, 1, 1, 2, 3, 5, 8, 13]) {
53/// assert_eq!(got, want);
54/// }
55/// ```
56///
57/// [hs]: https://wiki.haskell.org/The_Fibonacci_sequence#Canonical_zipWith_implementation
58pub fn delay<I: Iterator, F: FnOnce() -> I>(new: F) -> Delayed<I, F> {
59 Delayed(DelayState::New(Some(new)))
60}
61
62/// Lets you call `fibs.delay()` instead of `delay(fibs)`, if such is your wont.
63pub trait Delay<I: Iterator, F: FnOnce() -> I> {
64 fn delay(self) -> Delayed<I, F>;
65}
66
67impl<I: Iterator, F: FnOnce() -> I> Delay<I, F> for F {
68 fn delay(self) -> Delayed<I, F> {
69 delay(self)
70 }
71}