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 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 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 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
149pub type ArcPathMap<V> = HashMap<ArcPath, V, BuildHasherDefault<IdentityHasher>>;
152
153pub type ArcPathSet = HashSet<ArcPath, BuildHasherDefault<IdentityHasher>>;
156
157pub type ArcPathDashMap<V> = DashMap<ArcPath, V, BuildHasherDefault<IdentityHasher>>;
160
161pub type ArcPathDashSet = DashSet<ArcPath, BuildHasherDefault<IdentityHasher>>;
164
165pub type ArcPathIndexSet = IndexSet<ArcPath, BuildHasherDefault<IdentityHasher>>;