use pin_project_lite::pin_project; use std::{ future::Future, pin::Pin, task::{Context, Poll}, }; pin_project! { /// Future that resolves to the response or failure to connect. #[derive(Debug)] pub struct ResponseFuture { #[pin] inner: Inner, } } pin_project! { #[project = InnerProj] #[derive(Debug)] enum Inner { Future { #[pin] fut: F, }, Error { error: Option, }, } } impl Inner { fn future(fut: F) -> Self { Self::Future { fut } } fn error(error: Option) -> Self { Self::Error { error } } } impl ResponseFuture { pub(crate) fn new(inner: F) -> Self { ResponseFuture { inner: Inner::future(inner), } } pub(crate) fn error(error: E) -> Self { ResponseFuture { inner: Inner::error(Some(error)), } } } impl Future for ResponseFuture where F: Future>, E: Into, ME: Into, { type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let me = self.project(); match me.inner.project() { InnerProj::Future { fut } => fut.poll(cx).map_err(Into::into), InnerProj::Error { error } => { let e = error.take().expect("Polled after ready.").into(); Poll::Ready(Err(e)) } } } }