slim_futures/future/
and_then_async.rs

1use crate::future::map::Map;
2use crate::future::try_flatten::TryFlatten;
3use crate::support::{FromResidual, RawResidual, Try};
4use core::future::{Future, IntoFuture};
5use core::ops::ControlFlow;
6use core::pin::Pin;
7use core::task::{Context, Poll};
8use fn_traits::FnMut;
9use futures_core::FusedFuture;
10
11#[derive(Clone)]
12struct AndThenAsyncFn<F>
13where
14    F: ?Sized,
15{
16    f: F,
17}
18
19impl<T, F> FnMut<(T,)> for AndThenAsyncFn<F>
20where
21    T: Try,
22    F: FnMut<(T::Output,)> + ?Sized,
23    F::Output: IntoFuture,
24    <F::Output as IntoFuture>::Output: FromResidual<T::Residual>,
25{
26    type Output = RawResidual<T::Residual, F::Output>;
27
28    fn call_mut(&mut self, args: (T,)) -> Self::Output {
29        match args.0.branch() {
30            ControlFlow::Continue(output) => RawResidual::from_output(self.f.call_mut((output,))),
31            ControlFlow::Break(residual) => RawResidual::from_residual(residual),
32        }
33    }
34}
35
36pin_project_lite::pin_project! {
37    pub struct AndThenAsync<Fut, F>
38    where
39        Fut: Future,
40        Fut::Output: Try,
41        F: FnMut<(<Fut::Output as Try>::Output,)>,
42        F::Output: IntoFuture,
43        <F::Output as IntoFuture>::Output: FromResidual<<Fut::Output as Try>::Residual>,
44    {
45        #[pin]
46        inner: TryFlatten<Map<Fut, AndThenAsyncFn<F>>>
47    }
48}
49
50impl<Fut, F> AndThenAsync<Fut, F>
51where
52    Fut: Future,
53    Fut::Output: Try,
54    F: FnMut<(<Fut::Output as Try>::Output,)>,
55    F::Output: IntoFuture,
56    <F::Output as IntoFuture>::Output: FromResidual<<Fut::Output as Try>::Residual>,
57{
58    pub(crate) fn new(fut: Fut, f: F) -> Self {
59        Self {
60            inner: TryFlatten::new(Map::new(fut, AndThenAsyncFn { f })),
61        }
62    }
63}
64
65impl<Fut, F> Clone for AndThenAsync<Fut, F>
66where
67    Fut: Future + Clone,
68    Fut::Output: Try,
69    F: FnMut<(<Fut::Output as Try>::Output,)> + Clone,
70    F::Output: IntoFuture,
71    <F::Output as IntoFuture>::Output: FromResidual<<Fut::Output as Try>::Residual>,
72    <F::Output as IntoFuture>::IntoFuture: Clone,
73{
74    fn clone(&self) -> Self {
75        Self {
76            inner: self.inner.clone(),
77        }
78    }
79}
80
81impl<Fut, F> Future for AndThenAsync<Fut, F>
82where
83    Fut: Future,
84    Fut::Output: Try,
85    F: FnMut<(<Fut::Output as Try>::Output,)>,
86    F::Output: IntoFuture,
87    <F::Output as IntoFuture>::Output: FromResidual<<Fut::Output as Try>::Residual>,
88{
89    type Output = <F::Output as IntoFuture>::Output;
90
91    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
92        self.project().inner.poll(cx)
93    }
94}
95
96impl<Fut, F> FusedFuture for AndThenAsync<Fut, F>
97where
98    Fut: FusedFuture,
99    Fut::Output: Try,
100    F: FnMut<(<Fut::Output as Try>::Output,)>,
101    F::Output: IntoFuture,
102    <F::Output as IntoFuture>::Output: FromResidual<<Fut::Output as Try>::Residual>,
103    <F::Output as IntoFuture>::IntoFuture: FusedFuture,
104{
105    fn is_terminated(&self) -> bool {
106        self.inner.is_terminated()
107    }
108}
109
110#[cfg(test)]
111mod tests {
112    use crate::future::future_ext::FutureExt;
113    use futures_core::FusedFuture;
114    use futures_util::future::{self, Ready, TryFutureExt};
115    use std::mem;
116    use std::num::NonZeroU32;
117
118    fn ok_plus_3(value: u32) -> Ready<Result<u32, u32>> {
119        future::ok(value + 3)
120    }
121
122    fn err_plus_3(value: u32) -> Ready<Result<u32, u32>> {
123        future::err(value + 3)
124    }
125
126    #[tokio::test]
127    async fn test_and_then_async() {
128        assert_eq!(future::ok::<_, u32>(2).slim_and_then_async(ok_plus_3).await, Ok(5));
129        assert_eq!(future::ok::<_, u32>(2).slim_and_then_async(err_plus_3).await, Err(5));
130        assert_eq!(future::err::<_, u32>(2).slim_and_then_async(ok_plus_3).await, Err(2));
131        assert_eq!(future::err::<_, u32>(2).slim_and_then_async(err_plus_3).await, Err(2));
132    }
133
134    #[tokio::test]
135    async fn test_and_then_async_with_option() {
136        assert_eq!(
137            future::ready(Some(2))
138                .slim_and_then_async(|x| future::ready(Some(x + 3)))
139                .await,
140            Some(5),
141        );
142    }
143
144    #[tokio::test]
145    async fn test_and_then_async_clone() {
146        let future = future::ok::<u32, u32>(2).slim_and_then_async(ok_plus_3);
147        let future_2 = future.clone();
148
149        assert_eq!(future.await, Ok(5));
150        assert_eq!(future_2.await, Ok(5));
151    }
152
153    #[tokio::test]
154    async fn test_and_then_async_fused_future() {
155        let mut future = future::ok::<u32, u32>(2).slim_and_then_async(ok_plus_3);
156
157        assert!(!future.is_terminated());
158        assert_eq!(future.by_ref().await, Ok(5));
159        assert!(future.is_terminated());
160    }
161
162    #[tokio::test]
163    async fn test_and_then_async_is_slim() {
164        let make_base_future = || crate::future::ok_by_copy::<_, u32>(NonZeroU32::new(2).unwrap()).slim_map_ok(drop);
165        let base_future = make_base_future();
166        let future_1 = make_base_future().slim_and_then_async(crate::future::ok_by_copy::<_, u32>);
167        let future_2 = make_base_future().and_then(crate::future::ok_by_copy);
168
169        assert_eq!(mem::size_of_val(&base_future), mem::size_of_val(&future_1));
170        assert!(mem::size_of_val(&future_1) < mem::size_of_val(&future_2));
171        assert_eq!(base_future.await, Ok(()));
172        assert_eq!(future_1.await, Ok(()));
173        assert_eq!(future_2.await, Ok(()));
174    }
175}