#[derive(Clone)]
pub struct Path {
paths: Vec<String>,
sep: String,
}
impl Path {
pub fn system<T: AsRef<str>>(path: T) -> Self {
#[cfg(target_os = "windows")]
let sep = "\\";
#[cfg(not(target_os = "windows"))]
let sep = "/";
Self {
paths: Vec::new(),
sep: sep.to_string(),
}
.join(path)
}
pub fn join<T: AsRef<str>>(&self, path: T) -> Self {
let mut s = self.clone();
let v = path.as_ref().split(s.sep.as_str());
for ele in v {
if ele == ".." {
s.paths.pop();
} else if ele == "." {
} else if ele == "~" {
} else {
s.paths.push(ele.to_string());
}
}
s
}
pub fn level_count(&self) -> usize {
#[cfg(target_os = "windows")]
let sep = "\\";
#[cfg(not(target_os = "windows"))]
let sep = "/";
self.paths
.iter()
.filter(|f| !f.trim().is_empty() && f.as_str() != sep)
.count()
}
pub fn to_str(&self) -> String {
self.paths.join(&self.sep)
}
pub fn pop(&self) -> Self {
let mut s = self.clone();
s.paths.pop();
s
}
pub fn releative<T: AsRef<str>>(&self, target: T) -> String {
let mut target = Self::system(target);
let mut out = Vec::new();
out.append(&mut vec!["..".to_string(); self.paths.len()]);
out.append(&mut target.paths);
out.join(&self.sep)
}
}
#[cfg(test)]
mod tests {
use super::Path;
#[test]
fn test() {
let mut path = Path::system("/ok");
path = path.join("1");
assert_eq!("/ok/1", path.to_str());
assert_eq!(2, path.level_count());
let mut path = Path::system("/ok");
assert_eq!(1, path.level_count());
path = path.join("../1");
assert_eq!(1, path.level_count());
assert_eq!("/1", path.to_str());
let mut path = Path::system("res");
path = path.join("../1");
assert_eq!("1", path.to_str());
}
#[test]
fn test_releative_path() {
assert_eq!("../../4/5.png", Path::system("1/2").releative("4/5.png"));
assert_eq!("../../4/5.png", Path::system("4/2").releative("4/5.png"));
assert_eq!(
"../../4/5/6.png",
Path::system("4/2").releative("4/5/6.png")
);
assert_eq!("../4/5/6.png", Path::system("2").releative("4/5/6.png"));
}
}