From d4ce90e2e6cf67a7d6e0e44784924b9d1cc67b31 Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Fri, 6 Aug 2021 01:15:10 +0200 Subject: [PATCH] Move response futures into their own modules (#130) It cleans up the docs to have the futures in their own modules as users are unlikely to look at them. Also matches the pattern used in tower https://docs.rs/tower/0.4.8/tower/util/future/index.html. Added re-exports to the old locations so its not a breaking change. --- src/extract/extractor_middleware.rs | 15 +++- src/routing.rs | 108 +++---------------------- src/routing/future.rs | 117 ++++++++++++++++++++++++++++ src/service/future.rs | 24 ++++++ src/service/mod.rs | 36 ++------- 5 files changed, 168 insertions(+), 132 deletions(-) create mode 100644 src/routing/future.rs diff --git a/src/extract/extractor_middleware.rs b/src/extract/extractor_middleware.rs index e7eba2ba..59564050 100644 --- a/src/extract/extractor_middleware.rs +++ b/src/extract/extractor_middleware.rs @@ -163,7 +163,7 @@ where { type Response = Response; type Error = S::Error; - type Future = ExtractorMiddlewareResponseFuture; + type Future = ResponseFuture; #[inline] fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { @@ -177,7 +177,7 @@ where (req, extracted) }); - ExtractorMiddlewareResponseFuture { + ResponseFuture { state: State::Extracting { future: extract_future, }, @@ -186,10 +186,17 @@ where } } +#[doc(hidden)] +#[deprecated( + since = "0.1.3", + note = "Use axum::extract::extractor_middleware::ResponseFuture" +)] +pub type ExtractorMiddlewareResponseFuture = ResponseFuture; + pin_project! { /// Response future for [`ExtractorMiddleware`]. #[allow(missing_debug_implementations)] - pub struct ExtractorMiddlewareResponseFuture + pub struct ResponseFuture where E: FromRequest, S: Service>, @@ -212,7 +219,7 @@ pin_project! { } } -impl Future for ExtractorMiddlewareResponseFuture +impl Future for ResponseFuture where E: FromRequest, S: Service, Response = Response>, diff --git a/src/routing.rs b/src/routing.rs index c141b014..d6d65888 100644 --- a/src/routing.rs +++ b/src/routing.rs @@ -9,26 +9,29 @@ use crate::{ }; use async_trait::async_trait; use bytes::Bytes; -use futures_util::future; use http::{Method, Request, Response, StatusCode, Uri}; -use pin_project_lite::pin_project; use regex::Regex; use std::{ borrow::Cow, convert::Infallible, fmt, - future::Future, marker::PhantomData, - pin::Pin, sync::Arc, task::{Context, Poll}, }; use tower::{ - util::{BoxService, Oneshot, ServiceExt}, + util::{BoxService, ServiceExt}, BoxError, Layer, Service, ServiceBuilder, }; use tower_http::map_response_body::MapResponseBodyLayer; +pub mod future; + +// for backwards compatibility +// TODO: remove these in 0.2 +#[doc(hidden)] +pub use self::future::{BoxRouteFuture, EmptyRouterFuture, RouteFuture}; + /// A filter that matches one or more HTTP methods. #[derive(Debug, Copy, Clone)] pub enum MethodFilter { @@ -385,63 +388,6 @@ where } } -pin_project! { - /// The response future for [`Route`]. - #[derive(Debug)] - pub struct RouteFuture - where - S: Service>, - F: Service> { - #[pin] inner: RouteFutureInner, - } -} - -impl RouteFuture -where - S: Service>, - F: Service>, -{ - pub(crate) fn a(a: Oneshot>) -> Self { - RouteFuture { - inner: RouteFutureInner::A { a }, - } - } - - pub(crate) fn b(b: Oneshot>) -> Self { - RouteFuture { - inner: RouteFutureInner::B { b }, - } - } -} - -pin_project! { - #[project = RouteFutureInnerProj] - #[derive(Debug)] - enum RouteFutureInner - where - S: Service>, - F: Service>, - { - A { #[pin] a: Oneshot> }, - B { #[pin] b: Oneshot> }, - } -} - -impl Future for RouteFuture -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 { - match self.project().inner.project() { - RouteFutureInnerProj::A { a } => a.poll(cx), - RouteFutureInnerProj::B { b } => b.poll(cx), - } - } -} - #[derive(Debug)] pub(crate) struct UrlParams(pub(crate) Vec<(ByteStr, ByteStr)>); @@ -520,17 +466,11 @@ impl Service> for EmptyRouter { let mut res = Response::new(crate::body::empty()); *res.status_mut() = self.status; EmptyRouterFuture { - future: future::ok(res), + future: futures_util::future::ok(res), } } } -opaque_future! { - /// Response future for [`EmptyRouter`]. - pub type EmptyRouterFuture = - future::Ready, E>>; -} - #[derive(Debug, Clone)] pub(crate) struct PathPattern(Arc); @@ -666,36 +606,6 @@ where } } -pin_project! { - /// The response future for [`BoxRoute`]. - pub struct BoxRouteFuture - where - E: Into, - { - #[pin] inner: Oneshot, Response, E>, Request>, Request>, - } -} - -impl Future for BoxRouteFuture -where - E: Into, -{ - type Output = Result, E>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.project().inner.poll(cx) - } -} - -impl fmt::Debug for BoxRouteFuture -where - E: Into, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("BoxRouteFuture").finish() - } -} - /// A [`Service`] created from a router by applying a Tower middleware. /// /// Created with [`RoutingDsl::layer`]. See that method for more details. diff --git a/src/routing/future.rs b/src/routing/future.rs new file mode 100644 index 00000000..3af64bec --- /dev/null +++ b/src/routing/future.rs @@ -0,0 +1,117 @@ +//! Future types. + +use crate::{body::BoxBody, buffer::MpscBuffer}; +use http::{Request, Response}; +use pin_project_lite::pin_project; +use std::{ + fmt, + future::Future, + pin::Pin, + task::{Context, Poll}, +}; +use tower::{ + util::{BoxService, Oneshot}, + BoxError, Service, +}; + +opaque_future! { + /// Response future for [`EmptyRouter`](super::EmptyRouter). + pub type EmptyRouterFuture = + futures_util::future::Ready, E>>; +} + +pin_project! { + /// The response future for [`BoxRoute`](super::BoxRoute). + pub struct BoxRouteFuture + where + E: Into, + { + #[pin] + pub(super) inner: Oneshot< + MpscBuffer< + BoxService, Response, E >, + Request + >, + Request, + >, + } +} + +impl Future for BoxRouteFuture +where + E: Into, +{ + type Output = Result, E>; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.project().inner.poll(cx) + } +} + +impl fmt::Debug for BoxRouteFuture +where + E: Into, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("BoxRouteFuture").finish() + } +} + +pin_project! { + /// The response future for [`Route`](super::Route). + #[derive(Debug)] + pub struct RouteFuture + where + S: Service>, + F: Service> + { + #[pin] + inner: RouteFutureInner, + } +} + +impl RouteFuture +where + S: Service>, + F: Service>, +{ + pub(crate) fn a(a: Oneshot>) -> Self { + RouteFuture { + inner: RouteFutureInner::A { a }, + } + } + + pub(crate) fn b(b: Oneshot>) -> Self { + RouteFuture { + inner: RouteFutureInner::B { b }, + } + } +} + +pin_project! { + #[project = RouteFutureInnerProj] + #[derive(Debug)] + enum RouteFutureInner + where + S: Service>, + F: Service>, + { + A { #[pin] a: Oneshot> }, + B { #[pin] b: Oneshot> }, + } +} + +impl Future for RouteFuture +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 { + match self.project().inner.project() { + RouteFutureInnerProj::A { a } => a.poll(cx), + RouteFutureInnerProj::B { b } => b.poll(cx), + } + } +} diff --git a/src/service/future.rs b/src/service/future.rs index 0fbd06dd..372587d4 100644 --- a/src/service/future.rs +++ b/src/service/future.rs @@ -50,3 +50,27 @@ where } } } + +pin_project! { + /// Response future for [`BoxResponseBody`]. + #[derive(Debug)] + pub struct BoxResponseBodyFuture { + #[pin] + pub(super) future: F, + } +} + +impl Future for BoxResponseBodyFuture +where + F: Future, E>>, + B: http_body::Body + Send + Sync + 'static, + B::Error: Into + Send + Sync + 'static, +{ + type Output = Result, E>; + + fn poll(self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let res = ready!(self.project().future.poll(cx))?; + let res = res.map(box_body); + Poll::Ready(Ok(res)) + } +} diff --git a/src/service/mod.rs b/src/service/mod.rs index 0faf25b7..401c3a84 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -87,18 +87,15 @@ //! [load shed]: tower::load_shed use crate::{ - body::{box_body, BoxBody}, + body::BoxBody, response::IntoResponse, routing::{EmptyRouter, MethodFilter, RouteFuture}, }; use bytes::Bytes; -use futures_util::ready; use http::{Request, Response}; -use pin_project_lite::pin_project; use std::{ convert::Infallible, fmt, - future::Future, marker::PhantomData, task::{Context, Poll}, }; @@ -106,6 +103,10 @@ use tower::{util::Oneshot, BoxError, Service, ServiceExt as _}; pub mod future; +// for backwards compatibility +#[doc(hidden)] +pub use future::BoxResponseBodyFuture; + /// Route requests to the given service regardless of the HTTP method. /// /// See [`get`] for an example. @@ -637,7 +638,7 @@ where { type Response = Response; type Error = S::Error; - type Future = BoxResponseBodyFuture>>; + type Future = future::BoxResponseBodyFuture>>; fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) @@ -645,29 +646,6 @@ where fn call(&mut self, req: Request) -> Self::Future { let fut = self.inner.clone().oneshot(req); - BoxResponseBodyFuture { future: fut } - } -} - -pin_project! { - /// Response future for [`BoxResponseBody`]. - #[derive(Debug)] - pub struct BoxResponseBodyFuture { - #[pin] future: F, - } -} - -impl Future for BoxResponseBodyFuture -where - F: Future, E>>, - B: http_body::Body + Send + Sync + 'static, - B::Error: Into + Send + Sync + 'static, -{ - type Output = Result, E>; - - fn poll(self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let res = ready!(self.project().future.poll(cx))?; - let res = res.map(box_body); - Poll::Ready(Ok(res)) + future::BoxResponseBodyFuture { future: fut } } }