scuffle_http/service/
function.rs1use std::fmt::Debug;
2use std::future::Future;
3use std::net::SocketAddr;
4
5use super::{HttpService, HttpServiceFactory};
6use crate::IncomingRequest;
7
8#[derive(Clone)]
15pub struct FnHttpService<F>(F);
16
17impl<F> Debug for FnHttpService<F> {
18 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19 f.debug_tuple("FnHttpService").field(&std::any::type_name::<F>()).finish()
20 }
21}
22
23pub fn fn_http_service<F, Fut, E, B>(f: F) -> FnHttpService<F>
27where
28 F: Fn(IncomingRequest) -> Fut,
29 Fut: Future<Output = Result<http::Response<B>, E>> + Send,
30 E: std::error::Error,
31 B: http_body::Body,
32{
33 FnHttpService(f)
34}
35
36impl<F, Fut, E, B> HttpService for FnHttpService<F>
37where
38 F: Fn(IncomingRequest) -> Fut,
39 Fut: Future<Output = Result<http::Response<B>, E>> + Send,
40 E: std::error::Error,
41 B: http_body::Body,
42{
43 type Error = E;
44 type ResBody = B;
45
46 fn call(
47 &mut self,
48 req: IncomingRequest,
49 ) -> impl Future<Output = Result<http::Response<Self::ResBody>, Self::Error>> + Send {
50 (self.0)(req)
51 }
52}
53
54#[derive(Clone)]
61pub struct FnHttpServiceFactory<F>(F);
62
63impl<F> Debug for FnHttpServiceFactory<F> {
64 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65 f.debug_tuple("FnHttpServiceFactory")
66 .field(&std::any::type_name::<F>())
67 .finish()
68 }
69}
70
71pub fn fn_http_service_factory<F, Fut, E, S>(f: F) -> FnHttpServiceFactory<F>
75where
76 F: Fn(SocketAddr) -> Fut,
77 Fut: Future<Output = Result<S, E>> + Send,
78 E: std::error::Error,
79 S: HttpService,
80{
81 FnHttpServiceFactory(f)
82}
83
84impl<F, Fut, E, S> HttpServiceFactory for FnHttpServiceFactory<F>
85where
86 F: Fn(SocketAddr) -> Fut,
87 Fut: Future<Output = Result<S, E>> + Send,
88 E: std::error::Error,
89 S: HttpService,
90{
91 type Error = E;
92 type Service = S;
93
94 fn new_service(&mut self, remote_addr: SocketAddr) -> impl Future<Output = Result<Self::Service, Self::Error>> + Send {
95 (self.0)(remote_addr)
96 }
97}
98
99#[cfg(test)]
100#[cfg_attr(all(test, coverage_nightly), coverage(off))]
101mod tests {
102 use std::convert::Infallible;
103
104 #[test]
105 fn fn_service_debug() {
106 let service = super::fn_http_service(|_| async { Ok::<_, Infallible>(http::Response::new(String::new())) });
107 assert_eq!(
108 format!("{service:?}"),
109 "FnHttpService(\"scuffle_http::service::function::tests::fn_service_debug::{{closure}}\")"
110 );
111 }
112
113 #[test]
114 fn fn_service_factory_debug() {
115 let factory = super::fn_http_service_factory(|_| async {
116 Ok::<_, Infallible>(super::fn_http_service(|_| async {
117 Ok::<_, Infallible>(http::Response::new(String::new()))
118 }))
119 });
120 assert_eq!(
121 format!("{factory:?}"),
122 "FnHttpServiceFactory(\"scuffle_http::service::function::tests::fn_service_factory_debug::{{closure}}\")"
123 );
124 }
125}