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
//! Parsers used to create `Matcher` values from segments.
//!
//! Values of type `Parser` are required to construct `Matcher` values
//! at tree creation time, to specify priority order when routing an
//! incoming set of segments. A parser can also be a pure function which
//! can derive a potential `Matcher` from an input segment directly.
use crate::matcher::{DynamicMatcher, Matcher, StaticMatcher};

/// Parsing trait to enable conversion from literals into matchers.
///
/// This is used to run through a cascading parsing flow to enable custom
/// matchers being implemented. This trait enables all segment matching to
/// be determined at creation time to avoid any costs at routing time.
pub trait Parser: Send + Sync {
    /// Attempts to parse a `Matcher` out of a segment.
    fn parse(&self, segment: &str) -> Option<Box<Matcher>>;
}

/// Blanket implementation of `Parser` for pure functions.
impl<F> Parser for F
where
    F: Fn(&str) -> Option<Box<Matcher>> + Send + Sync,
{
    /// Attempts to parse a `Matcher` out of a segment.
    fn parse(&self, segment: &str) -> Option<Box<Matcher>> {
        self(segment)
    }
}

/// Segment parser to generate static route matchers.
pub struct StaticParser;

/// `Parser` implementation for the static matcher.
impl Parser for StaticParser {
    /// Parses out a static matcher from a segment literal.
    ///
    /// Note that although this returns a result, it will never fail
    /// as every string literal can be treated as a static matcher.
    fn parse(&self, segment: &str) -> Option<Box<Matcher>> {
        Some(Box::new(StaticMatcher::new(segment)))
    }
}

/// Segment parser to generate dynamic router matchers.
pub struct DynamicParser;

impl Parser for DynamicParser {
    /// Parses out a dynamic segment based on the `:.+` syntax.
    ///
    /// If you wish to use a custom syntax, you can construct a custom `Parser`
    /// implementation which constructs a `DynamicMatcher` instance.
    fn parse(&self, segment: &str) -> Option<Box<Matcher>> {
        if &segment[0..1] != ":" || segment.len() == 1 {
            return None;
        }

        let field = &segment[1..];
        let matcher = DynamicMatcher::new(field);

        Some(Box::new(matcher))
    }
}