1use core::pin::Pin;
2use futures_core::future::{FusedFuture, Future, TryFuture};
3use futures_core::ready;
4use futures_core::task::{Context, Poll};
5use pin_project_lite::pin_project;
6
7pin_project! {
8 #[project = TryFlattenErrProj]
9 #[derive(Debug)]
10 pub enum TryFlattenErr<Fut1, Fut2> {
11 First { #[pin] f: Fut1 },
12 Second { #[pin] f: Fut2 },
13 Empty,
14 }
15}
16
17impl<Fut1, Fut2> TryFlattenErr<Fut1, Fut2> {
18 pub(crate) fn new(future: Fut1) -> Self {
19 Self::First { f: future }
20 }
21}
22
23impl<Fut> FusedFuture for TryFlattenErr<Fut, Fut::Error>
24where
25 Fut: TryFuture,
26 Fut::Error: TryFuture<Ok = Fut::Ok>,
27{
28 fn is_terminated(&self) -> bool {
29 match self {
30 Self::Empty => true,
31 _ => false,
32 }
33 }
34}
35
36impl<Fut> Future for TryFlattenErr<Fut, Fut::Error>
37where
38 Fut: TryFuture,
39 Fut::Error: TryFuture<Ok = Fut::Ok>,
40{
41 type Output = Result<Fut::Ok, <Fut::Error as TryFuture>::Error>;
42
43 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
44 Poll::Ready(loop {
45 match self.as_mut().project() {
46 TryFlattenErrProj::First { f } => match ready!(f.try_poll(cx)) {
47 Err(f) => self.set(Self::Second { f }),
48 Ok(e) => {
49 self.set(Self::Empty);
50 break Ok(e);
51 }
52 },
53 TryFlattenErrProj::Second { f } => {
54 let output = ready!(f.try_poll(cx));
55 self.set(Self::Empty);
56 break output;
57 }
58 TryFlattenErrProj::Empty => panic!("TryFlattenErr polled after completion"),
59 }
60 })
61 }
62}
63