Skip to content

Commit de1b49f

Browse files
taiki-ecramertj
authored andcommitted
Add TryFutureExt::{inspect_ok, inspect_err}
1 parent f775ea6 commit de1b49f

File tree

5 files changed

+158
-2
lines changed

5 files changed

+158
-2
lines changed

futures-util/src/future/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ pub trait FutureExt: Future {
373373
/// # });
374374
/// ```
375375
fn inspect<F>(self, f: F) -> Inspect<Self, F>
376-
where F: FnOnce(&Self::Output) -> (),
376+
where F: FnOnce(&Self::Output),
377377
Self: Sized,
378378
{
379379
assert_future::<Self::Output, _>(Inspect::new(self, f))
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use core::pin::Pin;
2+
use futures_core::future::{FusedFuture, Future, TryFuture};
3+
use futures_core::task::{Context, Poll};
4+
use pin_utils::{unsafe_pinned, unsafe_unpinned};
5+
6+
/// Future for the [`inspect_err`](super::TryFutureExt::inspect_err) method.
7+
#[derive(Debug)]
8+
#[must_use = "futures do nothing unless you `.await` or poll them"]
9+
pub struct InspectErr<Fut, F> {
10+
future: Fut,
11+
f: Option<F>,
12+
}
13+
14+
impl<Fut: Unpin, F> Unpin for InspectErr<Fut, F> {}
15+
16+
impl<Fut, F> InspectErr<Fut, F>
17+
where
18+
Fut: TryFuture,
19+
F: FnOnce(&Fut::Error),
20+
{
21+
unsafe_pinned!(future: Fut);
22+
unsafe_unpinned!(f: Option<F>);
23+
24+
pub(super) fn new(future: Fut, f: F) -> Self {
25+
Self { future, f: Some(f) }
26+
}
27+
}
28+
29+
impl<Fut: FusedFuture, F> FusedFuture for InspectErr<Fut, F> {
30+
fn is_terminated(&self) -> bool {
31+
self.future.is_terminated()
32+
}
33+
}
34+
35+
impl<Fut, F> Future for InspectErr<Fut, F>
36+
where
37+
Fut: TryFuture,
38+
F: FnOnce(&Fut::Error),
39+
{
40+
type Output = Result<Fut::Ok, Fut::Error>;
41+
42+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
43+
let e = ready!(self.as_mut().future().try_poll(cx));
44+
if let Err(e) = &e {
45+
self.as_mut().f().take().expect("cannot poll InspectErr twice")(e);
46+
}
47+
Poll::Ready(e)
48+
}
49+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use core::pin::Pin;
2+
use futures_core::future::{FusedFuture, Future, TryFuture};
3+
use futures_core::task::{Context, Poll};
4+
use pin_utils::{unsafe_pinned, unsafe_unpinned};
5+
6+
/// Future for the [`inspect_ok`](super::TryFutureExt::inspect_ok) method.
7+
#[derive(Debug)]
8+
#[must_use = "futures do nothing unless you `.await` or poll them"]
9+
pub struct InspectOk<Fut, F> {
10+
future: Fut,
11+
f: Option<F>,
12+
}
13+
14+
impl<Fut: Unpin, F> Unpin for InspectOk<Fut, F> {}
15+
16+
impl<Fut, F> InspectOk<Fut, F>
17+
where
18+
Fut: TryFuture,
19+
F: FnOnce(&Fut::Ok),
20+
{
21+
unsafe_pinned!(future: Fut);
22+
unsafe_unpinned!(f: Option<F>);
23+
24+
pub(super) fn new(future: Fut, f: F) -> Self {
25+
Self { future, f: Some(f) }
26+
}
27+
}
28+
29+
impl<Fut: FusedFuture, F> FusedFuture for InspectOk<Fut, F> {
30+
fn is_terminated(&self) -> bool {
31+
self.future.is_terminated()
32+
}
33+
}
34+
35+
impl<Fut, F> Future for InspectOk<Fut, F>
36+
where
37+
Fut: TryFuture,
38+
F: FnOnce(&Fut::Ok),
39+
{
40+
type Output = Result<Fut::Ok, Fut::Error>;
41+
42+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
43+
let e = ready!(self.as_mut().future().try_poll(cx));
44+
if let Ok(e) = &e {
45+
self.as_mut().f().take().expect("cannot poll InspectOk twice")(e);
46+
}
47+
Poll::Ready(e)
48+
}
49+
}

futures-util/src/try_future/mod.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ pub use self::err_into::ErrInto;
4040
mod flatten_sink;
4141
pub use self::flatten_sink::FlattenSink;
4242

43+
mod inspect_ok;
44+
pub use self::inspect_ok::InspectOk;
45+
46+
mod inspect_err;
47+
pub use self::inspect_err::InspectErr;
48+
4349
mod into_future;
4450
pub use self::into_future::IntoFuture;
4551

@@ -322,6 +328,58 @@ pub trait TryFutureExt: TryFuture {
322328
OrElse::new(self, f)
323329
}
324330

331+
/// Do something with the success value of a future before passing it on.
332+
///
333+
/// When using futures, you'll often chain several of them together. While
334+
/// working on such code, you might want to check out what's happening at
335+
/// various parts in the pipeline, without consuming the intermediate
336+
/// value. To do that, insert a call to `inspect_ok`.
337+
///
338+
/// # Examples
339+
///
340+
/// ```
341+
/// #![feature(async_await)]
342+
/// # futures::executor::block_on(async {
343+
/// use futures::future::{self, TryFutureExt};
344+
///
345+
/// let future = future::ok::<_, ()>(1);
346+
/// let new_future = future.inspect_ok(|&x| println!("about to resolve: {}", x));
347+
/// assert_eq!(new_future.await, Ok(1));
348+
/// # });
349+
/// ```
350+
fn inspect_ok<F>(self, f: F) -> InspectOk<Self, F>
351+
where F: FnOnce(&Self::Ok),
352+
Self: Sized,
353+
{
354+
InspectOk::new(self, f)
355+
}
356+
357+
/// Do something with the error value of a future before passing it on.
358+
///
359+
/// When using futures, you'll often chain several of them together. While
360+
/// working on such code, you might want to check out what's happening at
361+
/// various parts in the pipeline, without consuming the intermediate
362+
/// value. To do that, insert a call to `inspect_err`.
363+
///
364+
/// # Examples
365+
///
366+
/// ```
367+
/// #![feature(async_await)]
368+
/// # futures::executor::block_on(async {
369+
/// use futures::future::{self, TryFutureExt};
370+
///
371+
/// let future = future::err::<(), _>(1);
372+
/// let new_future = future.inspect_err(|&x| println!("about to error: {}", x));
373+
/// assert_eq!(new_future.await, Err(1));
374+
/// # });
375+
/// ```
376+
fn inspect_err<F>(self, f: F) -> InspectErr<Self, F>
377+
where F: FnOnce(&Self::Error),
378+
Self: Sized,
379+
{
380+
InspectErr::new(self, f)
381+
}
382+
325383
/// Flatten the execution of this future when the successful result of this
326384
/// future is a stream.
327385
///

futures/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ pub mod future {
251251

252252
TryFutureExt,
253253
AndThen, ErrInto, FlattenSink, IntoFuture, MapErr, MapOk, OrElse,
254-
TryFlattenStream, UnwrapOrElse,
254+
InspectOk, InspectErr, TryFlattenStream, UnwrapOrElse,
255255
};
256256

257257
#[cfg(feature = "never-type")]

0 commit comments

Comments
 (0)