I've been learning from this thread and playing with the code. Here's a version that abstracts out an "iterize" function that makes such Iterators for you.
fn main() {
dbg!(fib().take(6).collect::<Vec<i32>>());
}
// Returns an Iterator for the Fibonacci sequence: 1 1 2 3 5 8 ...
fn fib() -> impl Iterator<Item = i32> {
iterize((1,1), |(a,b)| (b, a+b))
}
// Produces an Iterator by induction.
// Given an initial state of type (R,S) and a function that produces
// the next state from an existing state, return an Iterator for the Rs.
// So in (R,S), R is the part that gets (R)eturned by the Iterator,
// and S is any additional (S)tate used internally.
fn iterize<R: Copy, S: Copy>(s0: (R,S), f: impl Fn((R,S)) -> (R,S)) -> impl Iterator<Item = R> {
let mut state = s0;
std::iter::repeat_with(
move || { state.swap(f(state)).0 }
)
}
// a.swap(b) sets a to b and returns the old value of a.
pub trait Swap: Sized {
fn swap(&mut self, value: Self) -> Self;
}
impl<T> Swap for T {
fn swap(&mut self, new: Self) -> Self {
std::mem::replace(self, new)
}
}
I don't know how well it benches.
This is long, of course, but in addition to fib() it offers two abstractions (a.swap(b) and iterize()) which are hopefully useful in other situations.
I think R and S need to be Copy for std::mem::replace.
Credit to KrishnaSannasi for the Swap trait, which cleans up the replace: