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