rspack_paths/
lib.rs

1use std::{
2  collections::{HashMap, HashSet},
3  fmt::Debug,
4  hash::{BuildHasherDefault, Hash, Hasher},
5  ops::{Deref, DerefMut},
6  path::{Path, PathBuf},
7  sync::Arc,
8};
9
10pub use camino::{Utf8Component, Utf8Components, Utf8Path, Utf8PathBuf, Utf8Prefix};
11use dashmap::{DashMap, DashSet};
12use indexmap::IndexSet;
13use rspack_cacheable::{
14  cacheable,
15  with::{AsRefStr, AsRefStrConverter},
16};
17use rustc_hash::FxHasher;
18use ustr::IdentityHasher;
19
20pub trait AssertUtf8 {
21  type Output;
22  fn assert_utf8(self) -> Self::Output;
23}
24
25impl AssertUtf8 for PathBuf {
26  type Output = Utf8PathBuf;
27
28  /// Assert `self` is a valid UTF-8 [`PathBuf`] and convert to [`Utf8PathBuf`]
29  ///
30  /// # Panics
31  ///
32  /// Panics if `self` is not a valid UTF-8 path.
33  fn assert_utf8(self) -> Self::Output {
34    Utf8PathBuf::from_path_buf(self).unwrap_or_else(|p| {
35      panic!("expected UTF-8 path, got: {}", p.display());
36    })
37  }
38}
39
40impl<'a> AssertUtf8 for &'a Path {
41  type Output = &'a Utf8Path;
42
43  /// Assert `self` is a valid UTF-8 [`Path`] and convert to [`Utf8Path`]
44  ///
45  /// # Panics
46  ///
47  /// Panics if `self` is not a valid UTF-8 path.
48  fn assert_utf8(self) -> Self::Output {
49    Utf8Path::from_path(self).unwrap_or_else(|| {
50      panic!("expected UTF-8 path, got: {}", self.display());
51    })
52  }
53}
54
55#[cacheable(with=AsRefStr, hashable)]
56#[derive(Clone, PartialEq, Eq)]
57pub struct ArcPath {
58  path: Arc<Path>,
59  // Pre-calculating and caching the hash value upon creation, making hashing operations
60  // in collections virtually free.
61  hash: u64,
62}
63
64impl Debug for ArcPath {
65  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66    self.path.fmt(f)
67  }
68}
69
70impl ArcPath {
71  pub fn new(path: Arc<Path>) -> Self {
72    let mut hasher = FxHasher::default();
73    path.hash(&mut hasher);
74    let hash = hasher.finish();
75    Self { path, hash }
76  }
77}
78
79impl Deref for ArcPath {
80  type Target = Arc<Path>;
81
82  fn deref(&self) -> &Self::Target {
83    &self.path
84  }
85}
86
87impl DerefMut for ArcPath {
88  fn deref_mut(&mut self) -> &mut Self::Target {
89    &mut self.path
90  }
91}
92
93impl AsRef<Path> for ArcPath {
94  fn as_ref(&self) -> &Path {
95    &self.path
96  }
97}
98
99impl From<PathBuf> for ArcPath {
100  fn from(value: PathBuf) -> Self {
101    ArcPath::new(value.into())
102  }
103}
104
105impl From<&Path> for ArcPath {
106  fn from(value: &Path) -> Self {
107    ArcPath::new(value.into())
108  }
109}
110
111impl From<&Utf8Path> for ArcPath {
112  fn from(value: &Utf8Path) -> Self {
113    ArcPath::new(value.as_std_path().into())
114  }
115}
116
117impl From<&ArcPath> for ArcPath {
118  fn from(value: &ArcPath) -> Self {
119    value.clone()
120  }
121}
122
123impl From<&str> for ArcPath {
124  fn from(value: &str) -> Self {
125    ArcPath::new(<str as std::convert::AsRef<Path>>::as_ref(value).into())
126  }
127}
128
129impl AsRefStrConverter for ArcPath {
130  fn as_str(&self) -> &str {
131    self.path.to_str().expect("expect utf8 str")
132  }
133  fn from_str(s: &str) -> Self {
134    Self::from(Path::new(s))
135  }
136}
137
138impl Hash for ArcPath {
139  #[inline]
140  fn hash<H: Hasher>(&self, state: &mut H) {
141    state.write_u64(self.hash);
142  }
143}
144
145/// A standard `HashMap` using `ArcPath` as the key type with a custom `Hasher`
146/// that just uses the precomputed hash for speed instead of calculating it.
147pub type ArcPathMap<V> = HashMap<ArcPath, V, BuildHasherDefault<IdentityHasher>>;
148
149/// A standard `HashSet` using `ArcPath` as the key type with a custom `Hasher`
150/// that just uses the precomputed hash for speed instead of calculating it.
151pub type ArcPathSet = HashSet<ArcPath, BuildHasherDefault<IdentityHasher>>;
152
153/// A standard `DashMap` using `ArcPath` as the key type with a custom `Hasher`
154/// that just uses the precomputed hash for speed instead of calculating it.
155pub type ArcPathDashMap<V> = DashMap<ArcPath, V, BuildHasherDefault<IdentityHasher>>;
156
157/// A standard `DashSet` using `ArcPath` as the key type with a custom `Hasher`
158/// that just uses the precomputed hash for speed instead of calculating it.
159pub type ArcPathDashSet = DashSet<ArcPath, BuildHasherDefault<IdentityHasher>>;
160
161/// A standard `IndexSet` using `ArcPath` as the key type with a custom `Hasher`
162/// that just uses the precomputed hash for speed instead of calculating it.
163pub type ArcPathIndexSet = IndexSet<ArcPath, BuildHasherDefault<IdentityHasher>>;