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,
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 AsRef<Path> for ArcPath {
89  fn as_ref(&self) -> &Path {
90    &self.path
91  }
92}
93
94impl From<PathBuf> for ArcPath {
95  fn from(value: PathBuf) -> Self {
96    ArcPath::new(value.into())
97  }
98}
99
100impl From<&Path> for ArcPath {
101  fn from(value: &Path) -> Self {
102    ArcPath::new(value.into())
103  }
104}
105
106impl From<&Utf8Path> for ArcPath {
107  fn from(value: &Utf8Path) -> Self {
108    ArcPath::new(value.as_std_path().into())
109  }
110}
111
112impl From<&ArcPath> for ArcPath {
113  fn from(value: &ArcPath) -> Self {
114    value.clone()
115  }
116}
117
118impl From<&str> for ArcPath {
119  fn from(value: &str) -> Self {
120    ArcPath::new(<str as std::convert::AsRef<Path>>::as_ref(value).into())
121  }
122}
123
124impl CustomConverter for ArcPath {
125  type Target = PortablePath;
126  fn serialize(&self, guard: &ContextGuard) -> Result<Self::Target, CacheableError> {
127    Ok(PortablePath::new(&self.path, guard.project_root()))
128  }
129  fn deserialize(data: Self::Target, guard: &ContextGuard) -> Result<Self, CacheableError> {
130    Ok(Self::from(PathBuf::from(
131      data.into_path_string(guard.project_root()),
132    )))
133  }
134}
135
136impl Hash for ArcPath {
137  #[inline]
138  fn hash<H: Hasher>(&self, state: &mut H) {
139    state.write_u64(self.hash);
140  }
141}
142
143/// A standard `HashMap` using `ArcPath` as the key type with a custom `Hasher`
144/// that just uses the precomputed hash for speed instead of calculating it.
145pub type ArcPathMap<V> = HashMap<ArcPath, V, BuildHasherDefault<IdentityHasher>>;
146
147/// A standard `HashSet` using `ArcPath` as the key type with a custom `Hasher`
148/// that just uses the precomputed hash for speed instead of calculating it.
149pub type ArcPathSet = HashSet<ArcPath, BuildHasherDefault<IdentityHasher>>;
150
151/// A standard `DashMap` using `ArcPath` as the key type with a custom `Hasher`
152/// that just uses the precomputed hash for speed instead of calculating it.
153pub type ArcPathDashMap<V> = DashMap<ArcPath, V, BuildHasherDefault<IdentityHasher>>;
154
155/// A standard `DashSet` using `ArcPath` as the key type with a custom `Hasher`
156/// that just uses the precomputed hash for speed instead of calculating it.
157pub type ArcPathDashSet = DashSet<ArcPath, BuildHasherDefault<IdentityHasher>>;
158
159/// A standard `IndexSet` using `ArcPath` as the key type with a custom `Hasher`
160/// that just uses the precomputed hash for speed instead of calculating it.
161pub type ArcPathIndexSet = IndexSet<ArcPath, BuildHasherDefault<IdentityHasher>>;