use crate::stream::Closable;
use futures::{
future::{self, Either::{A, B}, Loop},
prelude::*,
stream::{futures_unordered::FuturesUnordered, StreamFuture},
sync::mpsc,
Stream
};
use void::{Void, unreachable};
pub enum State<S, T, A> {
Ready(S),
Stream(S, Box<dyn Stream<Item = T, Error = Void> + Send>),
Close(S),
Done(A)
}
pub fn dynamic_fold<S, F, R, T, E, A>
(init: S, main: mpsc::Receiver<T>, fun: F) -> impl Future<Item = Option<A>, Error = E>
where
F: FnMut(S, Option<T>) -> R,
R: Future<Item = State<S, T, A>, Error = E>,
T: Send + 'static
{
let (killcord, streams) = {
let (killcord, main) = Closable::new(main);
(killcord, Streams::new(Box::new(main)))
};
let init = (Some(killcord), streams, init, fun);
future::loop_fn(init, move |(killcord, streams, state, mut fun)| {
streams.into_future()
.and_then(move |(item, mut streams)| {
match item {
Some(m) => A(fun(state, Some(m)).then(move |result| {
match result {
Ok(State::Ready(a)) =>
A(future::ok(Loop::Continue((killcord, streams, a, fun)))),
Ok(State::Stream(a, s)) => {
let s = s.map_err(|void| unreachable(void));
streams.add(Box::new(s));
A(future::ok(Loop::Continue((killcord, streams, a, fun))))
}
Ok(State::Close(a)) =>
A(future::ok(Loop::Continue((None, streams, a, fun)))),
Ok(State::Done(x)) =>
B(future::ok(Loop::Break(Ok(Some(x))))),
Err(e) =>
B(future::ok(Loop::Break(Err(e))))
}
})),
None => B(fun(state, None).then(|result| {
match result {
Ok(State::Done(x)) => Ok(Loop::Break(Ok(Some(x)))),
Ok(_) => Ok(Loop::Break(Ok(None))),
Err(e) => Ok(Loop::Break(Err(e)))
}
}))
}
})
.or_else(|((), _)| Ok(Loop::Break(Ok(None))))
})
.then(|r: Result<_, ()>| {
match r {
Ok(Ok(x)) => Ok(x),
Ok(Err(e)) => Err(e),
Err(()) => Ok(None)
}
})
}
type UnorderedStreams<T> =
FuturesUnordered<StreamFuture<Box<dyn Stream<Item = T, Error = Void> + Send>>>;
struct Streams<T> {
main: Box<dyn Stream<Item = T, Error = ()> + Send>,
unordered: Option<UnorderedStreams<T>>,
done: bool }
impl<T> Streams<T> {
fn new(main: Box<dyn Stream<Item = T, Error = ()> + Send>) -> Self {
Streams { main, unordered: None, done: false }
}
fn add(&mut self, s: Box<dyn Stream<Item = T, Error = Void> + Send>) {
if let Some(ref mut t) = self.unordered {
t.push(s.into_future())
} else {
let mut t = FuturesUnordered::new();
t.push(s.into_future());
self.unordered = Some(t)
}
}
}
impl<T> Stream for Streams<T> {
type Item = T;
type Error = ();
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
match self.main.poll()? {
Async::Ready(Some(x)) => return Ok(Async::Ready(Some(x))),
Async::Ready(None) => { self.done = true }
Async::NotReady => {}
}
loop {
match self.unordered {
None => if self.done {
return Ok(Async::Ready(None))
} else {
return Ok(Async::NotReady)
}
Some(ref mut set) => match set.poll() {
Ok(Async::Ready(Some((Some(x), stream)))) => {
set.push(stream.into_future());
return Ok(Async::Ready(Some(x)))
}
Ok(Async::Ready(Some((None, _)))) => continue,
Ok(Async::Ready(None)) => if self.done {
return Ok(Async::Ready(None))
} else {
return Ok(Async::NotReady)
}
Ok(Async::NotReady) => return Ok(Async::NotReady),
Err((void, _)) => unreachable(void)
}
}
}
}
}