1 use crate::tree::Node;
2 use 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))]
9 pub struct Router<T> {
10     root: Node<T>,
11 }
12 
13 impl<T> Default for Router<T> {
default() -> Self14     fn default() -> Self {
15         Self {
16             root: Node::default(),
17         }
18     }
19 }
20 
21 impl<T> Router<T> {
22     /// Construct a new router.
new() -> Self23     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     /// ```
insert(&mut self, route: impl Into<String>, value: T) -> Result<(), InsertError>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     /// ```
at<'m, 'p>(&'m self, path: &'p str) -> Result<Match<'m, 'p, &'m T>, MatchError>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     /// ```
at_mut<'m, 'p>( &'m mut self, path: &'p str, ) -> Result<Match<'m, 'p, &'m mut T>, MatchError>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")]
check_priorities(&self) -> Result<u32, (u32, u32)>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)]
109 pub 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 }
115