1use std::{convert::From, ops::Deref};
2
3#[derive(Clone, Debug, Eq, Hash, PartialEq)]
4pub struct Pattern(String);
5
6impl Pattern {
7 pub fn new<S: Into<String>>(pattern: S) -> Self {
8 Pattern(pattern.into())
9 }
10
11 pub fn contains(&self, other: &Pattern) -> bool {
13 if self == other {
14 true
15 } else {
16 other.0.starts_with(&self.0)
18 && (self.0.len() == 1 || other.0.chars().nth(self.0.len()) == Some('/'))
19 }
20 }
21}
22
23impl Deref for Pattern {
24 type Target = String;
25
26 fn deref(&self) -> &Self::Target {
27 &self.0
28 }
29}
30
31impl<S> From<S> for Pattern
32where
33 S: Into<String>,
34{
35 fn from(s: S) -> Pattern {
36 Pattern::new(s)
37 }
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43
44 #[test]
45 fn test_root_namespace() {
46 assert!(Pattern::new("/").contains(&Pattern::new("/a")));
47 }
48
49 #[test]
50 fn test_equality() {
51 assert_eq!(Pattern::new("/a"), Pattern::new("/a"));
52 }
53
54 #[test]
55 fn test_case_inequality() {
56 assert_ne!(Pattern::new("/a"), Pattern::new("/A"));
57 }
58
59 #[test]
60 fn test_inequality() {
61 assert!(!Pattern::new("/a/b").contains(&Pattern::new("/ab")));
62 }
63
64 #[test]
65 fn test_contains_child_namespace() {
66 assert!(Pattern::new("/a").contains(&Pattern::new("/a/b")));
67 }
68
69 #[test]
70 fn test_not_contains_parent() {
71 assert!(!Pattern::new("/a/b").contains(&Pattern::new("/a")));
72 }
73}