feat(service): rename Service to HttpService, re-export tower::Service`
				
					
				
			The only important trait for a user is the `tower::Service` trait, which is now available also at `hyper::service::Service`. The other "trait aliases" are no longer publicly exported, as people thought they had to implement them. Also removes dependency on `tower-make`, which is trivial but otherwise shouldn't affect anyone. Closes #1959
This commit is contained in:
		
							
								
								
									
										58
									
								
								src/service/http.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/service/http.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| use std::error::Error as StdError; | ||||
|  | ||||
| use crate::body::Payload; | ||||
| use crate::common::{Future, Poll, task}; | ||||
| use crate::{Request, Response}; | ||||
|  | ||||
| /// An asynchronous function from `Request` to `Response`. | ||||
| pub trait HttpService<ReqBody>: sealed::Sealed<ReqBody> { | ||||
|     /// The `Payload` body of the `http::Response`. | ||||
|     type ResBody: Payload; | ||||
|  | ||||
|     /// The error type that can occur within this `Service`. | ||||
|     /// | ||||
|     /// Note: Returning an `Error` to a hyper server will cause the connection | ||||
|     /// to be abruptly aborted. In most cases, it is better to return a `Response` | ||||
|     /// with a 4xx or 5xx status code. | ||||
|     type Error: Into<Box<dyn StdError + Send + Sync>>; | ||||
|  | ||||
|     /// The `Future` returned by this `Service`. | ||||
|     type Future: Future<Output=Result<Response<Self::ResBody>, Self::Error>>; | ||||
|  | ||||
|     #[doc(hidden)] | ||||
|     fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>>; | ||||
|  | ||||
|     #[doc(hidden)] | ||||
|     fn call(&mut self, req: Request<ReqBody>) -> Self::Future; | ||||
| } | ||||
|  | ||||
| impl<T, B1, B2> HttpService<B1> for T | ||||
| where  | ||||
|     T: tower_service::Service<Request<B1>, Response = Response<B2>>, | ||||
|     B2: Payload, | ||||
|     T::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
| { | ||||
|     type ResBody = B2; | ||||
|  | ||||
|     type Error = T::Error; | ||||
|     type Future = T::Future; | ||||
|  | ||||
|     fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> { | ||||
|         tower_service::Service::poll_ready(self, cx) | ||||
|     } | ||||
|  | ||||
|     fn call(&mut self, req: Request<B1>) -> Self::Future { | ||||
|         tower_service::Service::call(self, req) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, B1, B2> sealed::Sealed<B1> for T  | ||||
| where  | ||||
|     T: tower_service::Service<Request<B1>, Response = Response<B2>>, | ||||
|     B2: Payload, | ||||
| {} | ||||
|  | ||||
| mod sealed { | ||||
|     pub trait Sealed<T> {} | ||||
| } | ||||
|  | ||||
| @@ -1,81 +1,50 @@ | ||||
| use std::error::Error as StdError; | ||||
| use std::fmt; | ||||
| 
 | ||||
| use tokio_io::{AsyncRead, AsyncWrite}; | ||||
| 
 | ||||
| use crate::body::Payload; | ||||
| use crate::common::{Future, Poll, task}; | ||||
| use super::Service; | ||||
| use super::{HttpService, Service}; | ||||
| 
 | ||||
| /// An asynchronous constructor of `Service`s.
 | ||||
| pub trait MakeService<Target, ReqBody>: sealed::Sealed<Target, ReqBody> { | ||||
|     /// The `Payload` body of the `http::Response`.
 | ||||
|     type ResBody: Payload; | ||||
| // The same "trait alias" as tower::MakeConnection, but inlined to reduce
 | ||||
| // dependencies.
 | ||||
| pub trait MakeConnection<Target>: self::sealed::Sealed<(Target,)> { | ||||
|     type Connection: AsyncRead + AsyncWrite; | ||||
|     type Error; | ||||
|     type Future: Future<Output = Result<Self::Connection, Self::Error>>; | ||||
| 
 | ||||
|     /// The error type that can be returned by `Service`s.
 | ||||
|     type Error: Into<Box<dyn StdError + Send + Sync>>; | ||||
|     fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>>; | ||||
| 
 | ||||
|     /// The resolved `Service` from `make_service()`.
 | ||||
|     type Service: Service< | ||||
|         ReqBody, | ||||
|         ResBody=Self::ResBody, | ||||
|         Error=Self::Error, | ||||
|     >; | ||||
| 
 | ||||
|     /// The future returned from `new_service` of a `Service`.
 | ||||
|     type Future: Future<Output=Result<Self::Service, Self::MakeError>>; | ||||
| 
 | ||||
|     /// The error type that can be returned when creating a new `Service`.
 | ||||
|     type MakeError: Into<Box<dyn StdError + Send + Sync>>; | ||||
| 
 | ||||
|     /// Returns `Ready` when the constructor is ready to create a new `Service`.
 | ||||
|     ///
 | ||||
|     /// The implementation of this method is allowed to return a `Ready` even if
 | ||||
|     /// the factory is not ready to create a new service. In this case, the future
 | ||||
|     /// returned from `make_service` will resolve to an error.
 | ||||
|     fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::MakeError>>; | ||||
| 
 | ||||
|     /// Create a new `Service`.
 | ||||
|     fn make_service(&mut self, target: Target) -> Self::Future; | ||||
|     fn make_connection(&mut self, target: Target) -> Self::Future; | ||||
| } | ||||
| 
 | ||||
| impl<T, Target, S, B1, B2, E, F> MakeService<Target, B1> for T | ||||
| impl<S, Target> self::sealed::Sealed<(Target,)> for S where S: Service<Target> {} | ||||
| 
 | ||||
| impl<S, Target> MakeConnection<Target> for S | ||||
| where | ||||
|     T: for<'a> tower_service::Service<&'a Target, Response = S, Error = E, Future = F>, | ||||
|     S: tower_service::Service<crate::Request<B1>, Response = crate::Response<B2>>, | ||||
|     E: Into<Box<dyn std::error::Error + Send + Sync>>, | ||||
|     S::Error: Into<Box<dyn std::error::Error + Send + Sync>>, | ||||
|     B1: Payload, | ||||
|     B2: Payload, | ||||
|     F: Future<Output = Result<S, E>>, | ||||
|     S: Service<Target>, | ||||
|     S::Response: AsyncRead + AsyncWrite, | ||||
| { | ||||
|     type ResBody = B2; | ||||
|     type Connection = S::Response; | ||||
|     type Error = S::Error; | ||||
|     type Service = S; | ||||
|     type Future = F; | ||||
|     type MakeError = E; | ||||
|     type Future = S::Future; | ||||
| 
 | ||||
|     fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::MakeError>> { | ||||
|          tower_service::Service::poll_ready(self, cx) | ||||
|     fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> { | ||||
|         Service::poll_ready(self, cx) | ||||
|     } | ||||
| 
 | ||||
|     fn make_service(&mut self, req: Target) -> Self::Future { | ||||
|         tower_service::Service::call(self, &req) | ||||
|     fn make_connection(&mut self, target: Target) -> Self::Future { | ||||
|         Service::call(self, target) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T, Target, S, B1, B2> sealed::Sealed<Target, B1> for T 
 | ||||
| where 
 | ||||
|     T: for<'a> tower_service::Service<&'a Target, Response = S>, | ||||
|     S: tower_service::Service<crate::Request<B1>, Response = crate::Response<B2>> | ||||
| { | ||||
| } | ||||
| 
 | ||||
| // Just a sort-of "trait alias" of `MakeService`, not to be implemented
 | ||||
| // by anyone, only used as bounds.
 | ||||
| #[doc(hidden)] | ||||
| pub trait MakeServiceRef<Target, ReqBody>: self::sealed::Sealed<Target, ReqBody> { | ||||
| pub trait MakeServiceRef<Target, ReqBody>: self::sealed::Sealed<(Target, ReqBody)> { | ||||
|     type ResBody: Payload; | ||||
|     type Error: Into<Box<dyn StdError + Send + Sync>>; | ||||
|     type Service: Service< | ||||
|     type Service: HttpService< | ||||
|         ReqBody, | ||||
|         ResBody=Self::ResBody, | ||||
|         Error=Self::Error, | ||||
| @@ -101,10 +70,10 @@ pub trait MakeServiceRef<Target, ReqBody>: self::sealed::Sealed<Target, ReqBody> | ||||
| 
 | ||||
| impl<T, Target, E, ME, S, F, IB, OB> MakeServiceRef<Target, IB> for T | ||||
| where | ||||
|     T: for<'a> tower_service::Service<&'a Target, Error=ME, Response=S, Future=F>, | ||||
|     T: for<'a> Service<&'a Target, Error=ME, Response=S, Future=F>, | ||||
|     E: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     ME: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     S: tower_service::Service<crate::Request<IB>, Response=crate::Response<OB>, Error=E>, | ||||
|     S: HttpService<IB, ResBody=OB, Error=E>, | ||||
|     F: Future<Output=Result<S, ME>>, | ||||
|     IB: Payload, | ||||
|     OB: Payload, | ||||
| @@ -126,17 +95,24 @@ where | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T, Target, S, B1, B2> self::sealed::Sealed<(Target, B1)> for T | ||||
| where | ||||
|     T: for<'a> Service<&'a Target, Response = S>, | ||||
|     S: HttpService<B1, ResBody = B2>, | ||||
|     B1: Payload, | ||||
|     B2: Payload, | ||||
| { | ||||
| } | ||||
| 
 | ||||
| /// Create a `MakeService` from a function.
 | ||||
| ///
 | ||||
| /// # Example
 | ||||
| ///
 | ||||
| /// ```rust,no_run
 | ||||
