1use rust_webx_core::error::Result;
7use rust_webx_core::http::IHttpContext;
8use rust_webx_core::routing::{HttpMethod, IEndpoint, IRouter};
9use std::collections::HashMap;
10use std::sync::Arc;
11
12type RouteValue = (Arc<dyn IEndpoint>, String);
13
14struct MethodRouter {
16 inner: matchit::Router<RouteValue>,
17}
18
19impl MethodRouter {
20 fn new() -> Self {
21 Self {
22 inner: matchit::Router::new(),
23 }
24 }
25
26 fn insert(&mut self, path: &str, endpoint: Arc<dyn IEndpoint>) {
27 let value = (endpoint, path.to_string());
28 let _ = self.inner.insert(path, value);
29 }
30
31 fn at<'a>(&'a self, path: &'a str) -> Option<matchit::Match<'a, 'a, &'a RouteValue>> {
32 self.inner.at(path).ok()
33 }
34}
35
36pub struct Router {
38 get: MethodRouter,
39 post: MethodRouter,
40 put: MethodRouter,
41 delete: MethodRouter,
42 patch: MethodRouter,
43 head: MethodRouter,
44 options: MethodRouter,
45}
46
47impl Router {
48 pub fn new() -> Self {
49 Self {
50 get: MethodRouter::new(),
51 post: MethodRouter::new(),
52 put: MethodRouter::new(),
53 delete: MethodRouter::new(),
54 patch: MethodRouter::new(),
55 head: MethodRouter::new(),
56 options: MethodRouter::new(),
57 }
58 }
59
60 fn method_router_mut(&mut self, m: HttpMethod) -> &mut MethodRouter {
61 match m {
62 HttpMethod::Get => &mut self.get,
63 HttpMethod::Post => &mut self.post,
64 HttpMethod::Put => &mut self.put,
65 HttpMethod::Delete => &mut self.delete,
66 HttpMethod::Patch => &mut self.patch,
67 HttpMethod::Head => &mut self.head,
68 HttpMethod::Options => &mut self.options,
69 }
70 }
71
72 fn method_router(&self, m: HttpMethod) -> &MethodRouter {
73 match m {
74 HttpMethod::Get => &self.get,
75 HttpMethod::Post => &self.post,
76 HttpMethod::Put => &self.put,
77 HttpMethod::Delete => &self.delete,
78 HttpMethod::Patch => &self.patch,
79 HttpMethod::Head => &self.head,
80 HttpMethod::Options => &self.options,
81 }
82 }
83}
84
85#[async_trait::async_trait]
86impl IRouter for Router {
87 fn register(&mut self, method: HttpMethod, path: &str, endpoint: Arc<dyn IEndpoint>) {
88 self.method_router_mut(method).insert(path, endpoint);
89 }
90
91 async fn match_route(
92 &self,
93 ctx: &mut dyn IHttpContext,
94 ) -> Result<Option<(Arc<dyn IEndpoint>, HashMap<String, String>, String)>> {
95 let path = ctx.request().path();
96 let method_str = ctx.request().method();
97 let method = HttpMethod::from_str(method_str).unwrap_or(HttpMethod::Get);
98
99 let router = self.method_router(method);
100
101 if let Some(matched) = router.at(path) {
102 let mut params = HashMap::new();
103 for (key, value) in matched.params.iter() {
104 params.insert(key.to_string(), value.to_string());
105 }
106
107 let (endpoint, pattern) = matched.value;
108 return Ok(Some((Arc::clone(endpoint), params, pattern.clone())));
109 }
110
111 Ok(None)
112 }
113}
114
115impl Default for Router {
116 fn default() -> Self {
117 Self::new()
118 }
119}