From 660aa5035ffaa04a6311a7e538e5690a1c0ea8e1 Mon Sep 17 00:00:00 2001 From: Boshen Date: Thu, 5 Dec 2024 23:12:19 +0800 Subject: [PATCH] feat: faster and stable path hash for the cache closes #322 --- src/cache.rs | 13 ++++++++++++- src/tests/resolve.rs | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/cache.rs b/src/cache.rs index e5a47da1..15447b07 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -42,9 +42,20 @@ impl Cache { } pub fn value(&self, path: &Path) -> CachedPath { + // `Path::hash` is slow: https://doc.rust-lang.org/std/path/struct.Path.html#impl-Hash-for-Path + // `path.as_os_str()` hash is not stable because we may joined a path like `foo/bar` and `foo\\bar` on windows. let hash = { let mut hasher = FxHasher::default(); - path.as_os_str().hash(&mut hasher); + for b in path + .as_os_str() + .as_encoded_bytes() + .iter() + .rev() + .filter(|&&b| b != b'/' && b != b'\\') + .take(10) + { + b.hash(&mut hasher); + } hasher.finish() }; if let Some(cache_entry) = self.paths.get((hash, path).borrow() as &dyn CacheKey) { diff --git a/src/tests/resolve.rs b/src/tests/resolve.rs index f2dbb88e..d961edca 100644 --- a/src/tests/resolve.rs +++ b/src/tests/resolve.rs @@ -117,3 +117,24 @@ fn resolve_hash_as_module() { let resolution = resolver.resolve(f, "#a"); assert_eq!(resolution, Err(ResolveError::NotFound("#a".into()))); } + +#[cfg(windows)] +#[test] +fn resolve_normalized_on_windows() { + use std::path::PathBuf; + + use normalize_path::NormalizePath; + + let f = super::fixture(); + let absolute = f.join("./foo/index.js").normalize(); + let absolute_str = absolute.to_string_lossy(); + let normalized_absolute = absolute_str.replace('\\', "/"); + let resolver = Resolver::new(ResolveOptions::default()); + + let resolution = resolver.resolve(&f, &normalized_absolute).map(|r| r.full_path()); + assert_eq!(resolution, Ok(PathBuf::from(absolute_str.as_ref()))); + + let normalized_f = f.to_str().unwrap().replace('\\', "/"); + let resolution = resolver.resolve(normalized_f, ".\\foo\\index.js").map(|r| r.full_path()); + assert_eq!(resolution, Ok(PathBuf::from(absolute_str.as_ref()))); +}