use std::io::{self, ErrorKind};
use std::env;
use std::borrow::Cow;
use std::path::{Component, Path, PathBuf};
use path_absolutize::*;
pub trait Calculate {
fn home_dir(&self) -> io::Result<Cow<Path>>;
fn as_absolute_path(&self) -> io::Result<Cow<Path>>;
fn relative_root_with(&self, path_b: &Path) -> io::Result<Cow<Path>>;
fn related_to(&self, src_path: &Path) -> io::Result<Cow<Path>>;
}
impl Calculate for Path {
fn home_dir(&self) -> io::Result<Cow<Path>> {
#[allow(deprecated)]
let home_dir = env::home_dir().unwrap();
if home_dir.to_str().unwrap() == "" {
return Err(io::Error::from(ErrorKind::InvalidInput))
}
Ok(Cow::from(home_dir))
}
fn as_absolute_path(&self) -> io::Result<Cow<Path>> {
let mut iters = self.components();
let first_component = iters.next();
match first_component {
Some(Component::RootDir) => {
return self.absolutize()
},
Some(Component::Normal(dir)) => {
if dir.to_str().unwrap() == "~" {} else {return self.absolutize()}
},
None => {
return self.absolutize()
}
_ => {},
}
let mut path_buf = PathBuf::new();
let home_dir = self.home_dir()?;
let home_iters = home_dir.components();
for iter in home_iters {
path_buf.push(iter)
}
for iter in iters {
path_buf.push(iter)
}
Ok(Cow::from(path_buf))
}
fn relative_root_with(&self, path_b: &Path) -> io::Result<Cow<Path>> {
let pa = self.as_absolute_path()?;
let pb = path_b.as_absolute_path()?;
let mut path_buf = PathBuf::new();
let mut itera = pa.components();
let mut iterb = pb.components();
let first_componenta = itera.next().unwrap();
let first_componentb = iterb.next().unwrap();
if first_componenta == first_componentb {
path_buf.push(first_componenta);
} else {
return Err(io::Error::from(ErrorKind::InvalidInput))
}
for componenta in itera {
if let Some(componentb) = iterb.next() {
if componenta == componentb {
path_buf.push(componenta);
} else {
break;
}
}
}
Ok(Cow::from(path_buf))
}
fn related_to(&self, src_path: &Path) -> io::Result<Cow<Path>> {
let pa = self.as_absolute_path().unwrap();
let pb = src_path.as_absolute_path().unwrap();
let relative_root = self.relative_root_with(src_path).unwrap();
let mut path_buf = PathBuf::new();
let mut itera = pa.components();
let mut iterb = pb.components();
let iterr = relative_root.components();
for _item in iterr {
itera.next();
iterb.next();
}
for _item in iterb {
path_buf.push(Component::ParentDir);
}
for item in itera {
path_buf.push(item)
}
Ok(Cow::from(path_buf))
}
}
impl Calculate for PathBuf {
fn home_dir(&self) -> io::Result<Cow<Path>> {
self.as_path().home_dir()
}
fn as_absolute_path(&self) -> io::Result<Cow<Path>> {
self.as_path().as_absolute_path()
}
fn relative_root_with(&self, path_b: &Path) -> io::Result<Cow<Path>> {
self.as_path().relative_root_with(path_b)
}
fn related_to(&self, src_path: &Path) -> io::Result<Cow<Path>> {
self.as_path().related_to(src_path)
}
}