1
0
Fork 0
mirror of https://github.com/tokio-rs/axum.git synced 2025-04-26 13:56:22 +02:00

Merge handler::{WithState, IntoService} into one HandlerService type ()

This commit is contained in:
Jonas Platte 2022-09-26 14:51:42 +02:00 committed by GitHub
parent 31638a2b22
commit 9196c09fe8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 92 additions and 155 deletions

View file

@ -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)

View file

@ -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<H, T, S, B> {
handler: H,
state: Arc<S>,
_marker: PhantomData<fn() -> (T, B)>,
}
impl<H, T, S, B> IntoService<H, T, S, B> {
/// Get a reference to the state.
pub fn state(&self) -> &S {
&self.state
}
}
#[test]
fn traits() {
use crate::test_helpers::*;
assert_send::<IntoService<(), NotSendSync, (), NotSendSync>>();
assert_sync::<IntoService<(), NotSendSync, (), NotSendSync>>();
}
impl<H, T, S, B> IntoService<H, T, S, B> {
pub(super) fn new(handler: H, state: Arc<S>) -> Self {
Self {
handler,
state,
_marker: PhantomData,
}
}
}
impl<H, T, S, B> fmt::Debug for IntoService<H, T, S, B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("IntoService").finish_non_exhaustive()
}
}
impl<H, T, S, B> Clone for IntoService<H, T, S, B>
where
H: Clone,
{
fn clone(&self) -> Self {
Self {
handler: self.handler.clone(),
state: Arc::clone(&self.state),
_marker: PhantomData,
}
}
}
impl<H, T, S, B> Service<Request<B>> for IntoService<H, T, S, B>
where
H: Handler<T, S, B> + Clone + Send + 'static,
B: Send + 'static,
S: Send + Sync,
{
type Response = Response;
type Error = Infallible;
type Future = super::future::IntoServiceFuture<H::Future>;
#[inline]
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
// `IntoService` can only be constructed from async functions which are always ready, or
// from `Layered` which bufferes in `<Layered as Handler>::call` and is therefore
// also always ready.
Poll::Ready(Ok(()))
}
fn call(&mut self, req: Request<B>) -> 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)
}
}

View file

