use std::convert::{From, Infallible};
use std::ffi::{OsStr, OsString};
use std::fmt::Display;
use std::io::Error as IoError;
#[allow(unused_imports)] use std::io::ErrorKind;
use tempfile::PersistError;
#[derive(Debug)]
pub enum Error {
Io(IoError),
#[cfg(feature = "http")]
Http {
code: u16,
message: String,
},
}
pub type Result<T> = std::result::Result<T, Error>;
impl Error {
pub(crate) fn to_os_string(&self, path: &OsStr) -> OsString {
let mut str = OsString::new();
str.push("Error opening ");
str.push(path);
str.push(": ");
str.push(self.to_string());
str
}
pub fn kind(&self) -> ErrorKind {
match self {
Error::Io(err) => err.kind(),
#[cfg(feature = "http")]
Error::Http { code, message: _ } => match code {
404 | 410 => ErrorKind::NotFound,
401 | 403 => ErrorKind::PermissionDenied,
_ => ErrorKind::Other,
},
}
}
}
impl From<Infallible> for Error {
fn from(_err: Infallible) -> Self {
unreachable!("Infallible should not exist")
}
}
impl From<PersistError> for Error {
fn from(err: PersistError) -> Self {
Error::Io(err.error)
}
}
impl From<IoError> for Error {
fn from(err: IoError) -> Self {
Error::Io(err)
}
}
impl From<walkdir::Error> for Error {
fn from(err: walkdir::Error) -> Self {
Error::Io(err.into())
}
}
impl From<Error> for IoError {
fn from(err: Error) -> Self {
match err {
Error::Io(err) => err,
#[cfg(feature = "http")]
Error::Http { .. } => IoError::new(err.kind(), err.to_string()),
}
}
}
#[cfg(feature = "http")]
impl From<url::ParseError> for Error {
fn from(err: url::ParseError) -> Self {
Error::Http {
code: 400,
message: err.to_string(),
}
}
}
impl std::error::Error for Error {}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
match self {
Error::Io(err) => err.fmt(f),
#[cfg(feature = "http")]
Error::Http { code, message } => write!(f, "{}: {}", code, message),
}
}
}
macro_rules! io_error {
($func_name:ident, $unix:ident, $win:ident => ($kind:ident, $des:literal)) => {
#[cfg(unix)]
pub(crate) fn $func_name() -> IoError {
IoError::from_raw_os_error(libc::$unix)
}
#[cfg(windows)]
pub(crate) fn $func_name() -> IoError {
IoError::from_raw_os_error(windows_sys::Win32::Foundation::$win as i32)
}
#[cfg(not(any(unix, windows)))]
pub(crate) fn $func_name() -> IoError {
IoError::new(ErrorKind::$kind, $des)
}
};
}
io_error!(seek_error, ESPIPE, ERROR_BROKEN_PIPE => (Other, "Cannot seek on stream"));
io_error!(dir_error, EISDIR, ERROR_INVALID_NAME => (PermissionDenied, "Is a directory"));
io_error!(not_dir_error, ENOTDIR, ERROR_ACCESS_DENIED => (PermissionDenied, "Is not a Directory"));
io_error!(permission_error, EACCES, ERROR_ACCESS_DENIED => (PermissionDenied, "Permission denied"));
io_error!(not_found_error, ENOENT, ERROR_FILE_NOT_FOUND => (NotFound, "The system cannot find the path specified."));