diff options
Diffstat (limited to 'third_party/rust/hyper/src/service/oneshot.rs')
-rw-r--r-- | third_party/rust/hyper/src/service/oneshot.rs | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/third_party/rust/hyper/src/service/oneshot.rs b/third_party/rust/hyper/src/service/oneshot.rs new file mode 100644 index 0000000000..2697af8f4c --- /dev/null +++ b/third_party/rust/hyper/src/service/oneshot.rs @@ -0,0 +1,73 @@ +// 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<S, Req>(svc: S, req: Req) -> Oneshot<S, Req> +where + S: Service<Req>, +{ + 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<S: Service<Req>, Req> { + #[pin] + state: State<S, Req>, + } +} + +pin_project! { + #[project = StateProj] + #[project_replace = StateProjOwn] + enum State<S: Service<Req>, Req> { + NotReady { + svc: S, + req: Req, + }, + Called { + #[pin] + fut: S::Future, + }, + Tmp, + } +} + +impl<S, Req> Future for Oneshot<S, Req> +where + S: Service<Req>, +{ + type Output = Result<S::Response, S::Error>; + + fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { + 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!(), + } + } + } +} |