Skip to main content

actix_router/
pattern.rs

1/// One or many patterns.
2#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3pub enum Patterns {
4    Single(String),
5    List(Vec<String>),
6}
7
8impl Patterns {
9    pub fn is_empty(&self) -> bool {
10        match self {
11            Patterns::Single(_) => false,
12            Patterns::List(pats) => pats.is_empty(),
13        }
14    }
15}
16
17/// Helper trait for type that could be converted to one or more path patterns.
18pub trait IntoPatterns {
19    fn patterns(&self) -> Patterns;
20}
21
22impl IntoPatterns for String {
23    fn patterns(&self) -> Patterns {
24        Patterns::Single(self.clone())
25    }
26}
27
28impl IntoPatterns for &String {
29    fn patterns(&self) -> Patterns {
30        (*self).patterns()
31    }
32}
33
34impl IntoPatterns for str {
35    fn patterns(&self) -> Patterns {
36        Patterns::Single(self.to_owned())
37    }
38}
39
40impl IntoPatterns for &str {
41    fn patterns(&self) -> Patterns {
42        (*self).patterns()
43    }
44}
45
46impl IntoPatterns for bytestring::ByteString {
47    fn patterns(&self) -> Patterns {
48        Patterns::Single(self.to_string())
49    }
50}
51
52impl IntoPatterns for Patterns {
53    fn patterns(&self) -> Patterns {
54        self.clone()
55    }
56}
57
58impl<T: AsRef<str>> IntoPatterns for Vec<T> {
59    fn patterns(&self) -> Patterns {
60        let mut patterns = self.iter().map(|v| v.as_ref().to_owned());
61
62        match patterns.size_hint() {
63            (1, _) => Patterns::Single(patterns.next().unwrap()),
64            _ => Patterns::List(patterns.collect()),
65        }
66    }
67}
68
69macro_rules! array_patterns_single (($tp:ty) => {
70    impl IntoPatterns for [$tp; 1] {
71        fn patterns(&self) -> Patterns {
72            Patterns::Single(self[0].to_owned())
73        }
74    }
75});
76
77macro_rules! array_patterns_multiple (($tp:ty, $str_fn:expr, $($num:tt) +) => {
78    // for each array length specified in space-separated $num
79    $(
80        impl IntoPatterns for [$tp; $num] {
81            fn patterns(&self) -> Patterns {
82                Patterns::List(self.iter().map($str_fn).collect())
83            }
84        }
85    )+
86});
87
88array_patterns_single!(&str);
89array_patterns_multiple!(&str, |&v| v.to_owned(), 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16);
90
91array_patterns_single!(String);
92array_patterns_multiple!(String, |v| v.clone(), 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16);
93
94#[cfg(test)]
95mod tests {
96    use bytestring::ByteString;
97
98    use super::*;
99
100    #[test]
101    fn empty_patterns_are_distinguished_from_single_patterns() {
102        assert!(!Patterns::Single("/one".to_owned()).is_empty());
103        assert!(Patterns::List(Vec::new()).is_empty());
104        assert!(!Patterns::List(vec!["/one".to_owned()]).is_empty());
105    }
106
107    #[test]
108    fn supported_inputs_convert_to_patterns() {
109        let owned = "/owned".to_owned();
110        assert_eq!(owned.patterns(), Patterns::Single("/owned".to_owned()));
111        let owned_ref = &owned;
112        assert_eq!(owned_ref.patterns(), Patterns::Single("/owned".to_owned()));
113
114        let str_value: &str = "/str";
115        assert_eq!(
116            <str as IntoPatterns>::patterns(str_value),
117            Patterns::Single("/str".to_owned())
118        );
119        let ref_value: &str = "/ref";
120        assert_eq!(
121            <&str as IntoPatterns>::patterns(&ref_value),
122            Patterns::Single("/ref".to_owned())
123        );
124
125        let bytes = ByteString::from("/bytes");
126        assert_eq!(bytes.patterns(), Patterns::Single("/bytes".to_owned()));
127
128        let original = Patterns::List(vec!["/first".to_owned(), "/second".to_owned()]);
129        assert_eq!(original.patterns(), original);
130
131        assert_eq!(vec!["/one"].patterns(), Patterns::Single("/one".to_owned()));
132        assert_eq!(
133            vec!["/one", "/two"].patterns(),
134            Patterns::List(vec!["/one".to_owned(), "/two".to_owned()])
135        );
136        assert_eq!(
137            vec!["/one".to_owned()].patterns(),
138            Patterns::Single("/one".to_owned())
139        );
140
141        assert_eq!(["/one"].patterns(), Patterns::Single("/one".to_owned()));
142        assert_eq!(
143            ["/one", "/two"].patterns(),
144            Patterns::List(vec!["/one".to_owned(), "/two".to_owned()])
145        );
146        assert_eq!(
147            ["/one".to_owned()].patterns(),
148            Patterns::Single("/one".to_owned())
149        );
150        assert_eq!(
151            ["/one".to_owned(), "/two".to_owned()].patterns(),
152            Patterns::List(vec!["/one".to_owned(), "/two".to_owned()])
153        );
154    }
155}