matchit/router.rs
1use crate::tree::Node;
2use crate::{InsertError, MatchError, Params};
3
4/// A URL router.
5///
6/// See [the crate documentation](crate) for details.
7#[derive(Clone)]
8#[cfg_attr(test, derive(Debug))]
9pub struct Router<T> {
10 root: Node<T>,
11}
12
13impl<T> Default for Router<T> {
14 fn default() -> Self {
15 Self {
16 root: Node::default(),
17 }
18 }
19}
20
21impl<T> Router<T> {
22 /// Construct a new router.
23 pub fn new() -> Self {
24 Self::default()
25 }
26
27 /// Insert a route.
28 ///
29 /// # Examples
30 ///
31 /// ```rust
32 /// # use matchit::Router;
33 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
34 /// let mut router = Router::new();
35 /// router.insert("/home", "Welcome!")?;
36 /// router.insert("/users/:id", "A User")?;
37 /// # Ok(())
38 /// # }
39 /// ```
40 pub fn insert(&mut self, route: impl Into<String>, value: T) -> Result<(), InsertError> {
41 self.root.insert(route, value)
42 }
43
44 /// Tries to find a value in the router matching the given path.
45 ///
46 /// # Examples
47 ///
48 /// ```rust
49 /// # use matchit::Router;
50 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
51 /// let mut router = Router::new();
52 /// router.insert("/home", "Welcome!")?;
53 ///
54 /// let matched = router.at("/home").unwrap();
55 /// assert_eq!(*matched.value, "Welcome!");
56 /// # Ok(())
57 /// # }
58 /// ```
59 pub fn at<'m, 'p>(&'m self, path: &'p str) -> Result<Match<'m, 'p, &'m T>, MatchError> {
60 match self.root.at(path.as_bytes()) {
61 Ok((value, params)) => Ok(Match {
62 // SAFETY: We only expose &mut T through &mut self
63 value: unsafe { &*value.get() },
64 params,
65 }),
66 Err(e) => Err(e),
67 }
68 }
69
70 /// Tries to find a value in the router matching the given path,
71 /// returning a mutable reference.
72 ///
73 /// # Examples
74 ///
75 /// ```rust
76 /// # use matchit::Router;
77 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
78 /// let mut router = Router::new();
79 /// router.insert("/", 1)?;
80 ///
81 /// *router.at_mut("/").unwrap().value += 1;
82 /// assert_eq!(*router.at("/").unwrap().value, 2);
83 /// # Ok(())
84 /// # }
85 /// ```
86 pub fn at_mut<'m, 'p>(
87 &'m mut self,
88 path: &'p str,
89 ) -> Result<Match<'m, 'p, &'m mut T>, MatchError> {
90 match self.root.at(path.as_bytes()) {
91 Ok((value, params)) => Ok(Match {
92 // SAFETY: We have &mut self
93 value: unsafe { &mut *value.get() },
94 params,
95 }),
96 Err(e) => Err(e),
97 }
98 }
99
100 #[cfg(feature = "__test_helpers")]
101 pub fn check_priorities(&self) -> Result<u32, (u32, u32)> {
102 self.root.check_priorities()
103 }
104}
105
106/// A successful match consisting of the registered value
107/// and URL parameters, returned by [`Router::at`](Router::at).
108#[derive(Debug)]
109pub struct Match<'k, 'v, V> {
110 /// The value stored under the matched node.
111 pub value: V,
112 /// The route parameters. See [parameters](crate#parameters) for more details.
113 pub params: Params<'k, 'v>,
114}