1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
//! Similar to [std::path::*](std::path)
use std::path::{Component, Path, PathBuf, Prefix};
/// Cleanup/simplify path as much as possible
///
/// # Examples
///
/// ```rust
/// # use std::path::Path;
/// # use mmrbi::path::cleanup;
/// assert_eq!(cleanup("a/b"), Path::new("a/b"));
/// assert_eq!(cleanup("a/b/.."), Path::new("a"));
/// assert_eq!(cleanup("a/b/../.."), Path::new("."));
/// assert_eq!(cleanup("a/b/../../.."), Path::new(".."));
/// assert_eq!(cleanup("a/b/../../../.."), Path::new("../.."));
///
/// assert_eq!(cleanup("../../a/b"), Path::new("../../a/b"));
/// assert_eq!(cleanup("../../a/b/.."), Path::new("../../a"));
/// assert_eq!(cleanup("../../a/b/../.."), Path::new("../.."));
/// assert_eq!(cleanup("../../a/b/../../.."), Path::new("../../.."));
/// assert_eq!(cleanup("../../a/b/../../../.."), Path::new("../../../.."));
///
/// if cfg!(windows) {
/// assert_eq!(cleanup(r"C:\foo\bar"), Path::new(r"C:\foo\bar"));
/// assert_eq!(cleanup(r"\\?\C:\foo\bar"), Path::new(r"C:\foo\bar"));
/// }
/// ```
pub fn cleanup(path: impl AsRef<Path>) -> PathBuf {
let mut p = PathBuf::new();
let mut components = path.as_ref().components();
while let Some(c) = components.next() {
match c {
Component::Prefix(pre) => match pre.kind() {
Prefix::Disk(disk) | Prefix::VerbatimDisk(disk) => {
p.clear();
p.push(format!("{}:\\", char::from(disk)));
let _root = components.next();
},
_other => {
p.clear();
p.push(c);
}
},
c @ Component::RootDir => {
p.clear();
p.push(c);
},
Component::CurDir => {},
Component::ParentDir => {
if p.ends_with("..") || !p.pop() {
p.push("..");
}
},
Component::Normal(c) => {
p.push(c);
},
}
}
if p == Path::new("") {
p.push(".");
}
p
}