1#![cfg_attr(not(target_os = "windows"), allow(unused))]
2#[cfg(windows)]
3use crate::{Drives, PathExt};
4use std::{
5 borrow::Cow,
6 fs,
7 path::{Path, PathBuf},
8};
9
10#[derive(Default)]
11pub struct SimpleUnc {
12 pub map_to_drive: bool,
23
24 pub skip_dunce: bool,
28}
29
30impl SimpleUnc {
31 pub fn canonicalize(&self, path: impl AsRef<Path>) -> anyhow::Result<PathBuf> {
32 let canonicalized = fs::canonicalize(path)?;
33 #[cfg(windows)]
34 if let Some(simplified) = self.simplify(&canonicalized)? {
35 return Ok(simplified.into_owned());
36 }
37 Ok(canonicalized)
38 }
39
40 pub fn simplify<'a>(&self, path: &'a Path) -> anyhow::Result<Option<Cow<'a, Path>>> {
41 #[cfg(windows)]
42 {
43 if let Some(drive_path) = Drives::drive_path(path)? {
45 if self.map_to_drive {
46 return Ok(Some(Cow::Owned(drive_path.to_path_buf())));
47 }
48 if let Some(stripped) = path.strip_win32_file_namespace_unc() {
49 return Ok(Some(Cow::Owned(stripped)));
50 }
51 }
52
53 if !self.skip_dunce {
54 let simplified = dunce::simplified(path);
56 if !std::ptr::eq(path, simplified) {
57 return Ok(Some(Cow::Borrowed(simplified)));
58 }
59 }
60 }
61 Ok(None)
62 }
63
64 pub fn refresh() -> anyhow::Result<()> {
66 #[cfg(windows)]
67 Drives::refresh()?;
68 Ok(())
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn simplify_none() {
78 let unc = SimpleUnc::default();
79 assert_eq!(unc.simplify(Path::new(r"C:\foo")).unwrap(), None);
80 }
81
82 #[cfg(windows)]
83 #[test]
84 fn simplify_dunce() {
85 let unc = SimpleUnc::default();
86 assert_eq!(
87 unc.simplify(Path::new(r"\\?\C:\foo")).unwrap(),
88 Some(Cow::Borrowed(Path::new(r"C:\foo")))
89 );
90 }
91
92 #[cfg(windows)]
93 #[test]
94 fn simplify_dunce_skip() {
95 let unc = SimpleUnc {
96 skip_dunce: true,
97 ..Default::default()
98 };
99 assert_eq!(unc.simplify(Path::new(r"\\?\C:\foo")).unwrap(), None);
100 }
101}