extern crate futures;
use std::fmt::{Debug, Formatter, Result as FmtResult};
use futures::{Future, IntoFuture, Poll};
#[doc(hidden)]
pub use futures::future::err;
pub struct TryFuture<F: Future> {
inner: TryFutureInner<F>
}
impl<F: Future + Debug> Debug for TryFuture<F> {
fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
fmt.debug_struct("TryFuture").finish()
}
}
#[derive(Debug)]
enum TryFutureInner<F: Future> {
Result(::futures::future::FutureResult<F::Item, F::Error>),
Future(F)
}
impl<F: Future> TryFuture<F> {
fn from_result(res: Result<F::Item, F::Error>) -> TryFuture<F> {
TryFuture {
inner: TryFutureInner::Result(res.into_future())
}
}
pub fn from_ok(item: F::Item) -> TryFuture<F> {
TryFuture::from_result(Ok(item))
}
pub fn from_error(err: F::Error) -> TryFuture<F> {
TryFuture::from_result(Err(err))
}
}
impl<F: IntoFuture> From<F> for TryFuture<F::Future> {
fn from(future: F) -> TryFuture<F::Future> {
TryFuture {
inner: TryFutureInner::Future(future.into_future())
}
}
}
impl<F: Future> Future for TryFuture<F> {
type Item = F::Item;
type Error = F::Error;
fn poll(&mut self) -> Poll<F::Item, F::Error> {
match self.inner {
TryFutureInner::Result(ref mut future) => future.poll(),
TryFutureInner::Future(ref mut future) => future.poll()
}
}
}
#[macro_export]
macro_rules! try_future {
($expression:expr) => (
match $expression {
Err(err) => {
return $crate::TryFuture::from_error(err.into());
},
Ok(value) => value
}
)
}
#[macro_export]
macro_rules! try_future_box {
($expression:expr) => (
match $expression {
Err(err) => {
return Box::new($crate::err(err.into()));
},
Ok(value) => value
}
)
}
#[cfg(test)]
mod tests {
use futures::{future, Future};
use super::TryFuture;
#[test]
fn test_from_ok() {
let future = TryFuture::<future::Empty<u32, ()>>::from_ok(42);
assert_eq!(42, future.wait().unwrap());
}
#[test]
fn test_from_error() {
let future = TryFuture::<future::Empty<u32, ()>>::from_error(());
assert_eq!((), future.wait().err().unwrap());
}
#[test]
fn test_ok_into() {
let future: TryFuture<_> = future::ok::<u32, ()>(42).into();
assert_eq!(42, future.wait().unwrap());
}
#[test]
fn test_err_into() {
let future: TryFuture<_> = future::err::<u32, ()>(()).into();
assert_eq!((), future.wait().err().unwrap());
}
#[test]
fn test_try_future() {
use std::io;
struct CustomError(io::Error);
impl From<io::Error> for CustomError {
fn from(err: io::Error) -> CustomError {
CustomError(err)
}
}
let future = future::lazy(|| {
try_future!(Err(io::Error::new(io::ErrorKind::Other, "oh no!")));
future::ok::<_, CustomError>(()).into()
});
assert_eq!("oh no!", future.wait().err().unwrap().0.to_string());
}
#[test]
fn test_try_future_box() {
use std::io;
struct CustomError(io::Error);
impl From<io::Error> for CustomError {
fn from(err: io::Error) -> CustomError {
CustomError(err)
}
}
let future = future::lazy(|| {
try_future_box!(Err(io::Error::new(io::ErrorKind::Other, "oh no!")));
Box::new(future::ok::<_, CustomError>(()))
});
assert_eq!("oh no!", future.wait().err().unwrap().0.to_string());
}
}