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
8pub type BoxedHandler = Box<
10 dyn Fn(Request) -> Pin<Box<dyn Future<Output = Response> + Send>> + Send + Sync,
11>;
12
13pub 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 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 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 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 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 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}