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 { root: Node, } impl Default for Router { fn default() -> Self { Self { root: Node::default(), } } } impl Router { /// Construct a new router. pub fn new() -> Self { Self::default() } /// Insert a route. /// /// # Examples /// /// ```rust /// # use matchit::Router; /// # fn main() -> Result<(), Box> { /// let mut router = Router::new(); /// router.insert("/home", "Welcome!")?; /// router.insert("/users/:id", "A User")?; /// # Ok(()) /// # } /// ``` pub fn insert(&mut self, route: impl Into, 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> { /// 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, 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> { /// 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, 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 { 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>, }