#![forbid(unsafe_code)]
use std::path::{Path, PathBuf};
#[derive(Debug, PartialEq)]
pub struct ParsedPattern {
directory: PathBuf,
pattern: Vec<String>,
}
impl ParsedPattern {
pub fn new(path: &Path) -> Self {
Self {
directory: match path.parent() {
None => PathBuf::from("/"),
Some(directory) => directory.to_owned(),
},
pattern: match path.file_name() {
None => vec![String::from("")],
Some(file_name_pattern) => file_name_pattern
.to_str()
.unwrap()
.split("*")
.map(|part| part.to_string())
.filter(|str| !str.is_empty())
.collect(),
},
}
}
pub fn match_to_pattern(&self, file_name: &String) -> Result<Vec<String>, ()> {
if self.pattern.is_empty() {
return Ok(vec![file_name.clone()]);
}
if self.pattern.len() == 1 && self.pattern[0].is_empty() {
match file_name.is_empty() {
false => return Err(()),
true => return Ok(Vec::<String>::new()),
}
}
let mut file_name = file_name.clone();
let mut found_fragments = Vec::<String>::new();
let mut new_fragment = String::new();
let mut first_pattern = true;
for pattern_part in &self.pattern {
while !file_name.is_empty() && !file_name.starts_with(pattern_part) {
let (prefix, suffix) = file_name.split_at(1);
new_fragment += prefix;
file_name = suffix.to_string();
}
if file_name.starts_with(pattern_part) {
if !first_pattern || !new_fragment.is_empty() {
found_fragments.push(new_fragment);
}
first_pattern = false;
new_fragment = String::new();
let (_, new_file_name) = file_name.split_at(pattern_part.len());
file_name = new_file_name.to_string();
} else {
return Err(());
}
}
if !file_name.is_empty() {
found_fragments.push(file_name);
}
Ok(found_fragments)
}
pub fn get_directory(&self) -> &PathBuf {
&self.directory
}
}
#[test]
fn test_new() {
let directory = PathBuf::from("/");
let pattern = vec![String::from("")];
let path = Path::new("");
assert_eq!(
ParsedPattern {
directory: directory,
pattern: pattern,
},
ParsedPattern::new(path)
);
let directory = PathBuf::from("src/");
let pattern = vec![String::from("test.txt")];
let path = Path::new("src/test.txt");
assert_eq!(
ParsedPattern {
directory: directory,
pattern: pattern,
},
ParsedPattern::new(path)
);
let directory = PathBuf::from("src/");
let pattern = vec![String::from("test.")];
let path = Path::new("src/test.*");
assert_eq!(
ParsedPattern {
directory: directory,
pattern: pattern,
},
ParsedPattern::new(path)
);
let directory = PathBuf::from("src/");
let pattern = vec![String::from("t"), String::from(".")];
let path = Path::new("src/t*.*");
assert_eq!(
ParsedPattern {
directory: directory,
pattern: pattern,
},
ParsedPattern::new(path)
);
}
#[test]
fn test_matching() {
let directory = PathBuf::from("src/");
let pattern = vec![String::from("te"), String::from("t.")];
let path = Path::new("src/te*t.*");
let parsed_pattern = ParsedPattern::new(path);
assert_eq!(ParsedPattern { directory, pattern }, parsed_pattern);
assert_eq!(
Ok(vec![String::from("s"), String::from("txt")]),
parsed_pattern.match_to_pattern(&String::from("test.txt"))
);
let directory = PathBuf::from("src/");
let pattern = vec![];
let path = Path::new("src/*");
let parsed_pattern = ParsedPattern::new(path);
assert_eq!(ParsedPattern { directory, pattern }, parsed_pattern);
assert_eq!(
Ok(vec![String::from("test.txt")]),
parsed_pattern.match_to_pattern(&String::from("test.txt"))
);
let directory = PathBuf::from("/");
let pattern = vec![String::from("")];
let path = Path::new("");
let parsed_pattern = ParsedPattern::new(path);
assert_eq!(ParsedPattern { directory, pattern }, parsed_pattern);
assert_eq!(
Err(()),
parsed_pattern.match_to_pattern(&String::from("test.txt"))
);
}