torch_web/
handler.rs

1use std::future::Future;
2use std::pin::Pin;
3use crate::{Request, Response};
4use crate::extractors::{FromRequestParts, IntoResponse};
5
6/// A trait for handling HTTP requests
7pub trait Handler<T>: Clone + Send + Sync + 'static {
8    /// The future type returned by the handler
9    type Future: Future<Output = Response> + Send + 'static;
10
11    /// Handle the request and return a response
12    fn call(&self, req: Request) -> Self::Future;
13}
14
15/// A boxed handler function type for dynamic dispatch
16pub type HandlerFn = std::sync::Arc<
17    dyn Fn(Request) -> Pin<Box<dyn Future<Output = Response> + Send + 'static>>
18        + Send
19        + Sync
20        + 'static,
21>;
22
23/// Implement Handler for async functions that take Request and return Response
24impl<F, Fut> Handler<()> for F
25where
26    F: Fn(Request) -> Fut + Clone + Send + Sync + 'static,
27    Fut: Future<Output = Response> + Send + 'static,
28{
29    type Future = Fut;
30
31    fn call(&self, req: Request) -> Self::Future {
32        self(req)
33    }
34}
35
36// Handler implementations for extractors
37
38/// Handler for async functions with no extractors (just returns a response)
39impl<F, Fut, Res> Handler<((),)> for F
40where
41    F: Fn() -> Fut + Clone + Send + Sync + 'static,
42    Fut: Future<Output = Res> + Send + 'static,
43    Res: IntoResponse,
44{
45    type Future = Pin<Box<dyn Future<Output = Response> + Send + 'static>>;
46
47    fn call(&self, _req: Request) -> Self::Future {
48        let fut = self();
49        Box::pin(async move {
50            let res = fut.await;
51            res.into_response()
52        })
53    }
54}
55
56/// Handler for functions with one extractor
57impl<F, Fut, Res, E1> Handler<(E1,)> for F
58where
59    F: Fn(E1) -> Fut + Clone + Send + Sync + 'static,
60    Fut: Future<Output = Res> + Send + 'static,
61    Res: IntoResponse,
62    E1: FromRequestParts + Send + 'static,
63{
64    type Future = Pin<Box<dyn Future<Output = Response> + Send + 'static>>;
65
66    fn call(&self, mut req: Request) -> Self::Future {
67        let handler = self.clone();
68        Box::pin(async move {
69            match E1::from_request_parts(&mut req).await {
70                Ok(e1) => {
71                    let res = handler(e1).await;
72                    res.into_response()
73                }
74                Err(err) => err.into_response(),
75            }
76        })
77    }
78}
79
80/// Handler for functions with two extractors
81impl<F, Fut, Res, E1, E2> Handler<(E1, E2)> for F
82where
83    F: Fn(E1, E2) -> Fut + Clone + Send + Sync + 'static,
84    Fut: Future<Output = Res> + Send + 'static,
85    Res: IntoResponse,
86    E1: FromRequestParts + Send + 'static,
87    E2: FromRequestParts + Send + 'static,
88{
89    type Future = Pin<Box<dyn Future<Output = Response> + Send + 'static>>;
90
91    fn call(&self, mut req: Request) -> Self::Future {
92        let handler = self.clone();
93        Box::pin(async move {
94            let e1 = match E1::from_request_parts(&mut req).await {
95                Ok(e1) => e1,
96                Err(err) => return err.into_response(),
97            };
98
99            let e2 = match E2::from_request_parts(&mut req).await {
100                Ok(e2) => e2,
101                Err(err) => return err.into_response(),
102            };
103
104            let res = handler(e1, e2).await;
105            res.into_response()
106        })
107    }
108}
109
110/// Handler for functions with three extractors
111impl<F, Fut, Res, E1, E2, E3> Handler<(E1, E2, E3)> for F
112where
113    F: Fn(E1, E2, E3) -> Fut + Clone + Send + Sync + 'static,
114    Fut: Future<Output = Res> + Send + 'static,
115    Res: IntoResponse,
116    E1: FromRequestParts + Send + 'static,
117    E2: FromRequestParts + Send + 'static,
118    E3: FromRequestParts + Send + 'static,
119{
120    type Future = Pin<Box<dyn Future<Output = Response> + Send + 'static>>;
121
122    fn call(&self, mut req: Request) -> Self::Future {
123        let handler = self.clone();
124        Box::pin(async move {
125            let e1 = match E1::from_request_parts(&mut req).await {
126                Ok(e1) => e1,
127                Err(err) => return err.into_response(),
128            };
129
130            let e2 = match E2::from_request_parts(&mut req).await {
131                Ok(e2) => e2,
132                Err(err) => return err.into_response(),
133            };
134
135            let e3 = match E3::from_request_parts(&mut req).await {
136                Ok(e3) => e3,
137                Err(err) => return err.into_response(),
138            };
139
140            let res = handler(e1, e2, e3).await;
141            res.into_response()
142        })
143    }
144}
145
146/// Handler for functions with four extractors
147impl<F, Fut, Res, E1, E2, E3, E4> Handler<(E1, E2, E3, E4)> for F
148where
149    F: Fn(E1, E2, E3, E4) -> Fut + Clone + Send + Sync + 'static,
150    Fut: Future<Output = Res> + Send + 'static,
151    Res: IntoResponse,
152    E1: FromRequestParts + Send + 'static,
153    E2: FromRequestParts + Send + 'static,
154    E3: FromRequestParts + Send + 'static,
155    E4: FromRequestParts + Send + 'static,
156{
157    type Future = Pin<Box<dyn Future<Output = Response> + Send + 'static>>;
158
159    fn call(&self, mut req: Request) -> Self::Future {
160        let handler = self.clone();
161        Box::pin(async move {
162            let e1 = match E1::from_request_parts(&mut req).await {
163                Ok(e1) => e1,
164                Err(err) => return err.into_response(),
165            };
166
167            let e2 = match E2::from_request_parts(&mut req).await {
168                Ok(e2) => e2,
169                Err(err) => return err.into_response(),
170            };
171
172            let e3 = match E3::from_request_parts(&mut req).await {
173                Ok(e3) => e3,
174                Err(err) => return err.into_response(),
175            };
176
177            let e4 = match E4::from_request_parts(&mut req).await {
178                Ok(e4) => e4,
179                Err(err) => return err.into_response(),
180            };
181
182            let res = handler(e1, e2, e3, e4).await;
183            res.into_response()
184        })
185    }
186}
187
188/// Convert a handler into a boxed handler function
189pub fn into_handler_fn<H, T>(handler: H) -> HandlerFn
190where
191    H: Handler<T>,
192{
193    std::sync::Arc::new(move |req| Box::pin(handler.call(req)))
194}
195
196// Handler implementations for FromRequest extractors (like Json, Form)
197
198/// Handler for async functions that take Request directly
199impl<F, Fut, Res> Handler<(Request,)> for F
200where
201    F: Fn(Request) -> Fut + Clone + Send + Sync + 'static,
202    Fut: Future<Output = Res> + Send + 'static,
203    Res: IntoResponse,
204{
205    type Future = Pin<Box<dyn Future<Output = Response> + Send + 'static>>;
206
207    fn call(&self, req: Request) -> Self::Future {
208        let handler = self.clone();
209        Box::pin(async move {
210            let res = handler(req).await;
211            res.into_response()
212        })
213    }
214}
215
216/// A convenience macro for creating simple handlers
217#[macro_export]
218macro_rules! handler {
219    ($body:expr) => {
220        |_req: $crate::Request| async move { $body }
221    };
222    ($req:ident => $body:expr) => {
223        |$req: $crate::Request| async move { $body }
224    };
225}
226
227#[cfg(test)]
228mod tests {
229    use super::*;
230    use crate::Response;
231
232    #[tokio::test]
233    async fn test_async_handler() {
234        let handler = |_req: Request| async {
235            Response::ok().body("Hello from async handler")
236        };
237
238        let req = Request::from_hyper(
239            http::Request::builder()
240                .method("GET")
241                .uri("/")
242                .body(())
243                .unwrap()
244                .into_parts()
245                .0,
246            Vec::new(),
247        )
248        .await
249        .unwrap();
250
251        let response = handler.call(req).await;
252        assert_eq!(response.body_data(), b"Hello from async handler");
253    }
254
255    #[tokio::test]
256    async fn test_sync_handler() {
257        let handler = |_req: Request| Response::ok().body("Hello from sync handler");
258
259        let req = Request::from_hyper(
260            http::Request::builder()
261                .method("GET")
262                .uri("/")
263                .body(())
264                .unwrap()
265                .into_parts()
266                .0,
267            Vec::new(),
268        )
269        .await
270        .unwrap();
271
272        let response = handler.call(req).await;
273        assert_eq!(response.body_data(), b"Hello from sync handler");
274    }
275
276    #[test]
277    fn test_handler_macro() {
278        let _handler1 = handler!(Response::ok().body("Simple response"));
279        let _handler2 = handler!(req => {
280            Response::ok().body(format!("Path: {}", req.path()))
281        });
282    }
283}