use std::path::Path;
use std::sync::OnceLock;
use dashmap::DashMap;
use crate::core::NormalizedPath;
fn canonicalize_cache() -> &'static DashMap<String, NormalizedPath> {
static CACHE: OnceLock<DashMap<String, NormalizedPath>> = OnceLock::new();
CACHE.get_or_init(DashMap::new)
}
const CANONICALIZE_CACHE_MAX_ENTRIES: usize = 64 * 1024;
#[cfg(test)]
pub(crate) fn canonicalize_cache_len_for_test() -> usize {
canonicalize_cache().len()
}
pub fn canonicalize_path(path: &Path, cwd: &Path) -> NormalizedPath {
let key = path.to_string_lossy().into_owned();
let cache = canonicalize_cache();
if let Some(cached) = cache.get(&key) {
return cached.clone();
}
let canonical = std::fs::canonicalize(path).unwrap_or_else(|_| {
if path.is_absolute() {
path.to_path_buf()
} else {
cwd.join(path)
}
});
let result = strip_win_prefix(canonical.into());
if cache.len() < CANONICALIZE_CACHE_MAX_ENTRIES {
cache.insert(key, result.clone());
}
result
}
pub fn strip_win_prefix(path: NormalizedPath) -> NormalizedPath {
#[cfg(windows)]
{
let s = path.to_string_lossy();
if let Some(stripped) = s.strip_prefix(r"\\?\") {
return NormalizedPath::from(stripped);
}
}
path
}