kit_rs/routing/
router.rs

1use crate::http::{Request, Response};
2use matchit::Router as MatchitRouter;
3use std::collections::HashMap;
4use std::future::Future;
5use std::pin::Pin;
6use std::sync::Arc;
7
8/// Type alias for route handlers
9pub type BoxedHandler = Box<
10    dyn Fn(Request) -> Pin<Box<dyn Future<Output = Response> + Send>> + Send + Sync,
11>;
12
13/// HTTP Router with Laravel-like route registration
14pub struct Router {
15    get_routes: MatchitRouter<Arc<BoxedHandler>>,
16    post_routes: MatchitRouter<Arc<BoxedHandler>>,
17    put_routes: MatchitRouter<Arc<BoxedHandler>>,
18    delete_routes: MatchitRouter<Arc<BoxedHandler>>,
19}
20
21impl Router {
22    pub fn new() -> Self {
23        Self {
24            get_routes: MatchitRouter::new(),
25            post_routes: MatchitRouter::new(),
26            put_routes: MatchitRouter::new(),
27            delete_routes: MatchitRouter::new(),
28        }
29    }
30
31    /// Register a GET route
32    pub fn get<H, Fut>(mut self, path: &str, handler: H) -> Self
33    where
34        H: Fn(Request) -> Fut + Send + Sync + 'static,
35        Fut: Future<Output = Response> + Send + 'static,
36    {
37        let handler: BoxedHandler = Box::new(move |req| Box::pin(handler(req)));
38        self.get_routes.insert(path, Arc::new(handler)).ok();
39        self
40    }
41
42    /// Register a POST route
43    pub fn post<H, Fut>(mut self, path: &str, handler: H) -> Self
44    where
45        H: Fn(Request) -> Fut + Send + Sync + 'static,
46        Fut: Future<Output = Response> + Send + 'static,
47    {
48        let handler: BoxedHandler = Box::new(move |req| Box::pin(handler(req)));
49        self.post_routes.insert(path, Arc::new(handler)).ok();
50        self
51    }
52
53    /// Register a PUT route
54    pub fn put<H, Fut>(mut self, path: &str, handler: H) -> Self
55    where
56        H: Fn(Request) -> Fut + Send + Sync + 'static,
57        Fut: Future<Output = Response> + Send + 'static,
58    {
59        let handler: BoxedHandler = Box::new(move |req| Box::pin(handler(req)));
60        self.put_routes.insert(path, Arc::new(handler)).ok();
61        self
62    }
63
64    /// Register a DELETE route
65    pub fn delete<H, Fut>(mut self, path: &str, handler: H) -> Self
66    where
67        H: Fn(Request) -> Fut + Send + Sync + 'static,
68        Fut: Future<Output = Response> + Send + 'static,
69    {
70        let handler: BoxedHandler = Box::new(move |req| Box::pin(handler(req)));
71        self.delete_routes.insert(path, Arc::new(handler)).ok();
72        self
73    }
74
75    /// Match a request and return the handler with extracted params
76    pub fn match_route(
77        &self,
78        method: &hyper::Method,
79        path: &str,
80    ) -> Option<(Arc<BoxedHandler>, HashMap<String, String>)> {
81        let router = match *method {
82            hyper::Method::GET => &self.get_routes,
83            hyper::Method::POST => &self.post_routes,
84            hyper::Method::PUT => &self.put_routes,
85            hyper::Method::DELETE => &self.delete_routes,
86            _ => return None,
87        };
88
89        router.at(path).ok().map(|matched| {
90            let params: HashMap<String, String> = matched
91                .params
92                .iter()
93                .map(|(k, v)| (k.to_string(), v.to_string()))
94                .collect();
95            (matched.value.clone(), params)
96        })
97    }
98}
99
100impl Default for Router {
101    fn default() -> Self {
102        Self::new()
103    }
104}