torch_web/
handler.rs

1use std::future::Future;
2use std::pin::Pin;
3use crate::{Request, Response};
4
5/// A trait for handling HTTP requests
6pub trait Handler<T>: Clone + Send + Sync + 'static {
7    /// The future type returned by the handler
8    type Future: Future<Output = Response> + Send + 'static;
9
10    /// Handle the request and return a response
11    fn call(&self, req: Request) -> Self::Future;
12}
13
14/// A boxed handler function type for dynamic dispatch
15pub type HandlerFn = std::sync::Arc<
16    dyn Fn(Request) -> Pin<Box<dyn Future<Output = Response> + Send + 'static>>
17        + Send
18        + Sync
19        + 'static,
20>;
21
22/// Implement Handler for async functions that take Request and return Response
23impl<F, Fut> Handler<()> for F
24where
25    F: Fn(Request) -> Fut + Clone + Send + Sync + 'static,
26    Fut: Future<Output = Response> + Send + 'static,
27{
28    type Future = Fut;
29
30    fn call(&self, req: Request) -> Self::Future {
31        self(req)
32    }
33}
34
35/// Implement Handler for functions that return Response directly (sync handlers)
36impl<F> Handler<((),)> for F
37where
38    F: Fn(Request) -> Response + Clone + Send + Sync + 'static,
39{
40    type Future = Pin<Box<dyn Future<Output = Response> + Send + 'static>>;
41
42    fn call(&self, req: Request) -> Self::Future {
43        let response = self(req);
44        Box::pin(async move { response })
45    }
46}
47
48/// Convert a handler into a boxed handler function
49pub fn into_handler_fn<H, T>(handler: H) -> HandlerFn
50where
51    H: Handler<T>,
52{
53    std::sync::Arc::new(move |req| Box::pin(handler.call(req)))
54}
55
56/// A convenience macro for creating simple handlers
57#[macro_export]
58macro_rules! handler {
59    ($body:expr) => {
60        |_req: $crate::Request| async move { $body }
61    };
62    ($req:ident => $body:expr) => {
63        |$req: $crate::Request| async move { $body }
64    };
65}
66
67#[cfg(disabled_for_now)]
68mod tests {
69    use super::*;
70    use crate::Response;
71
72    #[tokio::test]
73    async fn test_async_handler() {
74        let handler = |_req: Request| async {
75            Response::ok().body("Hello from async handler")
76        };
77
78        let req = Request::from_hyper(
79            http::Request::builder()
80                .method("GET")
81                .uri("/")
82                .body(())
83                .unwrap()
84                .into_parts()
85                .0,
86            Vec::new(),
87        )
88        .await
89        .unwrap();
90
91        let response = handler.call(req).await;
92        assert_eq!(response.body_data(), b"Hello from async handler");
93    }
94
95    #[tokio::test]
96    async fn test_sync_handler() {
97        let handler = |_req: Request| Response::ok().body("Hello from sync handler");
98
99        let req = Request::from_hyper(
100            http::Request::builder()
101                .method("GET")
102                .uri("/")
103                .body(())
104                .unwrap()
105                .into_parts()
106                .0,
107            Vec::new(),
108        )
109        .await
110        .unwrap();
111
112        let response = handler.call(req).await;
113        assert_eq!(response.body_data(), b"Hello from sync handler");
114    }
115
116    #[test]
117    fn test_handler_macro() {
118        let _handler1 = handler!(Response::ok().body("Simple response"));
119        let _handler2 = handler!(req => {
120            Response::ok().body(format!("Path: {}", req.path()))
121        });
122    }
123}