| /// ```
 | ||||
| /// # #[cfg(feature = "runtime")]
 | ||||
| /// # #[tokio::main]
 | ||||
| /// # async fn main() {
 | ||||
| /// use std::net::TcpStream;
 | ||||
| /// use hyper::{Body, Error, Request, Response, Server};
 | ||||
| /// use hyper::rt::{self, Future};
 | ||||
| /// # async fn run() {
 | ||||
| /// use std::convert::Infallible;
 | ||||
| /// use hyper::{Body, Request, Response, Server};
 | ||||
| /// use hyper::server::conn::AddrStream;
 | ||||
| /// use hyper::service::{make_service_fn, service_fn};
 | ||||
| ///
 | ||||
| @@ -145,8 +121,8 @@ where | ||||
| /// let make_svc = make_service_fn(|socket: &AddrStream| {
 | ||||
| ///     let remote_addr = socket.remote_addr();
 | ||||
| ///     async move {
 | ||||
| ///         Ok::<_, Error>(service_fn(move |_: Request<Body>| async move {
 | ||||
| ///             Ok::<_, Error>(
 | ||||
| ///         Ok::<_, Infallible>(service_fn(move |_: Request<Body>| async move {
 | ||||
| ///             Ok::<_, Infallible>(
 | ||||
| ///                 Response::new(Body::from(format!("Hello, {}!", remote_addr)))
 | ||||
