Skip to main content

rspack_cacheable/utils/
portable_path.rs

1use std::path::Path;
2
3use sugar_path::SugarPath;
4
5use crate::{ContextGuard, Result, cacheable, with::AsConverter};
6
7/// A portable path representation that can be serialized and deserialized across different
8/// environments with different project roots.
9///
10/// When serializing with a `project_root`, absolute paths are converted to relative paths.
11/// When deserializing, relative paths are resolved back to absolute paths.
12///
13/// # Example
14///
15/// ```rust,ignore
16/// // Serialize on Linux (project_root = /home/user/project)
17/// let path = PathBuf::from("/home/user/project/src/main.rs");
18/// // Stored as: "src/main.rs" (relative)
19///
20/// // Deserialize on Windows (project_root = C:\workspace)
21/// // Results in: "C:\workspace\src\main.rs"
22/// ```
23#[cacheable(crate=crate, hashable)]
24pub struct PortablePath {
25  path: String,
26  /// Whether the path was transformed to relative during serialization
27  transformed: bool,
28}
29
30impl PortablePath {
31  /// Create a portable path, converting to relative if both path and project_root are absolute
32  pub fn new(path: &Path, project_root: Option<&Path>) -> Self {
33    if path.is_absolute()
34      && let Some(project_root) = project_root
35    {
36      return Self {
37        path: path.relative(project_root).to_slash_lossy().into_owned(),
38        transformed: true,
39      };
40    }
41
42    Self {
43      path: path.to_slash_lossy().into_owned(),
44      transformed: false,
45    }
46  }
47
48  /// Convert back to path string using project_root if the path was transformed
49  pub fn into_path_string(self, project_root: Option<&Path>) -> String {
50    if self.transformed
51      && let Some(project_root) = project_root
52    {
53      return self
54        .path
55        .absolutize_with(project_root)
56        .to_string_lossy()
57        .into_owned();
58    }
59    self.path
60  }
61}
62
63impl<T> AsConverter<T> for PortablePath
64where
65  T: From<String> + AsRef<Path>,
66{
67  fn serialize(data: &T, guard: &ContextGuard) -> Result<Self>
68  where
69    Self: Sized,
70  {
71    Ok(Self::new(data.as_ref(), guard.project_root()))
72  }
73
74  fn deserialize(self, guard: &ContextGuard) -> Result<T> {
75    Ok(T::from(self.into_path_string(guard.project_root())))
76  }
77}