// TODO: Eventually to be replaced with tower_util::Oneshot. use pin_project_lite::pin_project; use tower_service::Service; use crate::common::{task, Future, Pin, Poll}; pub(crate) fn oneshot(svc: S, req: Req) -> Oneshot where S: Service, { Oneshot { state: State::NotReady { svc, req }, } } pin_project! { // A `Future` consuming a `Service` and request, waiting until the `Service` // is ready, and then calling `Service::call` with the request, and // waiting for that `Future`. #[allow(missing_debug_implementations)] pub struct Oneshot, Req> { #[pin] state: State, } } pin_project! { #[project = StateProj] #[project_replace = StateProjOwn] enum State, Req> { NotReady { svc: S, req: Req, }, Called { #[pin] fut: S::Future, }, Tmp, } } impl Future for Oneshot where S: Service, { type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll { let mut me = self.project(); loop { match me.state.as_mut().project() { StateProj::NotReady { ref mut svc, .. } => { ready!(svc.poll_ready(cx))?; // fallthrough out of the match's borrow } StateProj::Called { fut } => { return fut.poll(cx); } StateProj::Tmp => unreachable!(), } match me.state.as_mut().project_replace(State::Tmp) { StateProjOwn::NotReady { mut svc, req } => { me.state.set(State::Called { fut: svc.call(req) }); } _ => unreachable!(), } } } }