Skip to main content

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