1#![forbid(unsafe_code)]
2
3mod path;
4mod routes;
5mod visitor;
6
7pub use path::{Param, Span};
8use smallvec::SmallVec;
9pub use visitor::Found;
10
11use path::Pattern;
12use routes::{Node, RouteEntry};
13
14pub struct Router<T> {
15 nodes: Vec<Node>,
17
18 routes: Vec<T>,
20}
21
22pub struct Endpoint<'a, T> {
23 router: &'a mut Router<T>,
24 key: usize,
25}
26
27impl<T> Router<T> {
28 pub fn new() -> Self {
29 let mut nodes = Vec::new();
30 let routes = Vec::new();
31
32 nodes.push(Node::new(Pattern::Root));
33
34 Self { nodes, routes }
35 }
36
37 pub fn get(&self, key: usize) -> Option<&T> {
40 self.routes.get(key)
41 }
42
43 pub fn at(&mut self, path: &'static str) -> Endpoint<T> {
44 let mut segments = path::patterns(path);
45 let key = insert(self, &mut segments, 0);
46
47 Endpoint { router: self, key }
48 }
49
50 pub fn visit(&self, path: &str) -> Vec<Found> {
51 let mut segments = SmallVec::new();
52 let nodes = &self.nodes;
53
54 path::split_into(&mut segments, path);
55 visitor::visit(path, nodes, &segments)
56 }
57}
58
59impl<T> Router<T> {
60 fn entry(&mut self, key: usize) -> RouteEntry<T> {
62 RouteEntry::new(self, key)
63 }
64
65 fn push(&mut self, node: Node) -> usize {
68 let key = self.nodes.len();
69
70 self.nodes.push(node);
71 key
72 }
73
74 fn node(&self, key: usize) -> &Node {
76 &self.nodes[key]
77 }
78
79 fn node_mut(&mut self, key: usize) -> &mut Node {
81 &mut self.nodes[key]
82 }
83
84 fn get_mut(&mut self, key: usize) -> &mut T {
87 &mut self.routes[key]
88 }
89
90 fn push_route(&mut self, route: T) -> usize {
93 let index = self.routes.len();
94 self.routes.push(route);
95 index
96 }
97}
98
99impl<T> Default for Router<T> {
100 fn default() -> Self {
101 Self::new()
102 }
103}
104
105impl<'a, T> Endpoint<'a, T> {
106 pub fn at(&mut self, path: &'static str) -> Endpoint<T> {
107 let mut segments = path::patterns(path);
108 let key = insert(self.router, &mut segments, self.key);
109
110 Endpoint {
111 router: self.router,
112 key,
113 }
114 }
115
116 pub fn param(&self) -> Option<&Param> {
117 self.router.node(self.key).param()
118 }
119
120 pub fn get_or_insert_route_with<F>(&mut self, f: F) -> &mut T
124 where
125 F: FnOnce() -> T,
126 {
127 let route_index = self.router.entry(self.key).get_or_insert_route_with(f);
130
131 self.router.get_mut(route_index)
133 }
134}
135
136fn insert<T, I>(router: &mut Router<T>, segments: &mut I, into_index: usize) -> usize
137where
138 I: Iterator<Item = Pattern>,
139{
140 if let Pattern::Wildcard(_) = router.node(into_index).pattern {
145 for _ in segments {}
146 return into_index;
147 }
148
149 let pattern = match segments.next() {
151 Some(value) => value,
152 None => return into_index,
153 };
154
155 for next_index in router.node(into_index).entries() {
158 if pattern == router.node(*next_index).pattern {
159 return insert(router, segments, *next_index);
160 }
161 }
162
163 let next_index = router.entry(into_index).push(Node::new(pattern));
164
165 insert(router, segments, next_index)
169}
170
171#[cfg(test)]
172mod tests {
173 use crate::path::Param;
174
175 use super::Router;
176
177 const PATHS: [&str; 4] = [
178 "/*path",
179 "/echo/*path",
180 "/articles/:id",
181 "/articles/:id/comments",
182 ];
183
184 #[test]
185 fn test_router_visit() {
186 let mut router = Router::new();
187
188 for path in &PATHS {
189 let _ = router.at(path).get_or_insert_route_with(|| ());
190 }
191
192 {
193 let path = "/";
194 let matches: Vec<_> = router.visit(path);
195
196 assert_eq!(matches.len(), 2);
197
198 {
199 let found = &matches[0];
202 let route = found.route.and_then(|key| router.get(key));
203 let segment = &path[found.at.start()..found.at.end()];
204
205 assert_eq!(route, None);
206 assert_eq!(found.param, None);
207 assert_eq!(segment, "");
208 assert!(found.is_leaf);
209 }
210
211 {
212 let found = &matches[1];
215 let route = found.route.and_then(|key| router.get(key));
216 let segment = &path[found.at.start()..found.at.end()];
217
218 assert_eq!(route, Some(&()));
219 assert_eq!(found.param, Some(Param::new("path")));
220 assert_eq!(segment, "");
221 assert!(found.is_leaf);
223 }
224 }
225
226 {
227 let path = "/not/a/path";
228 let matches: Vec<_> = router.visit(path);
229
230 assert_eq!(matches.len(), 2);
231
232 {
233 let found = &matches[0];
236 let route = found.route.and_then(|key| router.get(key));
237 let segment = &path[found.at.start()..found.at.end()];
238
239 assert_eq!(route, None);
240 assert_eq!(found.param, None);
241 assert_eq!(segment, "");
242 assert!(!found.is_leaf);
243 }
244
245 {
246 let found = &matches[1];
249 let route = found.route.and_then(|key| router.get(key));
250 let segment = &path[found.at.start()..found.at.end()];
251
252 assert_eq!(route, Some(&()));
253 assert_eq!(found.param, Some(Param::new("path")));
254 assert_eq!(segment, &path[1..]);
255 assert!(found.is_leaf);
257 }
258 }
259
260 {
261 let path = "/echo/hello/world";
262 let matches: Vec<_> = router.visit(path);
263
264 assert_eq!(matches.len(), 4);
265
266 {
267 let found = &matches[0];
270 let route = found.route.and_then(|key| router.get(key));
271 let segment = &path[found.at.start()..found.at.end()];
272
273 assert_eq!(route, None);
274 assert_eq!(found.param, None);
275 assert_eq!(segment, "");
276 assert!(!found.is_leaf);
277 }
278
279 {
280 let found = &matches[1];
283 let route = found.route.and_then(|key| router.get(key));
284 let segment = &path[found.at.start()..found.at.end()];
285
286 assert_eq!(route, Some(&()));
287 assert_eq!(found.param, Some(Param::new("path")));
288 assert_eq!(segment, &path[1..]);
289 assert!(found.is_leaf);
291 }
292
293 {
294 let found = &matches[2];
297 let route = found.route.and_then(|key| router.get(key));
298 let segment = &path[found.at.start()..found.at.end()];
299
300 assert_eq!(route, None);
301 assert_eq!(found.param, None);
302 assert_eq!(segment, "echo");
303 assert!(!found.is_leaf);
304 }
305
306 {
307 let found = &matches[3];
310 let route = found.route.and_then(|key| router.get(key));
311 let segment = &path[found.at.start()..found.at.end()];
312
313 assert_eq!(route, Some(&()));
314 assert_eq!(found.param, Some(Param::new("path")));
315 assert_eq!(segment, "hello/world");
316 assert!(found.is_leaf);
317 }
318 }
319
320 {
321 let path = "/articles/100";
322 let matches: Vec<_> = router.visit(path);
323
324 assert_eq!(matches.len(), 4);
325
326 {
327 let found = &matches[0];
330 let route = found.route.and_then(|key| router.get(key));
331 let segment = &path[found.at.start()..found.at.end()];
332
333 assert_eq!(route, None);
334 assert_eq!(found.param, None);
335 assert_eq!(segment, "");
336 assert!(!found.is_leaf);
337 }
338
339 {
340 let found = &matches[1];
343 let route = found.route.and_then(|key| router.get(key));
344 let segment = &path[found.at.start()..found.at.end()];
345
346 assert_eq!(route, Some(&()));
347 assert_eq!(found.param, Some(Param::new("path")));
348 assert_eq!(segment, &path[1..]);
349 assert!(found.is_leaf);
351 }
352
353 {
354 let found = &matches[2];
357 let route = found.route.and_then(|key| router.get(key));
358 let segment = &path[found.at.start()..found.at.end()];
359
360 assert_eq!(route, None);
361 assert_eq!(found.param, None);
362 assert_eq!(segment, "articles");
363 assert!(!found.is_leaf);
364 }
365
366 {
367 let found = &matches[3];
370 let route = found.route.and_then(|key| router.get(key));
371 let segment = &path[found.at.start()..found.at.end()];
372
373 assert_eq!(route, Some(&()));
374 assert_eq!(found.param, Some(Param::new("id")));
375 assert_eq!(segment, "100");
376 assert!(found.is_leaf);
377 }
378 }
379
380 {
381 let path = "/articles/100/comments";
382 let matches: Vec<_> = router.visit(path);
383
384 assert_eq!(matches.len(), 5);
385
386 {
387 let found = &matches[0];
390 let route = found.route.and_then(|key| router.get(key));
391 let segment = &path[found.at.start()..found.at.end()];
392
393 assert_eq!(route, None);
394 assert_eq!(found.param, None);
395 assert_eq!(segment, "");
396 assert!(!found.is_leaf);
397 }
398
399 {
400 let found = &matches[1];
403 let route = found.route.and_then(|key| router.get(key));
404 let segment = &path[found.at.start()..found.at.end()];
405
406 assert_eq!(route, Some(&()));
407 assert_eq!(found.param, Some(Param::new("path")));
408 assert_eq!(segment, &path[1..]);
409 assert!(found.is_leaf);
411 }
412
413 {
414 let found = &matches[2];
417 let route = found.route.and_then(|key| router.get(key));
418 let segment = &path[found.at.start()..found.at.end()];
419
420 assert_eq!(route, None);
421 assert_eq!(found.param, None);
422 assert_eq!(segment, "articles");
423 assert!(!found.is_leaf);
424 }
425
426 {
427 let found = &matches[3];
430 let route = found.route.and_then(|key| router.get(key));
431 let segment = &path[found.at.start()..found.at.end()];
432
433 assert_eq!(route, Some(&()));
434 assert_eq!(found.param, Some(Param::new("id")));
435 assert_eq!(segment, "100");
436 assert!(!found.is_leaf);
437 }
438
439 {
440 let found = &matches[4];
443 let route = found.route.and_then(|key| router.get(key));
444 let segment = &path[found.at.start()..found.at.end()];
445
446 assert_eq!(route, Some(&()));
447 assert_eq!(found.param, None);
448 assert_eq!(segment, "comments");
449 assert!(found.is_leaf);
451 }
452 }
453 }
454}