Simple tool for automatic file management
1use std::fmt;
2use std::path::Path;
3
4use serde::{de, Deserialize};
5use wildmatch::WildMatch;
6
7/// Patterns that can be matched against files
8#[derive(Debug, Deserialize)]
9#[serde(rename_all = "snake_case")]
10pub enum Pattern {
11 #[serde(deserialize_with = "deserialize_wildcard")]
12 Wildcard(WildMatch),
13 #[serde(deserialize_with = "deserialize_regex")]
14 Regex(regex::Regex),
15 Exact(Box<Path>),
16}
17
18impl Pattern {
19 pub fn matches(&self, path: &Path) -> bool {
20 match *self {
21 Self::Wildcard(ref pattern) => pattern.matches(path.to_str().unwrap()),
22 Self::Regex(ref pattern) => pattern.is_match(path.to_str().unwrap()),
23 Self::Exact(ref pattern) => **pattern == *path,
24 }
25 }
26}
27
28struct RegexVisitor;
29
30impl<'de> de::Visitor<'de> for RegexVisitor {
31 type Value = regex::Regex;
32
33 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
34 write!(formatter, "expected regex string")
35 }
36
37 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
38 where
39 E: de::Error,
40 {
41 match regex::Regex::new(s) {
42 Ok(regex) => Ok(regex),
43 Err(regex::Error::Syntax(ref desc)) => {
44 Err(E::invalid_value(de::Unexpected::Str(s), &desc.as_str()))
45 }
46 Err(_) => unreachable!(),
47 }
48 }
49}
50
51fn deserialize_regex<'de, D>(des: D) -> Result<regex::Regex, D::Error>
52where
53 D: serde::Deserializer<'de>,
54{
55 des.deserialize_str(RegexVisitor)
56}
57
58struct WildcardVisitor;
59
60impl<'de> de::Visitor<'de> for WildcardVisitor {
61 type Value = WildMatch;
62
63 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
64 write!(formatter, "expected regex string")
65 }
66
67 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
68 where
69 E: de::Error,
70 {
71 Ok(WildMatch::new(s))
72 }
73}
74
75fn deserialize_wildcard<'de, D>(des: D) -> Result<WildMatch, D::Error>
76where
77 D: serde::Deserializer<'de>,
78{
79 des.deserialize_str(WildcardVisitor)
80}