From 7620f17edcf34bee055b2a90a02c5572271f1acc Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Sun, 6 Jun 2021 22:41:52 +0200 Subject: [PATCH] Remove some needless type params --- src/extract/mod.rs | 54 ++++++-------------- src/extract/rejection.rs | 28 +++++++++- src/handler.rs | 107 ++++++++++++++++++--------------------- src/lib.rs | 2 +- src/response.rs | 53 ++++++++++--------- src/routing.rs | 6 +-- src/service.rs | 10 ++-- src/tests.rs | 11 ++-- 8 files changed, 132 insertions(+), 139 deletions(-) diff --git a/src/extract/mod.rs b/src/extract/mod.rs index 8c19fe59..e68c45b3 100644 --- a/src/extract/mod.rs +++ b/src/extract/mod.rs @@ -3,8 +3,8 @@ use async_trait::async_trait; use bytes::Bytes; use http::{header, Request, Response}; use rejection::{ - BodyAlreadyTaken, FailedToBufferBody, InvalidJsonBody, InvalidUtf8, LengthRequired, - MissingExtension, MissingJsonContentType, MissingRouteParams, PayloadTooLarge, + BodyAlreadyTaken, FailedToBufferBody, InvalidJsonBody, InvalidUrlParam, InvalidUtf8, + LengthRequired, MissingExtension, MissingJsonContentType, MissingRouteParams, PayloadTooLarge, QueryStringMissing, }; use serde::de::DeserializeOwned; @@ -13,16 +13,16 @@ use std::{collections::HashMap, convert::Infallible, str::FromStr}; pub mod rejection; #[async_trait] -pub trait FromRequest: Sized { - type Rejection: IntoResponse; +pub trait FromRequest: Sized { + type Rejection: IntoResponse; async fn from_request(req: &mut Request) -> Result; } #[async_trait] -impl FromRequest for Option +impl FromRequest for Option where - T: FromRequest, + T: FromRequest, { type Rejection = Infallible; @@ -35,7 +35,7 @@ where pub struct Query(pub T); #[async_trait] -impl FromRequest for Query +impl FromRequest for Query where T: DeserializeOwned, { @@ -52,7 +52,7 @@ where pub struct Json(pub T); #[async_trait] -impl FromRequest for Json +impl FromRequest for Json where T: DeserializeOwned, { @@ -98,7 +98,7 @@ fn has_content_type(req: &Request, expected_content_type: &str) -> bool { pub struct Extension(pub T); #[async_trait] -impl FromRequest for Extension +impl FromRequest for Extension where T: Clone + Send + Sync + 'static, { @@ -116,7 +116,7 @@ where } #[async_trait] -impl FromRequest for Bytes { +impl FromRequest for Bytes { type Rejection = Response; async fn from_request(req: &mut Request) -> Result { @@ -132,7 +132,7 @@ impl FromRequest for Bytes { } #[async_trait] -impl FromRequest for String { +impl FromRequest for String { type Rejection = Response; async fn from_request(req: &mut Request) -> Result { @@ -153,7 +153,7 @@ impl FromRequest for String { } #[async_trait] -impl FromRequest for Body { +impl FromRequest for Body { type Rejection = BodyAlreadyTaken; async fn from_request(req: &mut Request) -> Result { @@ -165,7 +165,7 @@ impl FromRequest for Body { pub struct BytesMaxLength(pub Bytes); #[async_trait] -impl FromRequest for BytesMaxLength { +impl FromRequest for BytesMaxLength { type Rejection = Response; async fn from_request(req: &mut Request) -> Result { @@ -208,7 +208,7 @@ impl UrlParamsMap { } #[async_trait] -impl FromRequest for UrlParamsMap { +impl FromRequest for UrlParamsMap { type Rejection = MissingRouteParams; async fn from_request(req: &mut Request) -> Result { @@ -224,30 +224,6 @@ impl FromRequest for UrlParamsMap { } } -#[derive(Debug)] -pub struct InvalidUrlParam { - type_name: &'static str, -} - -impl InvalidUrlParam { - fn new() -> Self { - InvalidUrlParam { - type_name: std::any::type_name::(), - } - } -} - -impl IntoResponse for InvalidUrlParam { - fn into_response(self) -> http::Response { - let mut res = http::Response::new(Body::from(format!( - "Invalid URL param. Expected something of type `{}`", - self.type_name - ))); - *res.status_mut() = http::StatusCode::BAD_REQUEST; - res - } -} - pub struct UrlParams(pub T); macro_rules! impl_parse_url { @@ -255,7 +231,7 @@ macro_rules! impl_parse_url { ( $head:ident, $($tail:ident),* $(,)? ) => { #[async_trait] - impl<$head, $($tail,)*> FromRequest for UrlParams<($head, $($tail,)*)> + impl<$head, $($tail,)*> FromRequest for UrlParams<($head, $($tail,)*)> where $head: FromStr + Send, $( $tail: FromStr + Send, )* diff --git a/src/extract/rejection.rs b/src/extract/rejection.rs index 48284def..ce85973b 100644 --- a/src/extract/rejection.rs +++ b/src/extract/rejection.rs @@ -10,7 +10,7 @@ macro_rules! define_rejection { #[derive(Debug)] pub struct $name(pub(super) ()); - impl IntoResponse for $name { + impl IntoResponse for $name { fn into_response(self) -> http::Response { let mut res = http::Response::new(Body::from($body)); *res.status_mut() = http::StatusCode::$status; @@ -36,7 +36,7 @@ macro_rules! define_rejection { } } - impl IntoResponse for $name { + impl IntoResponse for $name { fn into_response(self) -> http::Response { let mut res = http::Response::new(Body::from(format!(concat!($body, ": {}"), self.0))); @@ -106,3 +106,27 @@ define_rejection! { #[body = "Cannot have two request body extractors for a single handler"] pub struct BodyAlreadyTaken(()); } + +#[derive(Debug)] +pub struct InvalidUrlParam { + type_name: &'static str, +} + +impl InvalidUrlParam { + pub(super) fn new() -> Self { + InvalidUrlParam { + type_name: std::any::type_name::(), + } + } +} + +impl IntoResponse for InvalidUrlParam { + fn into_response(self) -> http::Response { + let mut res = http::Response::new(Body::from(format!( + "Invalid URL param. Expected something of type `{}`", + self.type_name + ))); + *res.status_mut() = http::StatusCode::BAD_REQUEST; + res + } +} diff --git a/src/handler.rs b/src/handler.rs index 67d4fb78..0865800f 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -17,23 +17,23 @@ use std::{ }; use tower::{util::Oneshot, BoxError, Layer, Service, ServiceExt}; -pub fn get(handler: H) -> OnMethod, EmptyRouter> +pub fn get(handler: H) -> OnMethod, EmptyRouter> where - H: Handler, + H: Handler, { on(MethodFilter::Get, handler) } -pub fn post(handler: H) -> OnMethod, EmptyRouter> +pub fn post(handler: H) -> OnMethod, EmptyRouter> where - H: Handler, + H: Handler, { on(MethodFilter::Post, handler) } -pub fn on(method: MethodFilter, handler: H) -> OnMethod, EmptyRouter> +pub fn on(method: MethodFilter, handler: H) -> OnMethod, EmptyRouter> where - H: Handler, + H: Handler, { OnMethod { method, @@ -51,41 +51,37 @@ mod sealed { } #[async_trait] -pub trait Handler: Sized { - type Response: IntoResponse; - +pub trait Handler: Sized { // This seals the trait. We cannot use the regular "sealed super trait" approach // due to coherence. #[doc(hidden)] type Sealed: sealed::HiddentTrait; - async fn call(self, req: Request) -> Response; + async fn call(self, req: Request) -> Response; fn layer(self, layer: L) -> Layered where - L: Layer>, + L: Layer>, { Layered::new(layer.layer(IntoService::new(self))) } - fn into_service(self) -> IntoService { + fn into_service(self) -> IntoService { IntoService::new(self) } } #[async_trait] -impl Handler for F +impl Handler<()> for F where F: FnOnce(Request) -> Fut + Send + Sync, Fut: Future + Send, - Res: IntoResponse, + Res: IntoResponse, { - type Response = Res; - type Sealed = sealed::Hidden; - async fn call(self, req: Request) -> Response { - self(req).await.into_response() + async fn call(self, req: Request) -> Response { + self(req).await.into_response().map(BoxBody::new) } } @@ -95,34 +91,32 @@ macro_rules! impl_handler { ( $head:ident, $($tail:ident),* $(,)? ) => { #[async_trait] #[allow(non_snake_case)] - impl Handler for F + impl Handler<($head, $($tail,)*)> for F where F: FnOnce(Request, $head, $($tail,)*) -> Fut + Send + Sync, Fut: Future + Send, - Res: IntoResponse, - $head: FromRequest + Send, - $( $tail: FromRequest + Send, )* + Res: IntoResponse, + $head: FromRequest + Send, + $( $tail: FromRequest + Send, )* { - type Response = Res; - type Sealed = sealed::Hidden; - async fn call(self, mut req: Request) -> Response { + async fn call(self, mut req: Request) -> Response { let $head = match $head::from_request(&mut req).await { Ok(value) => value, - Err(rejection) => return rejection.into_response(), + Err(rejection) => return rejection.into_response().map(BoxBody::new), }; $( let $tail = match $tail::from_request(&mut req).await { Ok(value) => value, - Err(rejection) => return rejection.into_response(), + Err(rejection) => return rejection.into_response().map(BoxBody::new), }; )* let res = self(req, $head, $($tail,)*).await; - res.into_response() + res.into_response().map(BoxBody::new) } } @@ -147,27 +141,26 @@ where } #[async_trait] -impl Handler for Layered +impl Handler for Layered where S: Service, Response = Response> + Send, - S::Error: IntoResponse, - S::Response: IntoResponse, + // S::Response: IntoResponse, + S::Error: IntoResponse, S::Future: Send, + B: http_body::Body + Send + Sync + 'static, + B::Error: Into + Send + Sync + 'static, { - type Response = S::Response; - type Sealed = sealed::Hidden; - async fn call(self, req: Request) -> Self::Response { - // TODO(david): add tests for nesting services + async fn call(self, req: Request) -> Response { match self .svc .oneshot(req) .await .map_err(IntoResponse::into_response) { - Ok(res) => res, - Err(res) => res, + Ok(res) => res.map(BoxBody::new), + Err(res) => res.map(BoxBody::new), } } } @@ -184,21 +177,19 @@ impl Layered { where S: Service, Response = Response>, F: FnOnce(S::Error) -> Res, - Res: IntoResponse, - B: http_body::Body + Send + Sync + 'static, - B::Error: Into + Send + Sync + 'static, + Res: IntoResponse, { let svc = HandleError::new(self.svc, f); Layered::new(svc) } } -pub struct IntoService { +pub struct IntoService { handler: H, - _marker: PhantomData (B, T)>, + _marker: PhantomData T>, } -impl IntoService { +impl IntoService { fn new(handler: H) -> Self { Self { handler, @@ -207,7 +198,7 @@ impl IntoService { } } -impl Clone for IntoService +impl Clone for IntoService where H: Clone, { @@ -219,12 +210,11 @@ where } } -impl Service> for IntoService +impl Service> for IntoService where - H: Handler + Clone + Send + 'static, - H::Response: 'static, + H: Handler + Clone + Send + 'static, { - type Response = Response; + type Response = Response; type Error = Infallible; type Future = future::BoxFuture<'static, Result>; @@ -237,7 +227,10 @@ where fn call(&mut self, req: Request) -> Self::Future { let handler = self.handler.clone(); - Box::pin(async move { Ok(Handler::call(handler, req).await) }) + Box::pin(async move { + let res = Handler::call(handler, req).await; + Ok(res) + }) } } @@ -249,27 +242,23 @@ pub struct OnMethod { } impl OnMethod { - pub fn get(self, handler: H) -> OnMethod, Self> + pub fn get(self, handler: H) -> OnMethod, Self> where - H: Handler, + H: Handler, { self.on(MethodFilter::Get, handler) } - pub fn post(self, handler: H) -> OnMethod, Self> + pub fn post(self, handler: H) -> OnMethod, Self> where - H: Handler, + H: Handler, { self.on(MethodFilter::Post, handler) } - pub fn on( - self, - method: MethodFilter, - handler: H, - ) -> OnMethod, Self> + pub fn on(self, method: MethodFilter, handler: H) -> OnMethod, Self> where - H: Handler, + H: Handler, { OnMethod { method, diff --git a/src/lib.rs b/src/lib.rs index 37bcd423..5d07b600 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -637,7 +637,7 @@ pub trait ServiceExt: Service, Response = Response> { where Self: Sized, F: FnOnce(Self::Error) -> Res, - Res: IntoResponse, + Res: IntoResponse, B: http_body::Body + Send + Sync + 'static, B::Error: Into + Send + Sync + 'static, { diff --git a/src/response.rs b/src/response.rs index 3c821bc4..6539cad2 100644 --- a/src/response.rs +++ b/src/response.rs @@ -5,29 +5,28 @@ use serde::Serialize; use std::{borrow::Cow, convert::Infallible}; use tower::util::Either; -// TODO(david): can we change this to not be generic over the body and just use hyper::Body? -pub trait IntoResponse { - fn into_response(self) -> Response; +pub trait IntoResponse { + fn into_response(self) -> Response; } -impl IntoResponse for () { +impl IntoResponse for () { fn into_response(self) -> Response { Response::new(Body::empty()) } } -impl IntoResponse for Infallible { - fn into_response(self) -> Response { +impl IntoResponse for Infallible { + fn into_response(self) -> Response { match self {} } } -impl IntoResponse for Either +impl IntoResponse for Either where - T: IntoResponse, - K: IntoResponse, + T: IntoResponse, + K: IntoResponse, { - fn into_response(self) -> Response { + fn into_response(self) -> Response { match self { Either::A(inner) => inner.into_response(), Either::B(inner) => inner.into_response(), @@ -35,12 +34,12 @@ where } } -impl IntoResponse for Result +impl IntoResponse for Result where - T: IntoResponse, - E: IntoResponse, + T: IntoResponse, + E: IntoResponse, { - fn into_response(self) -> Response { + fn into_response(self) -> Response { match self { Ok(value) => value.into_response(), Err(err) => err.into_response(), @@ -48,27 +47,27 @@ where } } -impl IntoResponse for Response { +impl IntoResponse for Response { fn into_response(self) -> Self { self } } -impl IntoResponse for &'static str { +impl IntoResponse for &'static str { #[inline] fn into_response(self) -> Response { Cow::Borrowed(self).into_response() } } -impl IntoResponse for String { +impl IntoResponse for String { #[inline] fn into_response(self) -> Response { Cow::<'static, str>::Owned(self).into_response() } } -impl IntoResponse for std::borrow::Cow<'static, str> { +impl IntoResponse for std::borrow::Cow<'static, str> { fn into_response(self) -> Response { let mut res = Response::new(Body::from(self)); res.headers_mut() @@ -77,7 +76,7 @@ impl IntoResponse for std::borrow::Cow<'static, str> { } } -impl IntoResponse for Bytes { +impl IntoResponse for Bytes { fn into_response(self) -> Response { let mut res = Response::new(Body::from(self)); res.headers_mut().insert( @@ -88,7 +87,7 @@ impl IntoResponse for Bytes { } } -impl IntoResponse for &'static [u8] { +impl IntoResponse for &'static [u8] { fn into_response(self) -> Response { let mut res = Response::new(Body::from(self)); res.headers_mut().insert( @@ -99,7 +98,7 @@ impl IntoResponse for &'static [u8] { } } -impl IntoResponse for Vec { +impl IntoResponse for Vec { fn into_response(self) -> Response { let mut res = Response::new(Body::from(self)); res.headers_mut().insert( @@ -110,7 +109,7 @@ impl IntoResponse for Vec { } } -impl IntoResponse for std::borrow::Cow<'static, [u8]> { +impl IntoResponse for std::borrow::Cow<'static, [u8]> { fn into_response(self) -> Response { let mut res = Response::new(Body::from(self)); res.headers_mut().insert( @@ -121,7 +120,7 @@ impl IntoResponse for std::borrow::Cow<'static, [u8]> { } } -impl IntoResponse for StatusCode { +impl IntoResponse for StatusCode { fn into_response(self) -> Response { Response::builder() .status(self) @@ -130,7 +129,7 @@ impl IntoResponse for StatusCode { } } -impl IntoResponse for (StatusCode, T) +impl IntoResponse for (StatusCode, T) where T: Into, { @@ -142,7 +141,7 @@ where } } -impl IntoResponse for (StatusCode, HeaderMap, T) +impl IntoResponse for (StatusCode, HeaderMap, T) where T: Into, { @@ -156,7 +155,7 @@ where pub struct Html(pub T); -impl IntoResponse for Html +impl IntoResponse for Html where T: Into, { @@ -170,7 +169,7 @@ where pub struct Json(pub T); -impl IntoResponse for Json +impl IntoResponse for Json where T: Serialize, { diff --git a/src/routing.rs b/src/routing.rs index 15479a82..e2acf70f 100644 --- a/src/routing.rs +++ b/src/routing.rs @@ -389,7 +389,7 @@ impl Layered { where S: Service, Response = Response> + Clone, F: FnOnce(S::Error) -> Res, - Res: IntoResponse, + Res: IntoResponse, B: http_body::Body + Send + Sync + 'static, B::Error: Into + Send + Sync + 'static, { @@ -428,7 +428,7 @@ impl Service> for HandleError where S: Service, Response = Response> + Clone, F: FnOnce(S::Error) -> Res + Clone, - Res: IntoResponse, + Res: IntoResponse, B: http_body::Body + Send + Sync + 'static, B::Error: Into + Send + Sync + 'static, { @@ -459,7 +459,7 @@ impl Future for HandleErrorFuture where Fut: Future, E>>, F: FnOnce(E) -> Res, - Res: IntoResponse, + Res: IntoResponse, B: http_body::Body + Send + Sync + 'static, B::Error: Into + Send + Sync + 'static, { diff --git a/src/service.rs b/src/service.rs index 128bf879..6c129c40 100644 --- a/src/service.rs +++ b/src/service.rs @@ -105,10 +105,12 @@ where #[derive(Clone)] pub struct HandleError { - inner: S, - f: F, + pub(crate) inner: S, + pub(crate) f: F, } +impl crate::routing::RoutingDsl for HandleError {} + impl HandleError { pub(crate) fn new(inner: S, f: F) -> Self { Self { inner, f } @@ -131,7 +133,7 @@ impl Service> for HandleError where S: Service, Response = Response> + Clone, F: FnOnce(S::Error) -> Res + Clone, - Res: IntoResponse, + Res: IntoResponse, B: http_body::Body + Send + Sync + 'static, B::Error: Into + Send + Sync + 'static, { @@ -162,7 +164,7 @@ impl Future for HandleErrorFuture where Fut: Future, E>>, F: FnOnce(E) -> Res, - Res: IntoResponse, + Res: IntoResponse, B: http_body::Body + Send + Sync + 'static, B::Error: Into + Send + Sync + 'static, { diff --git a/src/tests.rs b/src/tests.rs index aa25edd4..4c73756d 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -8,7 +8,7 @@ use std::{ time::Duration, }; use tower::{make::Shared, BoxError, Service, ServiceBuilder}; -use tower_http::compression::CompressionLayer; +use tower_http::{compression::CompressionLayer, trace::TraceLayer}; #[tokio::test] async fn hello_world() { @@ -444,8 +444,6 @@ async fn middleware_on_single_route() { #[tokio::test] async fn handling_errors_from_layered_single_routes() { - use tower::timeout::TimeoutLayer; - async fn handle(_req: Request) -> &'static str { tokio::time::sleep(Duration::from_secs(10)).await; "" @@ -454,7 +452,12 @@ async fn handling_errors_from_layered_single_routes() { let app = route( "/", get(handle - .layer(TimeoutLayer::new(Duration::from_millis(100))) + .layer( + ServiceBuilder::new() + .timeout(Duration::from_secs(30)) + .layer(TraceLayer::new_for_http()) + .into_inner(), + ) .handle_error(|_error: BoxError| StatusCode::INTERNAL_SERVER_ERROR)), );