Skip to main content

tower/filter/
future.rs

1//! Future types
2
3use 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    /// Filtered response future from [`AsyncFilter`] services.
15    ///
16    /// [`AsyncFilter`]: crate::filter::AsyncFilter
17    #[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        // Inner service
27        service: S,
28    }
29}
30
31opaque_future! {
32    /// Filtered response future from [`Filter`] services.
33    ///
34    /// [`Filter`]: crate::filter::Filter
35    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        /// Waiting for the predicate future
47        Check {
48            #[pin]
49            check: F
50        },
51        /// Waiting for the response future
52        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}