try_future/
lib.rs

1//! This crate aims to provide a convenient short-hand for returning early
2//! from `futures`-based functions.
3//!
4//! The general pattern it supports is where before a function performs
5//! an asynchronous task, it does some work that might result in an early
6//! termination, for example:
7//!
8//! - certain parsing or validation logic that might fail, and upon which
9//!   the function should return immediately with an error
10//! - some local cache lookup or other optimization that might render the
11//!   asynchronous task unnecessary, and where the function should instead
12//!   return immediately with a value
13//!
14//! To that end, the [`TryFuture`](TryFuture) struct implements a future which can
15//! either resolve immediately with a value or an error, or alternatively wrap another
16//! future performing some asynchronous task.
17//!
18//! The equivalent of [`try!`](try!) or the `?` operator is provided by the
19//! [`try_future!`](try_future!) and [`try_future_box!`](try_future_box!) macros:
20//!
21//! - `try_future!` will inspect the `Result` passed to it, and will exit
22//! the current function by returning a `TryFuture` when it finds an `Err`. Otherwise
23//! it will unwrap the result and pass back the value inside the result.
24//!
25//! - `try_future_box!` works in the same way, except that when encountering an `Err`
26//! it will return a boxed future.
27//!
28//! > **Please note**: The `try_future!` and `try_future_box!` macros only accept inputs
29//! > of type `Result`. Alas, the equivalent of `async`/`await` is not yet possible in
30//! > stable rust (however if you don't shy away from using nightly, you could take a look
31//! > at the [`futures-await`](https://github.com/alexcrichton/futures-await) project).
32//!
33//! # Examples
34//!
35//! ## Using `impl Future<_>`
36//!
37//! ```rust,ignore
38//! #[macro_use] extern crate try_future;
39//!
40//! fn make_request<C: Connect>(target: &str, client: &Client<C>) ->
41//!     impl Future<Item=Response, Error=Error>
42//! {
43//!     let uri = try_future!(target.parse::<Uri>());
44//!
45//!     client.get(uri).into()
46//! }
47//! ```
48//!
49//! ## Using `Box<Future<_>>`
50//!
51//! ```rust,ignore
52//! #[macro_use] extern crate try_future;
53//!
54//! fn make_request<C: Connect>(target: &str, client: &Client<C>) ->
55//!     Box<Future<Item=Response, Error=Error>>
56//! {
57//!     let uri = try_future_box!(target.parse::<Uri>());
58//!
59//!     Box::new(client.get(uri))
60//! }
61//! ```
62
63extern crate futures;
64
65use std::fmt::{Debug, Formatter, Result as FmtResult};
66
67use futures::{Future, IntoFuture, Poll};
68
69#[doc(hidden)]
70pub use futures::future::err;
71
72/// Future which can either resolve immediately with a value or an error,
73/// or alternatively wrap another future performing some asynchronous task.
74///
75/// The [`From`](From) impl on `TryFuture` can be used to wrap another future.
76pub struct TryFuture<F: Future> {
77    inner: TryFutureInner<F>
78}
79
80impl<F: Future + Debug> Debug for TryFuture<F> {
81    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
82        fmt.debug_struct("TryFuture").finish()
83    }
84}
85
86#[derive(Debug)]
87enum TryFutureInner<F: Future> {
88   Result(::futures::future::FutureResult<F::Item, F::Error>),
89   Future(F)
90}
91
92impl<F: Future> TryFuture<F> {
93    fn from_result(res: Result<F::Item, F::Error>) -> TryFuture<F> {
94        TryFuture {
95            inner: TryFutureInner::Result(res.into_future())
96        }
97    }
98
99    /// Create a `TryFuture` future that immediately resolves
100    /// with the specified value.
101    pub fn from_ok(item: F::Item) -> TryFuture<F> {
102        TryFuture::from_result(Ok(item))
103    }
104
105    /// Create a `TryFuture` future that immediately rejects
106    /// with the specified error.
107    pub fn from_error(err: F::Error) -> TryFuture<F> {
108        TryFuture::from_result(Err(err))
109    }
110}
111
112impl<F: IntoFuture> From<F> for TryFuture<F::Future> {
113    fn from(future: F) -> TryFuture<F::Future> {
114        TryFuture {
115            inner: TryFutureInner::Future(future.into_future())
116        }
117    }
118}
119
120impl<F: Future> Future for TryFuture<F> {
121    type Item = F::Item;
122    type Error = F::Error;
123
124    fn poll(&mut self) -> Poll<F::Item, F::Error> {
125        match self.inner {
126            TryFutureInner::Result(ref mut future) => future.poll(),
127            TryFutureInner::Future(ref mut future) => future.poll()
128        }
129    }
130}
131
132/// Equivalent of `try! returning a [`TryFuture`](TryFuture).
133#[macro_export]
134macro_rules! try_future {
135    ($expression:expr) => (
136        match $expression {
137            Err(err) => {
138                return $crate::TryFuture::from_error(err.into());
139            },
140            Ok(value) => value
141        }
142    )
143}
144
145/// Equivalent of `try!` returning a `Box<Future<_>>`.
146#[macro_export]
147macro_rules! try_future_box {
148    ($expression:expr) => (
149        match $expression {
150            Err(err) => {
151                return Box::new($crate::err(err.into()));
152            },
153            Ok(value) => value
154        }
155    )
156}
157
158#[cfg(test)]
159mod tests {
160    use futures::{future, Future};
161
162    use super::TryFuture;
163
164    #[test]
165    fn test_from_ok() {
166        let future = TryFuture::<future::Empty<u32, ()>>::from_ok(42);
167        assert_eq!(42, future.wait().unwrap());
168    }
169
170    #[test]
171    fn test_from_error() {
172        let future = TryFuture::<future::Empty<u32, ()>>::from_error(());
173        assert_eq!((), future.wait().err().unwrap());
174    }
175
176    #[test]
177    fn test_ok_into() {
178        let future: TryFuture<_> = future::ok::<u32, ()>(42).into();
179        assert_eq!(42, future.wait().unwrap());
180    }
181
182    #[test]
183    fn test_err_into() {
184        let future: TryFuture<_> = future::err::<u32, ()>(()).into();
185        assert_eq!((), future.wait().err().unwrap());
186    }
187
188    #[test]
189    fn test_try_future() {
190        use std::io;
191
192        struct CustomError(io::Error);
193
194        impl From<io::Error> for CustomError {
195            fn from(err: io::Error) -> CustomError {
196                CustomError(err)
197            }
198        }
199
200        let future = future::lazy(|| {
201            try_future!(Err(io::Error::new(io::ErrorKind::Other, "oh no!")));
202
203            future::ok::<_, CustomError>(()).into()
204        });
205
206        assert_eq!("oh no!", future.wait().err().unwrap().0.to_string());
207    }
208
209    #[test]
210    fn test_try_future_box() {
211        use std::io;
212
213        struct CustomError(io::Error);
214
215        impl From<io::Error> for CustomError {
216            fn from(err: io::Error) -> CustomError {
217                CustomError(err)
218            }
219        }
220
221        let future = future::lazy(|| {
222            try_future_box!(Err(io::Error::new(io::ErrorKind::Other, "oh no!")));
223
224            Box::new(future::ok::<_, CustomError>(()))
225        });
226
227        assert_eq!("oh no!", future.wait().err().unwrap().0.to_string());
228    }
229}