//! Future types use super::error::{self, Error}; use futures_core::ready; use pin_project::{pin_project, project}; use std::{ future::Future, pin::Pin, task::{Context, Poll}, }; use tower_service::Service; /// Filtered response future #[pin_project] #[derive(Debug)] pub struct ResponseFuture where S: Service, { #[pin] /// Response future state state: State, #[pin] /// Predicate future check: T, /// Inner service service: S, } #[pin_project] #[derive(Debug)] enum State { Check(Option), WaitResponse(#[pin] U), } impl ResponseFuture where F: Future>, S: Service, S::Error: Into, { pub(crate) fn new(request: Request, check: F, service: S) -> Self { ResponseFuture { state: State::Check(Some(request)), check, service, } } } impl Future for ResponseFuture where F: Future>, S: Service, S::Error: Into, { type Output = Result; #[project] fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let mut this = self.project(); loop { #[project] match this.state.as_mut().project() { State::Check(request) => { let request = request .take() .expect("we either give it back or leave State::Check once we take"); // Poll predicate match this.check.as_mut().poll(cx)? { Poll::Ready(_) => { let response = this.service.call(request); this.state.set(State::WaitResponse(response)); } Poll::Pending => { this.state.set(State::Check(Some(request))); return Poll::Pending; } } } State::WaitResponse(response) => { return Poll::Ready(ready!(response.poll(cx)).map_err(Error::inner)); } } } } }