From aa822574c82a709335cd52a83d8bad713e08fd53 Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Sun, 25 Mar 2018 23:22:17 +0200 Subject: [PATCH] Add FutureExt::inspect_err method Fixes #898 --- futures-util/src/future/inspect.rs | 2 +- futures-util/src/future/inspect_err.rs | 41 ++++++++++++++++++++++++++ futures-util/src/future/mod.rs | 30 ++++++++++++++++++- 3 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 futures-util/src/future/inspect_err.rs diff --git a/futures-util/src/future/inspect.rs b/futures-util/src/future/inspect.rs index 986763f232..d0e1ba6416 100644 --- a/futures-util/src/future/inspect.rs +++ b/futures-util/src/future/inspect.rs @@ -3,7 +3,7 @@ use futures_core::task; /// Do something with the item of a future, passing it on. /// -/// This is created by the `Future::inspect` method. +/// This is created by the [`FutureExt::inspect`] method. #[derive(Debug)] #[must_use = "futures do nothing unless polled"] pub struct Inspect where A: Future { diff --git a/futures-util/src/future/inspect_err.rs b/futures-util/src/future/inspect_err.rs new file mode 100644 index 0000000000..ea0c312af5 --- /dev/null +++ b/futures-util/src/future/inspect_err.rs @@ -0,0 +1,41 @@ +use futures_core::{Future, Poll, Async}; +use futures_core::task; + +/// Do something with the error of a future, passing it on. +/// +/// This is created by the [`FutureExt::inspect_err`] method. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct InspectErr where A: Future { + future: A, + f: Option, +} + +pub fn new(future: A, f: F) -> InspectErr + where A: Future, + F: FnOnce(&A::Error), +{ + InspectErr { + future: future, + f: Some(f), + } +} + +impl Future for InspectErr + where A: Future, + F: FnOnce(&A::Error), +{ + type Item = A::Item; + type Error = A::Error; + + fn poll(&mut self, cx: &mut task::Context) -> Poll { + match self.future.poll(cx) { + Ok(Async::Pending) => Ok(Async::Pending), + Ok(Async::Ready(e)) => Ok(Async::Ready(e)), + Err(e) => { + (self.f.take().expect("cannot poll InspectErr twice"))(&e); + Err(e) + }, + } + } +} diff --git a/futures-util/src/future/mod.rs b/futures-util/src/future/mod.rs index 4e94474ac8..0d40a2780c 100644 --- a/futures-util/src/future/mod.rs +++ b/futures-util/src/future/mod.rs @@ -31,6 +31,7 @@ mod or_else; mod select; mod then; mod inspect; +mod inspect_err; mod recover; // impl details @@ -49,6 +50,7 @@ pub use self::or_else::OrElse; pub use self::select::Select; pub use self::then::Then; pub use self::inspect::Inspect; +pub use self::inspect_err::InspectErr; pub use self::recover::Recover; pub use either::Either; @@ -690,7 +692,7 @@ pub trait FutureExt: Future { /// /// When using futures, you'll often chain several of them together. /// While working on such code, you might want to check out what's happening at - /// various parts in the pipeline. To do that, insert a call to inspect(). + /// various parts in the pipeline. To do that, insert a call to `inspect`. /// /// # Examples /// @@ -714,6 +716,32 @@ pub trait FutureExt: Future { assert_future::(inspect::new(self, f)) } + /// Do something with the error of a future, passing it on. + /// + /// When using futures, you'll often chain several of them together. + /// While working on such code, you might want to check out what's happening + /// to the errors at various parts in the pipeline. To do that, insert a + /// call to `inspect_err`. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// use futures::prelude::*; + /// use futures::future; + /// use futures::executor::block_on; + /// + /// let future = future::err::(1); + /// let new_future = future.inspect_err(|&x| println!("about to error: {}", x)); + /// assert_eq!(block_on(new_future), Err(1)); + /// ``` + fn inspect_err(self, f: F) -> InspectErr + where F: FnOnce(&Self::Error) -> (), + Self: Sized, + { + assert_future::(inspect_err::new(self, f)) + } + /// Catches unwinding panics while polling the future. /// /// In general, panics within a future can propagate all the way out to the