From 9196c09fe829753705290a4d21108e33e4a2a374 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Mon, 26 Sep 2022 14:51:42 +0200 Subject: [PATCH] Merge handler::{WithState, IntoService} into one HandlerService type (#1418) --- axum/CHANGELOG.md | 3 + axum/src/handler/into_service.rs | 94 --------------- axum/src/handler/mod.rs | 37 +++--- .../src/handler/{with_state.rs => service.rs} | 113 +++++++++++------- 4 files changed, 92 insertions(+), 155 deletions(-) delete mode 100644 axum/src/handler/into_service.rs rename axum/src/handler/{with_state.rs => service.rs} (52%) diff --git a/axum/CHANGELOG.md b/axum/CHANGELOG.md index 9f6b60c4..7483c6c3 100644 --- a/axum/CHANGELOG.md +++ b/axum/CHANGELOG.md @@ -38,6 +38,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **breaking:** New `tokio` default feature needed for WASM support. If you don't need WASM support but have `default_features = false` for other reasons you likely need to re-enable the `tokio` feature ([#1382]) +- **breaking:** `handler::{WithState, IntoService}` are merged into one type, + named `HandlerService` ([#1418]) [#1368]: https://github.com/tokio-rs/axum/pull/1368 [#1371]: https://github.com/tokio-rs/axum/pull/1371 @@ -49,6 +51,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#1400]: https://github.com/tokio-rs/axum/pull/1400 [#1408]: https://github.com/tokio-rs/axum/pull/1408 [#1414]: https://github.com/tokio-rs/axum/pull/1414 +[#1418]: https://github.com/tokio-rs/axum/pull/1418 # 0.6.0-rc.2 (10. September, 2022) diff --git a/axum/src/handler/into_service.rs b/axum/src/handler/into_service.rs deleted file mode 100644 index b824a083..00000000 --- a/axum/src/handler/into_service.rs +++ /dev/null @@ -1,94 +0,0 @@ -use super::Handler; -use crate::response::Response; -use http::Request; -use std::{ - convert::Infallible, - fmt, - marker::PhantomData, - sync::Arc, - task::{Context, Poll}, -}; -use tower_service::Service; - -/// An adapter that makes a [`Handler`] into a [`Service`]. -/// -/// Created with [`HandlerWithoutStateExt::into_service`]. -/// -/// [`HandlerWithoutStateExt::into_service`]: super::HandlerWithoutStateExt::into_service -pub struct IntoService { - handler: H, - state: Arc, - _marker: PhantomData (T, B)>, -} - -impl IntoService { - /// Get a reference to the state. - pub fn state(&self) -> &S { - &self.state - } -} - -#[test] -fn traits() { - use crate::test_helpers::*; - assert_send::>(); - assert_sync::>(); -} - -impl IntoService { - pub(super) fn new(handler: H, state: Arc) -> Self { - Self { - handler, - state, - _marker: PhantomData, - } - } -} - -impl fmt::Debug for IntoService { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("IntoService").finish_non_exhaustive() - } -} - -impl Clone for IntoService -where - H: Clone, -{ - fn clone(&self) -> Self { - Self { - handler: self.handler.clone(), - state: Arc::clone(&self.state), - _marker: PhantomData, - } - } -} - -impl Service> for IntoService -where - H: Handler + Clone + Send + 'static, - B: Send + 'static, - S: Send + Sync, -{ - type Response = Response; - type Error = Infallible; - type Future = super::future::IntoServiceFuture; - - #[inline] - fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { - // `IntoService` can only be constructed from async functions which are always ready, or - // from `Layered` which bufferes in `::call` and is therefore - // also always ready. - Poll::Ready(Ok(())) - } - - fn call(&mut self, req: Request) -> Self::Future { - use futures_util::future::FutureExt; - - let handler = self.handler.clone(); - let future = Handler::call(handler, req, Arc::clone(&self.state)); - let future = future.map(Ok as _); - - super::future::IntoServiceFuture::new(future) - } -} diff --git a/axum/src/handler/mod.rs b/axum/src/handler/mod.rs index dd82b706..f63c58ae 100644 --- a/axum/src/handler/mod.rs +++ b/axum/src/handler/mod.rs @@ -51,14 +51,13 @@ use tower_service::Service; mod boxed; pub mod future; -mod into_service; mod into_service_state_in_extension; -mod with_state; +mod service; +pub use self::service::HandlerService; pub(crate) use self::{ boxed::BoxedHandler, into_service_state_in_extension::IntoServiceStateInExtension, }; -pub use self::{into_service::IntoService, with_state::WithState}; /// Trait for async functions that can be used to handle requests. /// @@ -145,7 +144,7 @@ pub trait Handler: Clone + Send + Sized + 'static { /// ``` fn layer(self, layer: L) -> Layered where - L: Layer> + Clone, + L: Layer> + Clone, { Layered { layer, @@ -155,15 +154,13 @@ pub trait Handler: Clone + Send + Sized + 'static { } /// Convert the handler into a [`Service`] by providing the state - fn with_state(self, state: S) -> WithState { + fn with_state(self, state: S) -> HandlerService { self.with_state_arc(Arc::new(state)) } /// Convert the handler into a [`Service`] by providing the state - fn with_state_arc(self, state: Arc) -> WithState { - WithState { - service: IntoService::new(self, state), - } + fn with_state_arc(self, state: Arc) -> HandlerService { + HandlerService::new(self, state) } } @@ -264,7 +261,7 @@ where impl Handler for Layered where - L: Layer> + Clone + Send + 'static, + L: Layer> + Clone + Send + 'static, H: Handler, L::Service: Service, Error = Infallible> + Clone + Send + 'static, >>::Response: IntoResponse, @@ -305,44 +302,44 @@ where /// [`MakeService`]: tower::make::MakeService pub trait HandlerWithoutStateExt: Handler { /// Convert the handler into a [`Service`] and no state. - fn into_service(self) -> WithState; + fn into_service(self) -> HandlerService; /// Convert the handler into a [`MakeService`] and no state. /// - /// See [`WithState::into_make_service`] for more details. + /// See [`HandlerService::into_make_service`] for more details. /// /// [`MakeService`]: tower::make::MakeService - fn into_make_service(self) -> IntoMakeService>; + fn into_make_service(self) -> IntoMakeService>; /// Convert the handler into a [`MakeService`] which stores information /// about the incoming connection and has no state. /// - /// See [`WithState::into_make_service_with_connect_info`] for more details. + /// See [`HandlerService::into_make_service_with_connect_info`] for more details. /// /// [`MakeService`]: tower::make::MakeService #[cfg(feature = "tokio")] fn into_make_service_with_connect_info( self, - ) -> IntoMakeServiceWithConnectInfo, C>; + ) -> IntoMakeServiceWithConnectInfo, C>; } impl HandlerWithoutStateExt for H where H: Handler, { - fn into_service(self) -> WithState { + fn into_service(self) -> HandlerService { self.with_state(()) } - fn into_make_service(self) -> IntoMakeService> { - self.with_state(()).into_make_service() + fn into_make_service(self) -> IntoMakeService> { + self.into_service().into_make_service() } #[cfg(feature = "tokio")] fn into_make_service_with_connect_info( self, - ) -> IntoMakeServiceWithConnectInfo, C> { - self.with_state(()).into_make_service_with_connect_info() + ) -> IntoMakeServiceWithConnectInfo, C> { + self.into_service().into_make_service_with_connect_info() } } diff --git a/axum/src/handler/with_state.rs b/axum/src/handler/service.rs similarity index 52% rename from axum/src/handler/with_state.rs rename to axum/src/handler/service.rs index 662b51b9..4e6b63b3 100644 --- a/axum/src/handler/with_state.rs +++ b/axum/src/handler/service.rs @@ -1,30 +1,36 @@ -use super::{Handler, IntoService}; +use super::Handler; #[cfg(feature = "tokio")] use crate::extract::connect_info::IntoMakeServiceWithConnectInfo; +use crate::response::Response; use crate::routing::IntoMakeService; use http::Request; -use std::task::{Context, Poll}; +use std::{ + convert::Infallible, + fmt, + marker::PhantomData, + sync::Arc, + task::{Context, Poll}, +}; use tower_service::Service; -/// A [`Handler`] which has access to some state. +/// An adapter that makes a [`Handler`] into a [`Service`]. /// -/// Implements [`Service`]. +/// Created with [`Handler::with_state`], [`Handler::with_state_arc`] or +/// [`HandlerWithoutStateExt::into_service`]. /// -/// The state can be extracted with [`State`](crate::extract::State). -/// -/// Created with [`Handler::with_state`]. -pub struct WithState { - pub(super) service: IntoService, +/// [`HandlerWithoutStateExt::into_service`]: super::HandlerWithoutStateExt::into_service +pub struct HandlerService { + handler: H, + state: Arc, + _marker: PhantomData (T, B)>, } -impl WithState { +impl HandlerService { /// Get a reference to the state. pub fn state(&self) -> &S { - self.service.state() + &self.state } -} -impl WithState { /// Convert the handler into a [`MakeService`]. /// /// This allows you to serve a single handler if you don't need any routing: @@ -57,8 +63,8 @@ impl WithState { /// ``` /// /// [`MakeService`]: tower::make::MakeService - pub fn into_make_service(self) -> IntoMakeService> { - IntoMakeService::new(self.service) + pub fn into_make_service(self) -> IntoMakeService> { + IntoMakeService::new(self) } /// Convert the handler into a [`MakeService`] which stores information @@ -100,47 +106,72 @@ impl WithState { #[cfg(feature = "tokio")] pub fn into_make_service_with_connect_info( self, - ) -> IntoMakeServiceWithConnectInfo, C> { - IntoMakeServiceWithConnectInfo::new(self.service) + ) -> IntoMakeServiceWithConnectInfo, C> { + IntoMakeServiceWithConnectInfo::new(self) } } -impl Service> for WithState -where - H: Handler + Clone + Send + 'static, - B: Send + 'static, - S: Send + Sync, -{ - type Response = as Service>>::Response; - type Error = as Service>>::Error; - type Future = as Service>>::Future; +#[test] +fn traits() { + use crate::test_helpers::*; + assert_send::>(); + assert_sync::>(); +} - #[inline] - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.service.poll_ready(cx) - } - - #[inline] - fn call(&mut self, req: Request) -> Self::Future { - self.service.call(req) +impl HandlerService { + pub(super) fn new(handler: H, state: Arc) -> Self { + Self { + handler, + state, + _marker: PhantomData, + } } } -impl std::fmt::Debug for WithState { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("WithState") - .field("service", &self.service) - .finish() +impl fmt::Debug for HandlerService { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("IntoService").finish_non_exhaustive() } } -impl Clone for WithState +impl Clone for HandlerService where H: Clone, { fn clone(&self) -> Self { Self { - service: self.service.clone(), + handler: self.handler.clone(), + state: Arc::clone(&self.state), + _marker: PhantomData, } } } + +impl Service> for HandlerService +where + H: Handler + Clone + Send + 'static, + B: Send + 'static, + S: Send + Sync, +{ + type Response = Response; + type Error = Infallible; + type Future = super::future::IntoServiceFuture; + + #[inline] + fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { + // `IntoService` can only be constructed from async functions which are always ready, or + // from `Layered` which bufferes in `::call` and is therefore + // also always ready. + Poll::Ready(Ok(())) + } + + fn call(&mut self, req: Request) -> Self::Future { + use futures_util::future::FutureExt; + + let handler = self.handler.clone(); + let future = Handler::call(handler, req, Arc::clone(&self.state)); + let future = future.map(Ok as _); + + super::future::IntoServiceFuture::new(future) + } +}