1use std::ffi::OsString;
3use std::fmt::Display;
4use std::ops::Deref;
5use std::path::{Path, PathBuf};
6
7#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub struct AbsolutePath(PathBuf);
10
11impl From<PathBuf> for AbsolutePath {
12 fn from(p: PathBuf) -> Self {
13 if p.is_absolute() {
14 Self(p)
15 } else {
16 let current_dir = std::env::current_dir().expect("Cannot determine current dir");
17 let joined = current_dir.join(p);
18 Self(
19 joined
20 .canonicalize()
21 .unwrap_or_else(|_| panic!("Cannot canonicalize {:?}", joined)),
22 )
23 }
24 }
25}
26
27impl Display for AbsolutePath {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 write!(f, "{}", self.0.to_string_lossy())
30 }
31}
32
33impl AbsolutePath {
34 pub fn into_os_string(&self) -> OsString {
36 self.0.clone().as_os_str().to_os_string()
37 }
38
39 pub fn as_path(&self) -> &Path {
41 &self.0
42 }
43
44 pub fn join<T>(&self, p: T) -> AbsolutePath
46 where
47 T: AsRef<Path>,
48 {
49 assert!(!p.as_ref().is_absolute());
50 Self(self.0.join(p))
51 }
52}
53
54impl From<&PathBuf> for AbsolutePath {
55 fn from(p: &PathBuf) -> Self {
56 Self::from(p.to_owned())
57 }
58}
59
60impl From<&Path> for AbsolutePath {
61 fn from(p: &Path) -> Self {
62 Self::from(p.to_path_buf())
63 }
64}
65
66impl From<AbsolutePath> for PathBuf {
67 fn from(a: AbsolutePath) -> Self {
68 a.0
69 }
70}
71
72impl From<&str> for AbsolutePath {
73 fn from(s: &str) -> Self {
74 Self::from(PathBuf::from(s.to_string()))
75 }
76}
77
78impl From<String> for AbsolutePath {
79 fn from(s: String) -> Self {
80 Self::from(PathBuf::from(s))
81 }
82}
83
84impl Deref for AbsolutePath {
85 type Target = Path;
86
87 fn deref(&self) -> &Self::Target {
88 &self.0
89 }
90}
91
92impl AsRef<Path> for AbsolutePath {
93 fn as_ref(&self) -> &Path {
94 self.0.as_path()
95 }
96}