1use std::collections::HashMap;
2
3use hyper::Method;
4
5use crate::handler::Handler;
6
7#[derive(Clone, Debug, Default)]
13pub struct PathParams(pub HashMap<String, String>);
14
15#[derive(Clone, Debug, Default)]
22pub struct QueryParams(pub HashMap<String, String>);
23
24#[derive(Default)]
29pub struct Router<S> {
30 root: Node<S>,
31}
32
33struct Node<S> {
34 segment: String,
35 param_name: String,
36 is_wildcard: bool,
37 handlers: Vec<(Method, Handler<S>)>,
47 children: Vec<Node<S>>,
48}
49
50impl<S> Default for Node<S> {
51 fn default() -> Self {
52 Node {
53 segment: String::new(),
54 param_name: String::new(),
55 is_wildcard: false,
56 handlers: Vec::new(),
57 children: Vec::new(),
58 }
59 }
60}
61
62impl<S: Send + Sync + 'static> Router<S> {
63 pub fn new() -> Self {
65 Router { root: Node::default() }
66 }
67
68 pub fn insert(&mut self, method: Method, path: &str, handler: Handler<S>) {
73 let segments = split_path(path);
74 let mut node = &mut self.root;
75
76 for seg in segments {
77 if seg == "*" {
78 if let Some(idx) = node.children.iter().position(|c| c.is_wildcard) {
79 node = &mut node.children[idx];
80 } else {
81 node.children.push(Node {
82 segment: "*".to_string(),
83 param_name: String::new(),
84 is_wildcard: true,
85 handlers: Vec::new(),
86 children: Vec::new(),
87 });
88 node = node.children.last_mut().unwrap();
89 }
90 } else if let Some(param_name) = seg.strip_prefix(':') {
91 if let Some(idx) = node.children.iter().position(|c| c.param_name == param_name) {
92 node = &mut node.children[idx];
93 } else {
94 node.children.push(Node {
95 segment: seg.to_string(),
96 param_name: param_name.to_string(),
97 is_wildcard: false,
98 handlers: Vec::new(),
99 children: Vec::new(),
100 });
101 node = node.children.last_mut().unwrap();
102 }
103 } else {
104 if let Some(idx) = node.children.iter().position(|c| c.segment == seg) {
105 node = &mut node.children[idx];
106 } else {
107 node.children.push(Node {
108 segment: seg.to_string(),
109 param_name: String::new(),
110 is_wildcard: false,
111 handlers: Vec::new(),
112 children: Vec::new(),
113 });
114 node = node.children.last_mut().unwrap();
115 }
116 }
117 }
118
119 if let Some(slot) = node.handlers.iter_mut().find(|(m, _)| *m == method) {
123 slot.1 = handler;
124 } else {
125 node.handlers.push((method, handler));
126 }
127 }
128
129 pub fn match_route<'a>(
134 &'a self,
135 method: &Method,
136 path: &str,
137 ) -> Option<(&'a Handler<S>, PathParams)> {
138 let segments = split_path(path);
139 let mut params = PathParams::default();
140 let node = Self::find_node(&self.root, &segments, 0, method, &mut params)?;
141 node.handlers.iter().find(|(m, _)| m == method).map(|(_, h)| (h, params))
142 }
143
144 pub fn allowed_methods(&self, path: &str) -> Vec<Method> {
148 let segments = split_path(path);
149 let mut methods = std::collections::HashSet::new();
150 let mut params = PathParams::default();
151 Self::collect_allowed_methods(&self.root, &segments, 0, &mut params, &mut methods);
152 methods.into_iter().collect()
153 }
154
155 pub fn path_exists(&self, path: &str) -> bool {
157 !self.allowed_methods(path).is_empty()
158 }
159
160 fn find_node<'a>(
174 node: &'a Node<S>,
175 segments: &[String],
176 idx: usize,
177 method: &Method,
178 params: &mut PathParams,
179 ) -> Option<&'a Node<S>> {
180 if idx == segments.len() {
181 return if node.handlers.iter().any(|(m, _)| m == method) { Some(node) } else { None };
182 }
183
184 let seg = &segments[idx];
185
186 for child in &node.children {
187 if !child.is_wildcard && child.param_name.is_empty() && child.segment == *seg {
188 if let Some(found) = Self::find_node(child, segments, idx + 1, method, params) {
190 return Some(found);
191 }
192 }
193 }
194
195 for child in &node.children {
196 if !child.is_wildcard && !child.param_name.is_empty() {
197 let mut p = params.clone();
199 p.0.insert(child.param_name.clone(), seg.clone());
200 if let Some(found) = Self::find_node(child, segments, idx + 1, method, &mut p) {
201 *params = p;
202 return Some(found);
203 }
204 params.0.remove(&child.param_name);
206 }
207 }
208
209 for child in &node.children {
210 if child.is_wildcard && child.handlers.iter().any(|(m, _)| m == method) {
211 params.0.insert("*".to_string(), segments[idx..].join("/"));
212 return Some(child);
213 }
214 }
215
216 None
217 }
218
219 fn collect_allowed_methods(
226 node: &Node<S>,
227 segments: &[String],
228 idx: usize,
229 params: &mut PathParams,
230 methods: &mut std::collections::HashSet<Method>,
231 ) {
232 if idx == segments.len() {
233 methods.extend(node.handlers.iter().map(|(m, _)| m.clone()));
234 return;
235 }
236
237 let seg = &segments[idx];
238
239 for child in &node.children {
240 if !child.is_wildcard && child.param_name.is_empty() && child.segment == *seg {
241 let mut p = params.clone();
242 Self::collect_allowed_methods(child, segments, idx + 1, &mut p, methods);
243 }
244 }
245
246 for child in &node.children {
247 if !child.is_wildcard && !child.param_name.is_empty() {
248 let mut p = params.clone();
249 p.0.insert(child.param_name.clone(), seg.clone());
250 Self::collect_allowed_methods(child, segments, idx + 1, &mut p, methods);
251 }
252 }
253
254 for child in &node.children {
255 if child.is_wildcard {
256 methods.extend(child.handlers.iter().map(|(m, _)| m.clone()));
257 }
258 }
259 }
260}
261
262fn split_path(path: &str) -> Vec<String> {
263 path.trim_start_matches('/')
264 .split('/')
265 .filter(|s| !s.is_empty())
266 .map(|s| percent_encoding::percent_decode_str(s).decode_utf8_lossy().into_owned())
267 .collect()
268}
269
270#[cfg(test)]
271#[path = "../tests/unit/router.rs"]
272mod tests;
273
274#[cfg(test)]
275#[path = "../tests/unit/router_properties.rs"]
276mod property_tests;