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
use core::fmt;
use smallvec::SmallVec;
use crate::node::{Node, SearchContext};
use crate::state::RootState;
/// Stores data from a successful router match.
#[derive(Debug)]
pub struct Match<'r, 'p, T> {
data: &'r T,
template: &'r str,
parameters: SmallVec<[(&'r str, &'p str); 4]>,
}
impl<'r, 'p, T> Match<'r, 'p, T> {
/// Returns a reference to the data associated with the matched template.
#[must_use]
pub const fn data(&self) -> &'r T {
self.data
}
/// Returns the matched template string.
#[must_use]
pub const fn template(&self) -> &'r str {
self.template
}
/// Returns the matched parameters as key-value pairs.
#[must_use]
pub fn parameters(&self) -> &[(&'r str, &'p str)] {
&self.parameters
}
}
/// An immutable, optimized router.
#[derive(Clone)]
pub struct Router<T> {
root: Node<RootState, T>,
}
impl<T> Router<T> {
pub(crate) const fn new(root: Node<RootState, T>) -> Self {
Self { root }
}
/// Searches for a matching template in the router.
///
/// Returns `None` if no template matches the path.
///
/// # Examples
///
/// ```rust
/// use wayfind::RouterBuilder;
///
/// let mut builder = RouterBuilder::new();
/// builder.insert("/users/<id>", 1)?;
///
/// let router = builder.build();
///
/// let search = router.search("/users/123").unwrap();
/// assert_eq!(search.data(), &1);
/// assert_eq!(search.template(), "/users/<id>");
/// assert_eq!(search.parameters(), &[("id", "123")]);
///
/// assert!(router.search("/not/found").is_none());
/// # Ok::<_, Box<dyn core::error::Error>>(())
/// ```
#[must_use]
pub fn search<'r, 'p>(&'r self, path: &'p str) -> Option<Match<'r, 'p, T>> {
let mut ctx = SearchContext::new();
let node = self.root.search(&mut ctx, path)?;
Some(Match {
data: &node.data,
template: &node.template,
parameters: ctx.parameters,
})
}
}
impl<T> fmt::Display for Router<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.root)
}
}