1use super::AsyncPredicate;
4use crate::BoxError;
5use pin_project_lite::pin_project;
6use std::{
7 future::Future,
8 pin::Pin,
9 task::{ready, Context, Poll},
10};
11use tower_service::Service;
12
13pin_project! {
14 #[derive(Debug)]
18 pub struct AsyncResponseFuture<P, S, Request>
19 where
20 P: AsyncPredicate<Request>,
21 S: Service<P::Request>,
22 {
23 #[pin]
24 state: State<P::Future, S::Future>,
25
26 service: S,
28 }
29}
30
31opaque_future! {
32 pub type ResponseFuture<R, F> =
36 futures_util::future::Either<
37 std::future::Ready<Result<R, crate::BoxError>>,
38 futures_util::future::ErrInto<F, crate::BoxError>
39 >;
40}
41
42pin_project! {
43 #[project = StateProj]
44 #[derive(Debug)]
45 enum State<F, G> {
46 Check {
48 #[pin]
49 check: F
50 },
51 WaitResponse {
53 #[pin]
54 response: G
55 },
56 }
57}
58
59impl<P, S, Request> AsyncResponseFuture<P, S, Request>
60where
61 P: AsyncPredicate<Request>,
62 S: Service<P::Request>,
63 S::Error: Into<BoxError>,
64{
65 pub(crate) fn new(check: P::Future, service: S) -> Self {
66 Self {
67 state: State::Check { check },
68 service,
69 }
70 }
71}
72
73impl<P, S, Request> Future for AsyncResponseFuture<P, S, Request>
74where
75 P: AsyncPredicate<Request>,
76 S: Service<P::Request>,
77 S::Error: Into<crate::BoxError>,
78{
79 type Output = Result<S::Response, crate::BoxError>;
80
81 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
82 let mut this = self.project();
83
84 loop {
85 match this.state.as_mut().project() {
86 StateProj::Check { mut check } => {
87 let request = ready!(check.as_mut().poll(cx))?;
88 let response = this.service.call(request);
89 this.state.set(State::WaitResponse { response });
90 }
91 StateProj::WaitResponse { response } => {
92 return response.poll(cx).map_err(Into::into);
93 }
94 }
95 }
96 }
97}