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 (#1418)
This commit is contained in:
parent
31638a2b22
commit
9196c09fe8
4 changed files with 92 additions and 155 deletions
axum
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue