use core::mem;
use {Future, IntoFuture, Async, Poll};
use stream::Stream;
pub fn unfold<T, F, Fut, It>(init: T, f: F) -> Unfold<T, F, Fut>
where F: FnMut(T) -> Option<Fut>,
Fut: IntoFuture<Item = (It, T)>,
{
Unfold {
f: f,
state: State::Ready(init),
}
}
#[derive(Debug)]
#[must_use = "streams do nothing unless polled"]
pub struct Unfold<T, F, Fut> where Fut: IntoFuture {
f: F,
state: State<T, Fut::Future>,
}
impl <T, F, Fut, It> Stream for Unfold<T, F, Fut>
where F: FnMut(T) -> Option<Fut>,
Fut: IntoFuture<Item = (It, T)>,
{
type Item = It;
type Error = Fut::Error;
fn poll(&mut self) -> Poll<Option<It>, Fut::Error> {
loop {
match mem::replace(&mut self.state, State::Empty) {
State::Empty => { return Ok(Async::Ready(None)); }
State::Ready(state) => {
match (self.f)(state) {
Some(fut) => { self.state = State::Processing(fut.into_future()); }
None => { return Ok(Async::Ready(None)); }
}
}
State::Processing(mut fut) => {
match try!(fut.poll()) {
Async:: Ready((item, next_state)) => {
self.state = State::Ready(next_state);
return Ok(Async::Ready(Some(item)));
}
Async::NotReady => {
self.state = State::Processing(fut);
return Ok(Async::NotReady);
}
}
}
}
}
}
}
#[derive(Debug)]
enum State<T, F> where F: Future {
Empty,
Ready(T),
Processing(F),
}