use std::{
error::Error as StdError,
fmt,
path::{Path, PathBuf},
};
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum PathError
{
DirContainsFiles(PathBuf),
DirDoesNotMatchParent(PathBuf),
DoesNotExist(PathBuf),
Empty,
ExistsAlready(PathBuf),
ExtensionNotFound(PathBuf),
FailedToString(PathBuf),
FileNameNotFound(PathBuf),
InvalidExpansion(PathBuf),
IsNotDir(PathBuf),
IsNotExec(PathBuf),
IsNotFile(PathBuf),
IsNotSymlink(PathBuf),
IsNotFileOrSymlinkToFile(PathBuf),
LinkLooping(PathBuf),
MultipleHomeSymbols(PathBuf),
ParentNotFound(PathBuf),
}
impl PathError
{
pub fn dir_contains_files<T: AsRef<Path>>(path: T) -> PathError
{
PathError::DirContainsFiles(path.as_ref().to_path_buf())
}
pub fn dir_does_not_match_parent<T: AsRef<Path>>(path: T) -> PathError
{
PathError::DirDoesNotMatchParent(path.as_ref().to_path_buf())
}
pub fn does_not_exist<T: AsRef<Path>>(path: T) -> PathError
{
PathError::DoesNotExist(path.as_ref().to_path_buf())
}
pub fn exists_already<T: AsRef<Path>>(path: T) -> PathError
{
PathError::ExistsAlready(path.as_ref().to_path_buf())
}
pub fn extension_not_found<T: AsRef<Path>>(path: T) -> PathError
{
PathError::ExtensionNotFound(path.as_ref().to_path_buf())
}
pub fn failed_to_string<T: AsRef<Path>>(path: T) -> PathError
{
PathError::FailedToString(path.as_ref().to_path_buf())
}
pub fn filename_not_found<T: AsRef<Path>>(path: T) -> PathError
{
PathError::FileNameNotFound(path.as_ref().to_path_buf())
}
pub fn is_not_dir<T: AsRef<Path>>(path: T) -> PathError
{
PathError::IsNotDir(path.as_ref().to_path_buf())
}
pub fn is_not_exec<T: AsRef<Path>>(path: T) -> PathError
{
PathError::IsNotExec(path.as_ref().to_path_buf())
}
pub fn is_not_file<T: AsRef<Path>>(path: T) -> PathError
{
PathError::IsNotFile(path.as_ref().to_path_buf())
}
pub fn is_not_symlink<T: AsRef<Path>>(path: T) -> PathError
{
PathError::IsNotSymlink(path.as_ref().to_path_buf())
}
pub fn is_not_file_or_symlink_to_file<T: AsRef<Path>>(path: T) -> PathError
{
PathError::IsNotFileOrSymlinkToFile(path.as_ref().to_path_buf())
}
pub fn invalid_expansion<T: AsRef<Path>>(path: T) -> PathError
{
PathError::InvalidExpansion(path.as_ref().to_path_buf())
}
pub fn link_looping<T: AsRef<Path>>(path: T) -> PathError
{
PathError::LinkLooping(path.as_ref().to_path_buf())
}
pub fn multiple_home_symbols<T: AsRef<Path>>(path: T) -> PathError
{
PathError::MultipleHomeSymbols(path.as_ref().to_path_buf())
}
pub fn parent_not_found<T: AsRef<Path>>(path: T) -> PathError
{
PathError::ParentNotFound(path.as_ref().to_path_buf())
}
}
impl StdError for PathError {}
impl AsRef<dyn StdError> for PathError
{
fn as_ref(&self) -> &(dyn StdError+'static)
{
self
}
}
impl fmt::Display for PathError
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
{
match *self {
PathError::DirContainsFiles(ref path) => {
write!(f, "Target directory contains files: {}", path.display())
},
PathError::DirDoesNotMatchParent(ref path) => {
write!(f, "Target path's directory doesn't match parent: {}", path.display())
},
PathError::DoesNotExist(ref path) => {
write!(f, "Target path does not exist: {}", path.display())
},
PathError::Empty => write!(f, "path empty"),
PathError::ExistsAlready(ref path) => {
write!(f, "Target path exists already: {}", path.display())
},
PathError::ExtensionNotFound(ref path) => {
write!(f, "Target path extension not found: {}", path.display())
},
PathError::FailedToString(ref path) => {
write!(f, "Target path failed to convert to string: {}", path.display())
},
PathError::FileNameNotFound(ref path) => {
write!(f, "Target path filename not found: {}", path.display())
},
PathError::InvalidExpansion(ref path) => {
write!(f, "Target path has an invalid expansion: {}", path.display())
},
PathError::IsNotDir(ref path) => {
write!(f, "Target path is not a directory: {}", path.display())
},
PathError::IsNotExec(ref path) => {
write!(f, "Target path is not an executable: {}", path.display())
},
PathError::IsNotFile(ref path) => {
write!(f, "Target path is not a file: {}", path.display())
},
PathError::IsNotSymlink(ref path) => {
write!(f, "Target path is not a symlink: {}", path.display())
},
PathError::IsNotFileOrSymlinkToFile(ref path) => {
write!(f, "Target path is not a file or a symlink to a file: {}", path.display())
},
PathError::LinkLooping(ref path) => {
write!(f, "Target path causes link looping: {}", path.display())
},
PathError::MultipleHomeSymbols(ref path) => {
write!(f, "Target path has multiple home symbols: {}", path.display())
},
PathError::ParentNotFound(ref path) => {
write!(f, "Target path's parent not found: {}", path.display())
},
}
}
}
#[cfg(test)]
mod tests
{
use std::path::{Path, PathBuf};
use crate::errors::*;
fn path_empty() -> RvResult<PathBuf>
{
Err(PathError::Empty)?
}
fn parent_not_found() -> RvResult<PathBuf>
{
Err(PathError::parent_not_found("foo"))?
}
#[test]
fn test_as_ref()
{
assert_eq!(PathError::Empty.as_ref().downcast_ref::<PathError>(), Some(&PathError::Empty));
}
#[test]
fn test_new_path_empty()
{
assert!(path_empty().is_err());
assert_eq!(path_empty().unwrap_err().downcast_ref::<PathError>(), Some(&PathError::Empty));
}
#[test]
fn test_parent_not_found()
{
assert!(parent_not_found().is_err());
assert_ne!(
parent_not_found().unwrap_err().downcast_ref::<PathError>(),
Some(&PathError::parent_not_found("bar"))
);
assert_eq!(
parent_not_found().unwrap_err().downcast_ref::<PathError>(),
Some(&PathError::parent_not_found("foo"))
);
assert_eq!(
format!("{}", parent_not_found().unwrap_err().downcast_ref::<PathError>().unwrap()),
"Target path's parent not found: foo"
);
}
#[test]
fn test_other_errors()
{
assert_eq!(
PathError::dir_contains_files(Path::new("foo")),
PathError::DirContainsFiles(PathBuf::from("foo"))
);
assert_eq!(
PathError::dir_does_not_match_parent(Path::new("foo")),
PathError::DirDoesNotMatchParent(PathBuf::from("foo"))
);
assert_eq!(
format!("{}", PathError::dir_does_not_match_parent(PathBuf::from("foo"))),
"Target path's directory doesn't match parent: foo"
);
assert_eq!(PathError::does_not_exist(Path::new("foo")), PathError::DoesNotExist(PathBuf::from("foo")));
assert_eq!(
format!("{}", PathError::DoesNotExist(PathBuf::from("foo"))),
"Target path does not exist: foo"
);
assert_eq!(format!("{}", PathError::Empty), "path empty");
assert_eq!(PathError::exists_already(Path::new("foo")), PathError::ExistsAlready(PathBuf::from("foo")));
assert_eq!(
format!("{}", PathError::ExistsAlready(PathBuf::from("foo"))),
"Target path exists already: foo"
);
assert_eq!(
PathError::extension_not_found(Path::new("foo")),
PathError::ExtensionNotFound(PathBuf::from("foo"))
);
assert_eq!(
format!("{}", PathError::ExtensionNotFound(PathBuf::from("foo"))),
"Target path extension not found: foo"
);
assert_eq!(PathError::failed_to_string(Path::new("foo")), PathError::FailedToString(PathBuf::from("foo")));
assert_eq!(
format!("{}", PathError::failed_to_string(PathBuf::from("foo"))),
"Target path failed to convert to string: foo"
);
assert_eq!(
PathError::filename_not_found(Path::new("foo")),
PathError::FileNameNotFound(PathBuf::from("foo"))
);
assert_eq!(
format!("{}", PathError::filename_not_found(PathBuf::from("foo"))),
"Target path filename not found: foo"
);
assert_eq!(
PathError::invalid_expansion(Path::new("foo")),
PathError::InvalidExpansion(PathBuf::from("foo"))
);
assert_eq!(
format!("{}", PathError::invalid_expansion(PathBuf::from("foo"))),
"Target path has an invalid expansion: foo"
);
assert_eq!(PathError::is_not_dir(Path::new("foo")), PathError::IsNotDir(PathBuf::from("foo")));
assert_eq!(
format!("{}", PathError::is_not_dir(PathBuf::from("foo"))),
"Target path is not a directory: foo"
);
assert_eq!(PathError::is_not_exec(Path::new("foo")), PathError::IsNotExec(PathBuf::from("foo")));
assert_eq!(
format!("{}", PathError::is_not_exec(PathBuf::from("foo"))),
"Target path is not an executable: foo"
);
assert_eq!(PathError::is_not_file(Path::new("foo")), PathError::IsNotFile(PathBuf::from("foo")));
assert_eq!(format!("{}", PathError::is_not_file(PathBuf::from("foo"))), "Target path is not a file: foo");
assert_eq!(PathError::is_not_symlink(Path::new("foo")), PathError::IsNotSymlink(PathBuf::from("foo")));
assert_eq!(
format!("{}", PathError::is_not_symlink(PathBuf::from("foo"))),
"Target path is not a symlink: foo"
);
assert_eq!(
PathError::is_not_file_or_symlink_to_file(Path::new("foo")),
PathError::IsNotFileOrSymlinkToFile(PathBuf::from("foo"))
);
assert_eq!(
format!("{}", PathError::is_not_file_or_symlink_to_file(PathBuf::from("foo"))),
"Target path is not a file or a symlink to a file: foo"
);
assert_eq!(PathError::link_looping(Path::new("foo")), PathError::LinkLooping(PathBuf::from("foo")));
assert_eq!(
format!("{}", PathError::link_looping(PathBuf::from("foo"))),
"Target path causes link looping: foo"
);
assert_eq!(
PathError::multiple_home_symbols(Path::new("foo")),
PathError::MultipleHomeSymbols(PathBuf::from("foo"))
);
assert_eq!(
format!("{}", PathError::multiple_home_symbols(PathBuf::from("foo"))),
"Target path has multiple home symbols: foo"
);
}
#[test]
fn test_backtrace()
{
let err = path_empty().unwrap_err();
println!("{:?}", err);
}
}