use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::Mutex;
use crate::indicator::Match;
use crate::registry::Registry;
fn normalize(p: &Path) -> PathBuf {
p.components().collect()
}
impl Registry {
pub fn resolve_for_path(&self, file_path: impl AsRef<Path>) -> Option<(PathBuf, Vec<Match>)> {
let mut dir = normalize(file_path.as_ref().parent()?);
loop {
let m = self.detect(&dir);
if !m.is_empty() {
return Some((dir, m));
}
match dir.parent() {
Some(parent) => dir = parent.to_path_buf(),
None => return None,
}
}
}
}
pub struct Resolver<'a> {
registry: &'a Registry,
root: PathBuf,
cache: Mutex<HashMap<PathBuf, Vec<Match>>>,
}
impl<'a> Resolver<'a> {
pub fn new(root: impl AsRef<Path>, registry: &'a Registry) -> Self {
Resolver {
registry,
root: normalize(root.as_ref()),
cache: Mutex::new(HashMap::new()),
}
}
pub fn resolve(&self, file_path: impl AsRef<Path>) -> Vec<Match> {
let mut dir = match file_path.as_ref().parent() {
Some(p) => normalize(p),
None => return Vec::new(),
};
loop {
let m = self.detect_cached(&dir);
if !m.is_empty() {
return m;
}
if dir == self.root {
return Vec::new();
}
match dir.parent() {
Some(parent) => dir = parent.to_path_buf(),
None => return Vec::new(),
}
}
}
fn detect_cached(&self, dir: &Path) -> Vec<Match> {
if let Some(cached) = self.cache.lock().unwrap().get(dir) {
return cached.clone();
}
let m = self.registry.detect(dir);
self.cache
.lock()
.unwrap()
.insert(dir.to_path_buf(), m.clone());
m
}
}