ts_webapi/middleware/futures/
undefined.rs1use core::{
4 pin::Pin,
5 task::{Context, Poll, ready},
6};
7
8use http::{Request, Response, StatusCode};
9use http_body::Body;
10use pin_project_lite::pin_project;
11use tower_service::Service;
12
13pub trait DefiningFuture<B>:
15 Future<Output = Result<Request<B>, StatusCode>> + Send + 'static
16{
17}
18impl<B, F> DefiningFuture<B> for F where
19 F: Future<Output = Result<Request<B>, StatusCode>> + Send + 'static
20{
21}
22
23pin_project! {
24 pub struct UndefinedFuture<S, B> where S: Service<Request<B>>, {
26 #[pin]
27 state: State<S::Future, Pin<Box<dyn DefiningFuture<B>>>>,
28 service: S,
29 }
30}
31
32pin_project! {
33 #[project = StateProj]
34 enum State<SFut, DFut> {
35 Defining {
36 #[pin]
37 future: DFut,
38 },
39 Proceeding {
40 #[pin]
41 future: SFut,
42 },
43 }
44}
45
46impl<S, B> UndefinedFuture<S, B>
47where
48 S: Service<Request<B>>,
49{
50 pub fn define(future: Pin<Box<dyn DefiningFuture<B>>>, service: S) -> Self {
52 Self {
53 state: State::Defining { future },
54 service,
55 }
56 }
57
58 pub fn proceed(future: S::Future, service: S) -> Self {
60 Self {
61 state: State::Proceeding { future },
62 service,
63 }
64 }
65}
66
67impl<ResBody, S, B> Future for UndefinedFuture<S, B>
68where
69 ResBody: Body + Default,
70 S: Service<Request<B>, Response = Response<ResBody>>,
71{
72 type Output = Result<Response<ResBody>, S::Error>;
73
74 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
75 let mut this = self.project();
76
77 loop {
78 match this.state.as_mut().project() {
79 StateProj::Defining { future } => {
80 let auth = ready!(future.poll(cx));
81 match auth {
82 Ok(request) => {
83 let future = this.service.call(request);
84 this.state.set(State::Proceeding { future });
85 }
86 Err(status) => {
87 return Poll::Ready(Ok(Response::builder()
88 .status(status)
89 .body(ResBody::default())
90 .expect("error response should be valid response")));
91 }
92 };
93 }
94 StateProj::Proceeding { future: fut } => {
95 return Poll::Ready(Ok(ready!(fut.poll(cx))?));
96 }
97 }
98 }
99 }
100}