use std::iter;
use std::panic;
use futures::{Future, Sink, Stream};
use errors::Dropped;
use wrappers::{CleanupIterator, OkIterator, ResultIterator, SinkSender, StreamExtractor};
pub use coroutine::Coroutine;
pub trait CoroutineFuture: Future + Sized {
fn coro_wait(self) -> Result<Self::Item, Self::Error> {
self.coro_wait_cleanup().unwrap_or_else(|_| panic::resume_unwind(Box::new(Dropped)))
}
fn coro_wait_cleanup(self) -> Result<Result<Self::Item, Self::Error>, Dropped>;
}
impl<F: Future> CoroutineFuture for F {
fn coro_wait_cleanup(self) -> Result<Result<Self::Item, Self::Error>, Dropped> {
Coroutine::wait(self)
}
}
pub trait CoroutineStream: Stream + Sized {
fn iter_ok(self) -> OkIterator<CleanupIterator<Self>> {
OkIterator::new(self.iter_cleanup())
}
fn iter_result(self) -> ResultIterator<CleanupIterator<Self>> {
ResultIterator::new(self.iter_cleanup())
}
fn iter_cleanup(self) -> CleanupIterator<Self>;
fn extractor(&mut self) -> StreamExtractor<Self>;
fn coro_next(&mut self) -> Result<Option<Self::Item>, Self::Error> {
self.coro_next_cleanup().unwrap()
}
fn coro_next_cleanup(&mut self) -> Result<Result<Option<Self::Item>, Self::Error>, Dropped> {
self.extractor().coro_wait_cleanup()
}
}
impl<S: Stream> CoroutineStream for S {
fn iter_cleanup(self) -> CleanupIterator<Self> {
CleanupIterator::new(self)
}
fn extractor(&mut self) -> StreamExtractor<Self> {
StreamExtractor::new(self)
}
}
pub trait CoroutineSink: Sink + Sized {
fn coro_send(&mut self, item: Self::SinkItem) -> Result<(), Self::SinkError> {
self.coro_sender(iter::once(item)).coro_wait()
}
fn coro_send_cleanup(&mut self, item: Self::SinkItem)
-> Result<Result<(), Self::SinkError>, Dropped>
{
self.coro_sender(iter::once(item)).coro_wait_cleanup()
}
fn coro_send_many<I>(&mut self, iter: I) -> Result<Result<(), Self::SinkError>, Dropped>
where
I: IntoIterator<Item = Self::SinkItem>
{
self.coro_sender(iter).coro_wait_cleanup()
}
fn coro_sender<I>(&mut self, iter: I) -> SinkSender<Self::SinkItem, Self, I::IntoIter>
where
I: IntoIterator<Item = Self::SinkItem>;
}
impl<S: Sink> CoroutineSink for S {
fn coro_sender<Src>(&mut self, iter: Src) -> SinkSender<Self::SinkItem, Self, Src::IntoIter>
where
Src: IntoIterator<Item = Self::SinkItem>
{
SinkSender::new(self, iter)
}
}