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