#[macro_use]
extern crate failure;
use std::path::{Path, PathBuf};
use failure::Error;
pub mod error;
#[derive(Debug)]
pub struct CdManager<'a> {
path: &'a mut PathBuf,
added_depth: usize,
}
impl<'a> CdManager<'a> {
pub fn new(path: &'a mut PathBuf) -> Self {
CdManager {
path,
added_depth: 0,
}
}
pub fn push<P: AsRef<Path>>(&mut self, path: P) {
self.added_depth += path.as_ref().components().count();
self.path.push(path);
}
pub fn pop(&mut self) -> Result<(), Error> {
ensure!(self.added_depth > 0, error::TooManyPopError);
self.added_depth -= 1;
self.path.pop();
Ok(())
}
pub fn layer(&mut self) -> CdManager {
CdManager::new(&mut self.path)
}
pub fn clone_inner(&self) -> PathBuf {
self.path.clone()
}
}
impl<'a, P: AsRef<Path>> PartialEq<P> for CdManager<'a> {
fn eq(&self, other: &P) -> bool {
self.path.as_path() == other.as_ref()
}
}
impl<'a> Eq for CdManager<'a> {}
impl<'a> PartialEq<CdManager<'a>> for PathBuf {
fn eq(&self, other: &CdManager) -> bool {
self == other.path
}
}
impl<'a> Drop for CdManager<'a> {
fn drop(&mut self) {
for _ in 0..self.added_depth {
self.path.pop();
}
}
}
impl<'a> AsRef<Path> for CdManager<'a> {
fn as_ref(&self) -> &Path {
self.path
}
}
#[cfg(test)]
mod test {
use super::CdManager;
use std::path::PathBuf;
#[test]
fn cd_manager_push() {
let mut path = PathBuf::from("a/path/to/something".to_string());
let mut p2 = path.clone();
{
let mut cd_manager = CdManager::new(&mut p2);
cd_manager.push("abc/def");
path.push("abc/def");
assert_eq!(cd_manager.added_depth, 2);
assert_eq!(path, cd_manager);
path.pop();
path.pop();
}
assert_eq!(p2, path);
}
#[test]
fn cd_manager_pop() {
let mut path = PathBuf::from("a/path/to/something".to_string());
let mut p2 = path.clone();
{
let mut cd_manager = CdManager::new(&mut p2);
cd_manager.push("abc/def");
path.push("abc/def");
cd_manager.pop().unwrap();
path.pop();
assert_eq!(path, cd_manager);
assert_eq!(cd_manager.added_depth, 1);
path.pop();
}
assert_eq!(p2, path);
}
#[test]
fn cd_manager_error() {
let mut path = PathBuf::from("a/path/to/something".to_string());
let mut cd_manager = CdManager::new(&mut path);
assert!(cd_manager.pop().is_err());
}
}