From 6ce355cca3f3ea1418ea54de5d75aecd99ccf978 Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Sat, 7 Aug 2021 22:27:27 +0200 Subject: [PATCH] Add unique future types for all services (#157) So we can more easily change them in the future. --- CHANGELOG.md | 4 ++++ src/handler/future.rs | 36 ++++++++++++++++++++++++++++++++++-- src/handler/mod.rs | 8 +++++--- src/routing.rs | 10 ++++++---- src/routing/future.rs | 25 +++++++++++++++++++++++++ src/service/future.rs | 29 +++++++++++++++++++++++++++-- src/service/mod.rs | 8 +++++--- 7 files changed, 106 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dba2f7ee..03809b6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `UrlParamsRejection` - `InvalidUrlParam` - Removed `extract::UrlParams` and `extract::UrlParamsMap`. Use `extract::Path` instead +- The following services have new response future types: + - `service::OnMethod` + - `handler::OnMethod` + - `routing::Nested` # 0.1.3 (06. August, 2021) diff --git a/src/handler/future.rs b/src/handler/future.rs index f593fde1..8368b327 100644 --- a/src/handler/future.rs +++ b/src/handler/future.rs @@ -1,11 +1,43 @@ //! Handler future types. use crate::body::BoxBody; -use http::Response; -use std::convert::Infallible; +use http::{Request, Response}; +use pin_project_lite::pin_project; +use std::{ + convert::Infallible, + future::Future, + pin::Pin, + task::{Context, Poll}, +}; +use tower::Service; opaque_future! { /// The response future for [`IntoService`](super::IntoService). pub type IntoServiceFuture = futures_util::future::BoxFuture<'static, Result, Infallible>>; } + +pin_project! { + /// The response future for [`OnMethod`](super::OnMethod). + #[derive(Debug)] + pub struct OnMethodFuture + where + S: Service>, + F: Service> + { + #[pin] + pub(super) inner: crate::routing::future::RouteFuture, + } +} + +impl Future for OnMethodFuture +where + S: Service, Response = Response>, + F: Service, Response = Response, Error = S::Error>, +{ + type Output = Result, S::Error>; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.project().inner.poll(cx) + } +} diff --git a/src/handler/mod.rs b/src/handler/mod.rs index e0691b11..8f402f75 100644 --- a/src/handler/mod.rs +++ b/src/handler/mod.rs @@ -617,19 +617,21 @@ where { type Response = Response; type Error = Infallible; - type Future = RouteFuture; + type Future = future::OnMethodFuture; fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) } fn call(&mut self, req: Request) -> Self::Future { - if self.method.matches(req.method()) { + let f = if self.method.matches(req.method()) { let fut = self.svc.clone().oneshot(req); RouteFuture::a(fut) } else { let fut = self.fallback.clone().oneshot(req); RouteFuture::b(fut) - } + }; + + future::OnMethodFuture { inner: f } } } diff --git a/src/routing.rs b/src/routing.rs index 676e3457..820a1f8b 100644 --- a/src/routing.rs +++ b/src/routing.rs @@ -1,6 +1,6 @@ //! Routing between [`Service`]s. -use self::future::{BoxRouteFuture, EmptyRouterFuture, RouteFuture}; +use self::future::{BoxRouteFuture, EmptyRouterFuture, NestedFuture, RouteFuture}; use crate::{ body::{box_body, BoxBody}, buffer::MpscBuffer, @@ -898,7 +898,7 @@ where { type Response = Response; type Error = S::Error; - type Future = RouteFuture; + type Future = NestedFuture; fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) @@ -910,7 +910,7 @@ where req.extensions_mut().insert(original_uri); } - if let Some((prefix, captures)) = self.pattern.prefix_match(req.uri().path()) { + let f = if let Some((prefix, captures)) = self.pattern.prefix_match(req.uri().path()) { let without_prefix = strip_prefix(req.uri(), prefix); *req.uri_mut() = without_prefix; @@ -920,7 +920,9 @@ where } else { let fut = self.fallback.clone().oneshot(req); RouteFuture::b(fut) - } + }; + + NestedFuture { inner: f } } } diff --git a/src/routing/future.rs b/src/routing/future.rs index 3af64bec..3ed4ba66 100644 --- a/src/routing/future.rs +++ b/src/routing/future.rs @@ -115,3 +115,28 @@ where } } } + +pin_project! { + /// The response future for [`Nested`](super::Nested). + #[derive(Debug)] + pub struct NestedFuture + where + S: Service>, + F: Service> + { + #[pin] + pub(super) inner: RouteFuture, + } +} + +impl Future for NestedFuture +where + S: Service, Response = Response>, + F: Service, Response = Response, Error = S::Error>, +{ + type Output = Result, S::Error>; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.project().inner.poll(cx) + } +} diff --git a/src/service/future.rs b/src/service/future.rs index 372587d4..b4ac261e 100644 --- a/src/service/future.rs +++ b/src/service/future.rs @@ -6,14 +6,14 @@ use crate::{ }; use bytes::Bytes; use futures_util::ready; -use http::Response; +use http::{Request, Response}; use pin_project_lite::pin_project; use std::{ future::Future, pin::Pin, task::{Context, Poll}, }; -use tower::BoxError; +use tower::{BoxError, Service}; pin_project! { /// Response future for [`HandleError`](super::HandleError). @@ -74,3 +74,28 @@ where Poll::Ready(Ok(res)) } } + +pin_project! { + /// The response future for [`OnMethod`](super::OnMethod). + #[derive(Debug)] + pub struct OnMethodFuture + where + S: Service>, + F: Service> + { + #[pin] + pub(super) inner: crate::routing::future::RouteFuture, + } +} + +impl Future for OnMethodFuture +where + S: Service, Response = Response>, + F: Service, Response = Response, Error = S::Error>, +{ + type Output = Result, S::Error>; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.project().inner.poll(cx) + } +} diff --git a/src/service/mod.rs b/src/service/mod.rs index 1012db85..7995c656 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -439,20 +439,22 @@ where { type Response = Response; type Error = S::Error; - type Future = RouteFuture; + type Future = future::OnMethodFuture; fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) } fn call(&mut self, req: Request) -> Self::Future { - if self.method.matches(req.method()) { + let f = if self.method.matches(req.method()) { let fut = self.svc.clone().oneshot(req); RouteFuture::a(fut) } else { let fut = self.fallback.clone().oneshot(req); RouteFuture::b(fut) - } + }; + + future::OnMethodFuture { inner: f } } }