| ///             )
 | ||||
| ///         }))
 | ||||
| @@ -162,7 +138,7 @@ where | ||||
| ///     eprintln!("server error: {}", e);
 | ||||
| /// }
 | ||||
| /// # }
 | ||||
| /// # #[cfg(not(feature = "runtime"))] fn main() {}
 | ||||
| /// # fn main() {}
 | ||||
| /// ```
 | ||||
| pub fn make_service_fn<F, Target, Ret>(f: F) -> MakeServiceFn<F> | ||||
| where | ||||
| @@ -179,7 +155,7 @@ pub struct MakeServiceFn<F> { | ||||
|     f: F, | ||||
| } | ||||
| 
 | ||||
| impl<'t, F, Ret, Target, Svc, MkErr> tower_service::Service<&'t Target> for MakeServiceFn<F> | ||||
| impl<'t, F, Ret, Target, Svc, MkErr> Service<&'t Target> for MakeServiceFn<F> | ||||
| where | ||||
|     F: FnMut(&Target) -> Ret, | ||||
|     Ret: Future<Output=Result<Svc, MkErr>>, | ||||
| @@ -206,7 +182,7 @@ impl<F> fmt::Debug for MakeServiceFn<F> { | ||||
| } | ||||
| 
 | ||||
| mod sealed { | ||||
|     pub trait Sealed<T, B> {} | ||||
|     pub trait Sealed<X> {} | ||||
| 
 | ||||
|     pub trait CantImpl {} | ||||
| 
 | ||||
| @@ -1,15 +1,21 @@ | ||||
| //! Services and MakeServices | ||||
| //! Asynchronous Services | ||||
| //! | ||||
| //! - A [`Service`](service::Service) is a trait representing an asynchronous | ||||
| //!   function of a request to a response. It's similar to | ||||
| //!   `async fn(Request) -> Result<Response, Error>`. | ||||
| //! - A [`MakeService`](service::MakeService) is a trait creating specific | ||||
| //!   instances of a `Service`. | ||||
| //! A [`Service`](service::Service) is a trait representing an asynchronous | ||||
| //! function of a request to a response. It's similar to | ||||
| //! `async fn(Request) -> Result<Response, Error>`. | ||||
| //! | ||||
| //! These types are conceptually similar to those in | ||||
| //! [tower](https://crates.io/crates/tower), while being specific to hyper. | ||||
| //! The argument and return value isn't strictly required to be for HTTP. | ||||
| //! Therefore, hyper uses several "trait aliases" to reduce clutter around | ||||
| //! bounds. These are: | ||||
| //! | ||||
| //! # Service | ||||
| //! - `HttpService`: This is blanketly implemented for all types that | ||||
| //!   implement `Service<http::Request<B1>, Response = http::Response<B2>>`. | ||||
| //! - `MakeService`: When a `Service` returns a new `Service` as its "response", | ||||
| //!   we consider it a `MakeService`. Again, blanketly implemented in those cases. | ||||
| //! - `MakeConnection`: A `Service` that returns a "connection", a type that | ||||
| //!   implements `AsyncRead` and `AsyncWrite`. | ||||
| //! | ||||
| //! # HttpService | ||||
| //! | ||||
| //! In hyper, especially in the server setting, a `Service` is usually bound | ||||
| //! to a single connection. It defines how to respond to **all** requests that | ||||
| @@ -25,11 +31,17 @@ | ||||
| //! `MakeService` does. | ||||
| //! | ||||
| //! Resources that need to be shared by all `Service`s can be put into a | ||||
| //! `MakeService`, and then passed to individual `Service`s when `make_service` | ||||
| //! `MakeService`, and then passed to individual `Service`s when `call` | ||||
| //! is called. | ||||
|  | ||||
| mod make_service; | ||||
| mod service; | ||||
| pub use tower_service::Service; | ||||
|  | ||||
| pub use self::make_service::{make_service_fn, MakeService, MakeServiceRef}; | ||||
| pub use self::service::{service_fn, Service}; | ||||
| mod http; | ||||
| mod make; | ||||
| mod util; | ||||
|  | ||||
| pub(crate) use self::make::{MakeConnection, MakeServiceRef}; | ||||
| pub(crate) use self::http::HttpService; | ||||
|  | ||||
| pub use self::make::make_service_fn; | ||||
| pub use self::util::service_fn; | ||||
|   | ||||
| @@ -1,127 +0,0 @@ | ||||
| use std::error::Error as StdError; | ||||
| use std::fmt; | ||||
| use std::marker::PhantomData; | ||||
|  | ||||
| use crate::body::Payload; | ||||
| use crate::common::{Future, Poll, task}; | ||||
| use crate::{Request, Response}; | ||||
|  | ||||
| /// An asynchronous function from `Request` to `Response`. | ||||
| pub trait Service<ReqBody>: sealed::Sealed<ReqBody> { | ||||
|     /// The `Payload` body of the `http::Response`. | ||||
|     type ResBody: Payload; | ||||
|  | ||||
|     /// The error type that can occur within this `Service`. | ||||
|     /// | ||||
|     /// Note: Returning an `Error` to a hyper server will cause the connection | ||||
|     /// to be abruptly aborted. In most cases, it is better to return a `Response` | ||||
|     /// with a 4xx or 5xx status code. | ||||
|     type Error: Into<Box<dyn StdError + Send + Sync>>; | ||||
|  | ||||
|     /// The `Future` returned by this `Service`. | ||||
|     type Future: Future<Output=Result<Response<Self::ResBody>, Self::Error>>; | ||||
|  | ||||
|     /// Returns `Ready` when the service is able to process requests. | ||||
|     /// | ||||
|     /// The implementation of this method is allowed to return a `Ready` even if | ||||
|     /// the service is not ready to process. In this case, the future returned | ||||
|     /// from `call` will resolve to an error. | ||||
|     fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>>; | ||||
|  | ||||
|     /// Calls this `Service` with a request, returning a `Future` of the response. | ||||
|     fn call(&mut self, req: Request<ReqBody>) -> Self::Future; | ||||
| } | ||||
|  | ||||
| impl<T, B1, B2> Service<B1> for T | ||||
| where  | ||||
|     T: tower_service::Service<Request<B1>, Response = Response<B2>>, | ||||
|     B2: Payload, | ||||
|     T::Error: Into<Box<dyn StdError + Send + Sync>>, | ||||
| { | ||||
|     type ResBody = B2; | ||||
|  | ||||
|     type Error = T::Error; | ||||
|     type Future = T::Future; | ||||
|  | ||||
|     fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> { | ||||
|         tower_service::Service::poll_ready(self, cx) | ||||
|     } | ||||
|  | ||||
|     fn call(&mut self, req: Request<B1>) -> Self::Future { | ||||
|         tower_service::Service::call(self, req) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, B1, B2> sealed::Sealed<B1> for T  | ||||
| where  | ||||
|     T: tower_service::Service<Request<B1>, Response = Response<B2>>, | ||||
|     B2: Payload, | ||||
| {} | ||||
|  | ||||
| mod sealed { | ||||
|     pub trait Sealed<T> {} | ||||
| } | ||||
|  | ||||
|  | ||||
| /// Create a `Service` from a function. | ||||
| /// | ||||
| /// # Example | ||||
| /// | ||||
| /// ```rust | ||||
| /// use hyper::{Body, Request, Response, Version}; | ||||
| /// use hyper::service::service_fn; | ||||
| /// | ||||
| /// let service = service_fn(|req: Request<Body>| async move{ | ||||
| ///     if req.version() == Version::HTTP_11 { | ||||
| ///         Ok(Response::new(Body::from("Hello World"))) | ||||
| ///     } else { | ||||
| ///         // Note: it's usually better to return a Response | ||||
| ///         // with an appropriate StatusCode instead of an Err. | ||||
| ///         Err("not HTTP/1.1, abort connection") | ||||
| ///     } | ||||
| /// }); | ||||
| /// ``` | ||||
| pub fn service_fn<F, R, S>(f: F) -> ServiceFn<F, R> | ||||
| where | ||||
|     F: FnMut(Request<R>) -> S, | ||||
|     S: Future, | ||||
| { | ||||
|     ServiceFn { | ||||
|         f, | ||||
|         _req: PhantomData, | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Not exported from crate as this will likely be replaced with `impl Service`. | ||||
| pub struct ServiceFn<F, R> { | ||||
|     f: F, | ||||
|     _req: PhantomData<fn(R)>, | ||||
| } | ||||
|  | ||||
| impl<F, ReqBody, Ret, ResBody, E> tower_service::Service<crate::Request<ReqBody>> for ServiceFn<F, ReqBody> | ||||
| where | ||||
|     F: FnMut(Request<ReqBody>) -> Ret, | ||||
|     ReqBody: Payload, | ||||
|     Ret: Future<Output=Result<Response<ResBody>, E>>, | ||||
|     E: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     ResBody: Payload, | ||||
| { | ||||
|     type Response = crate::Response<ResBody>; | ||||
|     type Error = E; | ||||
|     type Future = Ret; | ||||
|  | ||||
|     fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> { | ||||
|         Poll::Ready(Ok(())) | ||||
|     } | ||||
|  | ||||
|     fn call(&mut self, req: Request<ReqBody>) -> Self::Future { | ||||
|         (self.f)(req) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<F, R> fmt::Debug for ServiceFn<F, R> { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         f.debug_struct("impl Service") | ||||
|             .finish() | ||||
|     } | ||||
| } | ||||
							
								
								
									
										70
									
								
								src/service/util.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/service/util.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| use std::error::Error as StdError; | ||||
| use std::fmt; | ||||
| use std::marker::PhantomData; | ||||
|  | ||||
| use crate::body::Payload; | ||||
| use crate::common::{Future, Poll, task}; | ||||
| use crate::{Request, Response}; | ||||
|  | ||||
| /// Create a `Service` from a function. | ||||
| /// | ||||
| /// # Example | ||||
| /// | ||||
| /// ``` | ||||
| /// use hyper::{Body, Request, Response, Version}; | ||||
| /// use hyper::service::service_fn; | ||||
| /// | ||||
| /// let service = service_fn(|req: Request<Body>| async move { | ||||
| ///     if req.version() == Version::HTTP_11 { | ||||
| ///         Ok(Response::new(Body::from("Hello World"))) | ||||
| ///     } else { | ||||
| ///         // Note: it's usually better to return a Response | ||||
| ///         // with an appropriate StatusCode instead of an Err. | ||||
| ///         Err("not HTTP/1.1, abort connection") | ||||
| ///     } | ||||
| /// }); | ||||
| /// ``` | ||||
| pub fn service_fn<F, R, S>(f: F) -> ServiceFn<F, R> | ||||
| where | ||||
|     F: FnMut(Request<R>) -> S, | ||||
|     S: Future, | ||||
| { | ||||
|     ServiceFn { | ||||
|         f, | ||||
|         _req: PhantomData, | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Not exported from crate as this will likely be replaced with `impl Service`. | ||||
| pub struct ServiceFn<F, R> { | ||||
|     f: F, | ||||
|     _req: PhantomData<fn(R)>, | ||||
| } | ||||
|  | ||||
| impl<F, ReqBody, Ret, ResBody, E> tower_service::Service<crate::Request<ReqBody>> for ServiceFn<F, ReqBody> | ||||
| where | ||||
|     F: FnMut(Request<ReqBody>) -> Ret, | ||||
|     ReqBody: Payload, | ||||
|     Ret: Future<Output=Result<Response<ResBody>, E>>, | ||||
|     E: Into<Box<dyn StdError + Send + Sync>>, | ||||
|     ResBody: Payload, | ||||
| { | ||||
|     type Response = crate::Response<ResBody>; | ||||
|     type Error = E; | ||||
|     type Future = Ret; | ||||
|  | ||||
|     fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> { | ||||
|         Poll::Ready(Ok(())) | ||||
|     } | ||||
|  | ||||
|     fn call(&mut self, req: Request<ReqBody>) -> Self::Future { | ||||
|         (self.f)(req) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<F, R> fmt::Debug for ServiceFn<F, R> { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         f.debug_struct("impl Service") | ||||
|             .finish() | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user