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
//! Matchers used to compare against incoming segments.
//!
//! Values of type `Matcher` are stored inside a tree and used to match
//! against incoming segments in order to walk through the tree correctly.
use crate::capture::Capture;

/// Matching trait to enable generic route matching algorithms.
///
/// This trait backs the main tree, enabling custom segment matching based
/// on the needs of the end developer. In many cases it's wasteful to check
/// for things like RegEx, especially when all routes will only be static
/// (as an example).
pub trait Matcher: Send + Sync {
    /// Retrieves a potential capture from a segment.
    fn capture<'a>(&'a self, _segment: &str) -> Option<Capture<'a>> {
        None
    }

    /// Determines whether an incoming segment is a match for a base segment.
    fn is_match(&self, segment: &str) -> bool;
}

/// Blanket implementation of `Matcher` for pure functions.
///
/// Pure functions are assumed to not have a capture group, as there's no
/// way to directly name them at this point (unless derived from the input).
impl<F> Matcher for F
where
    F: Fn(&str) -> bool + Send + Sync,
{
    /// Determines whether an incoming segment is a match for a base segment.
    fn is_match(&self, segment: &str) -> bool {
        self(segment)
    }
}

/// Static path segment matcher.
///
/// This struct is constructed via the `StaticParser` and compares incoming
/// segments directly against the internal static `String` segment.
pub struct StaticMatcher {
    inner: String,
}

impl StaticMatcher {
    /// Constructs a new `StaticMatcher` from a segment.
    pub fn new<S: Into<String>>(s: S) -> Self {
        Self { inner: s.into() }
    }
}

impl Matcher for StaticMatcher {
    /// Compares an incoming segment against a literal base segment.
    fn is_match(&self, segment: &str) -> bool {
        self.inner == segment
    }
}

/// Dynamic path segment matcher.
///
/// This struct is constructed via the `DynamicParser` and assumes that any
/// incoming path segment is a candidate for matching.
pub struct DynamicMatcher {
    inner: String,
}

impl DynamicMatcher {
    /// Constructs a new `DynamicMatcher` from a segment.
    pub fn new<S: Into<String>>(s: S) -> Self {
        Self { inner: s.into() }
    }
}

impl Matcher for DynamicMatcher {
    /// Determines if there is a capture for the incoming segment.
    fn capture<'a>(&'a self, segment: &str) -> Option<Capture<'a>> {
        Some((&self.inner, (0, segment.len())))
    }

    /// Determines if this matcher matches the incoming segment.
    fn is_match(&self, _segment: &str) -> bool {
        true
    }
}