@ -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<T, S, B = Body>: Clone + Send + Sized + 'static {
/// ```
fn layer<L>(self, layer: L) -> Layered<L, Self, T, S, B>
where
L: Layer<WithState<Self, T, S, B>> + Clone,
L: Layer<HandlerService<Self, T, S, B>> + Clone,
{
Layered {
layer,
@ -155,15 +154,13 @@ pub trait Handler<T, S, B = Body>: Clone + Send + Sized + 'static {
}
/// Convert the handler into a [`Service`] by providing the state
fn with_state(self, state: S) -> WithState<Self, T, S, B> {
fn with_state(self, state: S) -> HandlerService<Self, T, S, B> {
self.with_state_arc(Arc::new(state))
}
/// Convert the handler into a [`Service`] by providing the state
fn with_state_arc(self, state: Arc<S>) -> WithState<Self, T, S, B> {
WithState {
service: IntoService::new(self, state),
}
fn with_state_arc(self, state: Arc<S>) -> HandlerService<Self, T, S, B> {
HandlerService::new(self, state)
}
}
@ -264,7 +261,7 @@ where
impl<H, S, T, B, L> Handler<T, S, B> for Layered<L, H, T, S, B>
where
L: Layer<WithState<H, T, S, B>> + Clone + Send + 'static,
L: Layer<HandlerService<H, T, S, B>> + Clone + Send + 'static,
H: Handler<T, S, B>,
L::Service: Service<Request<B>, Error = Infallible> + Clone + Send + 'static,
<L::Service as Service<Request<B>>>::Response: IntoResponse,
@ -305,44 +302,44 @@ where
/// [`MakeService`]: tower::make::MakeService
pub trait HandlerWithoutStateExt<T, B>: Handler<T, (), B> {
/// Convert the handler into a [`Service`] and no state.
fn into_service(self) -> WithState<Self, T, (), B>;
fn into_service(self) -> HandlerService<Self, T, (), B>;
/// 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<IntoService<Self, T, (), B>>;
fn into_make_service(self) -> IntoMakeService<HandlerService<Self, T, (), B>>;
/// 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<C>(
self,
) -> IntoMakeServiceWithConnectInfo<IntoService<Self, T, (), B>, C>;
) -> IntoMakeServiceWithConnectInfo<HandlerService<Self, T, (), B>, C>;
}
impl<H, T, B> HandlerWithoutStateExt<T, B> for H
where
H: Handler<T, (), B>,
{
fn into_service(self) -> WithState<Self, T, (), B> {
fn into_service(self) -> HandlerService<Self, T, (), B> {
self.with_state(())
}
fn into_make_service(self) -> IntoMakeService<IntoService<Self, T, (), B>> {
self.with_state(()).into_make_service()
fn into_make_service(self) -> IntoMakeService<HandlerService<Self, T, (), B>> {
self.into_service().into_make_service()
}
#[cfg(feature = "tokio")]
fn into_make_service_with_connect_info<C>(
self,
) -> IntoMakeServiceWithConnectInfo<IntoService<Self, T, (), B>, C> {
self.with_state(()).into_make_service_with_connect_info()
) -> IntoMakeServiceWithConnectInfo<HandlerService<Self, T, (), B>, C> {
self.into_service().into_make_service_with_connect_info()
}
}

View file

@ -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<H, T, S, B> {
pub(super) service: IntoService<H, T, S, B>,
/// [`HandlerWithoutStateExt::into_service`]: super::HandlerWithoutStateExt::into_service
pub struct HandlerService<H, T, S, B> {
handler: H,
state: Arc<S>,
_marker: PhantomData<fn() -> (T, B)>,
}
impl<H, T, S, B> WithState<H, T, S, B> {
impl<H, T, S, B> HandlerService<H, T, S, B> {
/// Get a reference to the state.
pub fn state(&self) -> &S {
self.service.state()
&self.state
}
}
impl<H, T, S, B> WithState<H, T, S, B> {
/// 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<H, T, S, B> WithState<H, T, S, B> {
/// ```
///
/// [`MakeService`]: tower::make::MakeService
pub fn into_make_service(self) -> IntoMakeService<IntoService<H, T, S, B>> {
IntoMakeService::new(self.service)
pub fn into_make_service(self) -> IntoMakeService<HandlerService<H, T, S, B>> {
IntoMakeService::new(self)
}
/// Convert the handler into a [`MakeService`] which stores information
@ -100,47 +106,72 @@ impl<H, T, S, B> WithState<H, T, S, B> {
#[cfg(feature = "tokio")]
pub fn into_make_service_with_connect_info<C>(
self,
) -> IntoMakeServiceWithConnectInfo<IntoService<H, T, S, B>, C> {
IntoMakeServiceWithConnectInfo::new(self.service)
) -> IntoMakeServiceWithConnectInfo<HandlerService<H, T, S, B>, C> {
IntoMakeServiceWithConnectInfo::new(self)
}
}
impl<H, T, S, B> Service<Request<B>> for WithState<H, T, S, B>
where
H: Handler<T, S, B> + Clone + Send + 'static,
B: Send + 'static,
S: Send + Sync,
{
type Response = <IntoService<H, T, S, B> as Service<Request<B>>>::Response;
type Error = <IntoService<H, T, S, B> as Service<Request<B>>>::Error;
type Future = <IntoService<H, T, S, B> as Service<Request<B>>>::Future;
#[test]
fn traits() {
use crate::test_helpers::*;
assert_send::<HandlerService<(), NotSendSync, (), NotSendSync>>();
assert_sync::<HandlerService<(), NotSendSync, (), NotSendSync>>();
}
#[inline]
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
#[inline]
fn call(&mut self, req: Request<B>) -> Self::Future {
self.service.call(req)
impl<H, T, S, B> HandlerService<H, T, S, B> {
pub(super) fn new(handler: H, state: Arc<S>) -> Self {
Self {
handler,
state,
_marker: PhantomData,
}
}
}
impl<H, T, S, B> std::fmt::Debug for WithState<H, T, S, B> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("WithState")
.field("service", &self.service)
.finish()
impl<H, T, S, B> fmt::Debug for HandlerService<H, T, S, B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("IntoService").finish_non_exhaustive()
}
}
impl<H, T, S, B> Clone for WithState<H, T, S, B>
impl<H, T, S, B> Clone for HandlerService<H, T, S, B>
where
H: Clone,
{
fn clone(&self) -> Self {
Self {
service: self.service.clone(),
handler: self.handler.clone(),
state: Arc::clone(&self.state),
_marker: PhantomData,
}
}
}
impl<H, T, S, B> Service<Request<B>> for HandlerService<H, T, S, B>
where
H: Handler<T, S, B> + Clone + Send + 'static,
B: Send + 'static,
S: Send + Sync,
{
type Response = Response;
type Error = Infallible;
type Future = super::future::IntoServiceFuture<H::Future>;
#[inline]
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
// `IntoService` can only be constructed from async functions which are always ready, or
// from `Layered` which bufferes in `<Layered as Handler>::call` and is therefore
// also always ready.
Poll::Ready(Ok(()))
}
fn call(&mut self, req: Request<B>) -> 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)
}
}