use { glob, lazy_regex::regex, serde::{de::Error, Deserialize, Deserializer}, std::path::Path, }; #[derive(Debug, Clone, PartialEq, Hash, Eq)] pub struct Glob { pattern: glob::Pattern, } #[derive(Debug, Clone, Copy, PartialEq)] pub enum SpecialHandling { None, Enter, NoEnter, Hide, } #[derive(Debug, Clone)] pub struct SpecialPath { pub pattern: glob::Pattern, pub handling: SpecialHandling, } pub trait SpecialPathList { fn find(self, path: &Path) -> SpecialHandling; } impl<'de> Deserialize<'de> for SpecialHandling { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { let s = String::deserialize(deserializer)?; let s = s.to_lowercase(); // we remove non letters so to accept eg "no-enter" let s = regex!(r"\W+").replace_all(&s, ""); match s.as_ref() { "none" => Ok(SpecialHandling::None), "enter" => Ok(SpecialHandling::Enter), "noenter" => Ok(SpecialHandling::NoEnter), "hide" => Ok(SpecialHandling::Hide), _ => Err(D::Error::custom(format!( "unrecognized special handling: {:?}", s ))), } } } impl<'de> Deserialize<'de> for Glob { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { let s = String::deserialize(deserializer)?; glob::Pattern::new(&s) .map_err(|e| D::Error::custom(format!("invalid glob pattern {:?} : {:?}", s, e))) .map(|pattern| Glob { pattern }) } } impl SpecialPath { pub fn new(glob: Glob, handling: SpecialHandling) -> Self { Self { pattern: glob.pattern, handling, } } pub fn can_have_matches_in(&self, path: &Path) -> bool { path.to_str() .map_or(false, |p| self.pattern.as_str().starts_with(p)) } } impl SpecialPathList for &[SpecialPath] { fn find(self, path: &Path) -> SpecialHandling { for sp in self { if sp.pattern.matches_path(path) { return sp.handling; } } SpecialHandling::None } }