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}