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
//! Defines the wrapping type for a segment-matching regex.

use regex::Regex;

use std::cmp::Ordering;
use std::panic::AssertUnwindSafe;

/// A unwind-safe wrapper for Regex that implements PartialEq, Eq, PartialOrd, and Ord.  These
/// traits are implemented in a potentially error-prone way by comparing the underlying &str
/// representations of the regular expression.
///
/// If the `ConstrainedSegmentRegex::is_match` traps a panic from `Regex::is_match`,
/// `std::process::abort()` will be called and the program will terminate.
pub struct ConstrainedSegmentRegex {
    regex: AssertUnwindSafe<Regex>,
}

impl ConstrainedSegmentRegex {
    /// Creates a new ConstrainedSegmentRegex from a provided string.
    ///
    /// It wraps the string in begin and end of line anchors to prevent it from matching more than
    /// intended.
    pub fn new(regex: &str) -> Self {
        ConstrainedSegmentRegex {
            regex: AssertUnwindSafe(Regex::new(&format!("^{}$", regex)).unwrap()),
        }
    }

    /// Returns the pattern backing this regex as a `&str`.
    #[inline]
    pub(crate) fn as_str(&self) -> &str {
        self.regex.as_str()
    }

    /// Wraps `regex::Regex::is_match` to return true if and only if the regex matches the string
    /// given.
    #[inline]
    pub(crate) fn is_match(&self, s: &str) -> bool {
        self.regex.is_match(s)
    }
}

impl PartialEq for ConstrainedSegmentRegex {
    fn eq(&self, other: &Self) -> bool {
        self.regex.as_str() == other.regex.as_str()
    }
}

impl Eq for ConstrainedSegmentRegex {}

impl PartialOrd for ConstrainedSegmentRegex {
    fn partial_cmp(&self, other: &ConstrainedSegmentRegex) -> Option<Ordering> {
        Some(self.as_str().cmp(other.as_str()))
    }
}

impl Ord for ConstrainedSegmentRegex {
    fn cmp(&self, other: &Self) -> Ordering {
        self.as_str().cmp(other.as_str())
    }
}

impl Clone for ConstrainedSegmentRegex {
    fn clone(&self) -> ConstrainedSegmentRegex {
        ConstrainedSegmentRegex {
            regex: AssertUnwindSafe(self.regex.0.clone()),
        }
    }
}