matchit/router.rs
1use crate::tree::Node;
2use crate::{InsertError, MatchError, Params};
3
4/// A zero-copy URL router.
5///
6/// See [the crate documentation](crate) for details.
7#[derive(Clone, Debug)]
8pub struct Router<T> {
9 root: Node<T>,
10}
11
12impl<T> Default for Router<T> {
13 fn default() -> Self {
14 Self {
15 root: Node::default(),
16 }
17 }
18}
19
20impl<T> Router<T> {
21 /// Construct a new router.
22 pub fn new() -> Self {
23 Self::default()
24 }
25
26 /// Insert a route into the router.
27 ///
28 /// # Examples
29 ///
30 /// ```rust
31 /// # use matchit::Router;
32 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
33 /// let mut router = Router::new();
34 /// router.insert("/home", "Welcome!")?;
35 /// router.insert("/users/{id}", "A User")?;
36 /// # Ok(())
37 /// # }
38 /// ```
39 pub fn insert(&mut self, route: impl Into<String>, value: T) -> Result<(), InsertError> {
40 self.root.insert(route.into(), value)
41 }
42
43 /// Tries to find a value in the router matching the given path.
44 ///
45 /// # Examples
46 ///
47 /// ```rust
48 /// # use matchit::Router;
49 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
50 /// let mut router = Router::new();
51 /// router.insert("/home", "Welcome!")?;
52 ///
53 /// let matched = router.at("/home").unwrap();
54 /// assert_eq!(*matched.value, "Welcome!");
55 /// # Ok(())
56 /// # }
57 /// ```
58 pub fn at<'path>(&self, path: &'path str) -> Result<Match<'_, 'path, &T>, MatchError> {
59 match self.root.at(path.as_bytes()) {
60 Ok((value, params)) => Ok(Match {
61 // Safety: We only expose `&mut T` through `&mut self`
62 value: unsafe { &*value.get() },
63 params,
64 }),
65 Err(e) => Err(e),
66 }
67 }
68
69 /// Tries to find a value in the router matching the given path,
70 /// returning a mutable reference.
71 ///
72 /// # Examples
73 ///
74 /// ```rust
75 /// # use matchit::Router;
76 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
77 /// let mut router = Router::new();
78 /// router.insert("/", 1)?;
79 ///
80 /// *router.at_mut("/").unwrap().value += 1;
81 /// assert_eq!(*router.at("/").unwrap().value, 2);
82 /// # Ok(())
83 /// # }
84 /// ```
85 pub fn at_mut<'path>(
86 &mut self,
87 path: &'path str,
88 ) -> Result<Match<'_, 'path, &mut T>, MatchError> {
89 match self.root.at(path.as_bytes()) {
90 Ok((value, params)) => Ok(Match {
91 // Safety: We have `&mut self`
92 value: unsafe { &mut *value.get() },
93 params,
94 }),
95 Err(e) => Err(e),
96 }
97 }
98
99 /// Remove a given route from the router.
100 ///
101 /// Returns the value stored under the route if it was found.
102 /// If the route was not found or invalid, `None` is returned.
103 ///
104 /// # Examples
105 ///
106 /// ```rust
107 /// # use matchit::Router;
108 /// let mut router = Router::new();
109 ///
110 /// router.insert("/home", "Welcome!");
111 /// assert_eq!(router.remove("/home"), Some("Welcome!"));
112 /// assert_eq!(router.remove("/home"), None);
113 ///
114 /// router.insert("/home/{id}/", "Hello!");
115 /// assert_eq!(router.remove("/home/{id}/"), Some("Hello!"));
116 /// assert_eq!(router.remove("/home/{id}/"), None);
117 ///
118 /// router.insert("/home/{id}/", "Hello!");
119 /// // the route does not match
120 /// assert_eq!(router.remove("/home/{user}"), None);
121 /// assert_eq!(router.remove("/home/{id}/"), Some("Hello!"));
122 ///
123 /// router.insert("/home/{id}/", "Hello!");
124 /// // invalid route
125 /// assert_eq!(router.remove("/home/{id"), None);
126 /// assert_eq!(router.remove("/home/{id}/"), Some("Hello!"));
127 /// ```
128 pub fn remove(&mut self, path: impl Into<String>) -> Option<T> {
129 self.root.remove(path.into())
130 }
131
132 #[cfg(feature = "__test_helpers")]
133 pub fn check_priorities(&self) -> Result<u32, (u32, u32)> {
134 self.root.check_priorities()
135 }
136}
137
138/// A successful match consisting of the registered value
139/// and URL parameters, returned by [`Router::at`](Router::at).
140#[derive(Debug)]
141pub struct Match<'k, 'v, V> {
142 /// The value stored under the matched node.
143 pub value: V,
144
145 /// The route parameters. See [parameters](crate#parameters) for more details.
146 pub params: Params<'k, 'v>,
147}