1use std::error::Error as StdError;
2use std::fmt;
3use std::future::Future;
4use std::marker::PhantomData;
5use std::task::{Context, Poll};
6
7use crate::body::HttpBody;
8use crate::{Request, Response};
9
10/// Create a `Service` from a function.
11///
12/// # Example
13///
14/// ```
15/// use hyper::{Body, Request, Response, Version};
16/// use hyper::service::service_fn;
17///
18/// let service = service_fn(|req: Request<Body>| async move {
19/// if req.version() == Version::HTTP_11 {
20/// Ok(Response::new(Body::from("Hello World")))
21/// } else {
22/// // Note: it's usually better to return a Response
23/// // with an appropriate StatusCode instead of an Err.
24/// Err("not HTTP/1.1, abort connection")
25/// }
26/// });
27/// ```
28pub fn service_fn<F, R, S>(f: F) -> ServiceFn<F, R>
29where
30 F: FnMut(Request<R>) -> S,
31 S: Future,
32{
33 ServiceFn {
34 f,
35 _req: PhantomData,
36 }
37}
38
39/// Service returned by [`service_fn`]
40pub struct ServiceFn<F, R> {
41 f: F,
42 _req: PhantomData<fn(R)>,
43}
44
45impl<F, ReqBody, Ret, ResBody, E> tower_service::Service<crate::Request<ReqBody>>
46 for ServiceFn<F, ReqBody>
47where
48 F: FnMut(Request<ReqBody>) -> Ret,
49 ReqBody: HttpBody,
50 Ret: Future<Output = Result<Response<ResBody>, E>>,
51 E: Into<Box<dyn StdError + Send + Sync>>,
52 ResBody: HttpBody,
53{
54 type Response = crate::Response<ResBody>;
55 type Error = E;
56 type Future = Ret;
57
58 fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
59 Poll::Ready(Ok(()))
60 }
61
62 fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
63 (self.f)(req)
64 }
65}
66
67impl<F, R> fmt::Debug for ServiceFn<F, R> {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 f.debug_struct(name:"impl Service").finish()
70 }
71}
72
73impl<F, R> Clone for ServiceFn<F, R>
74where
75 F: Clone,
76{
77 fn clone(&self) -> Self {
78 ServiceFn {
79 f: self.f.clone(),
80 _req: PhantomData,
81 }
82 }
83}
84
85impl<F, R> Copy for ServiceFn<F, R> where F: Copy {}
86