use std::error;
use std::fmt;
use std::io;
use std::path::Path;
use std::path::PathBuf;
#[cfg(feature = "unstable")]
type RawOsError = io::RawOsError;
#[cfg(not(feature = "unstable"))]
type RawOsError = i32;
#[derive(Debug)]
pub struct Error {
path: PathBuf,
operation: ErrorOperation,
source: io::Error,
}
#[derive(Copy, Clone, Debug)]
pub enum ErrorOperation {
OpenFile,
OpenDirectory,
ReadDirectory,
ReadMetadata,
GenerateData,
}
impl Error {
#[inline]
pub fn from_io_error(path: PathBuf, operation: ErrorOperation, source: io::Error) -> Self {
Self {
path,
operation,
source,
}
}
#[inline]
pub fn from_raw_os_error(path: PathBuf, operation: ErrorOperation, code: RawOsError) -> Self {
Self::from_io_error(path, operation, io::Error::from_raw_os_error(code))
}
#[inline]
pub fn last_os_error(path: PathBuf, operation: ErrorOperation) -> Self {
Self::from_io_error(path, operation, io::Error::last_os_error())
}
#[inline]
pub fn path(&self) -> &Path {
&self.path
}
#[inline]
pub fn operation(&self) -> ErrorOperation {
self.operation
}
#[inline]
pub fn source(&self) -> &io::Error {
&self.source
}
#[inline]
pub fn into_source(self) -> io::Error {
self.source
}
#[inline]
pub fn into_path_source(self) -> (PathBuf, io::Error) {
(self.path, self.source)
}
#[inline]
pub fn raw_os_error(&self) -> Option<RawOsError> {
self.source.raw_os_error()
}
#[inline]
pub fn kind(&self) -> io::ErrorKind {
self.source.kind()
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let op = match self.operation {
ErrorOperation::OpenFile => "opening file",
ErrorOperation::OpenDirectory => "opening directory",
ErrorOperation::ReadDirectory => "reading directory",
ErrorOperation::ReadMetadata => "reading metadata",
ErrorOperation::GenerateData => "generating associated data",
};
write!(
f,
"{}: error while {}: {}",
self.path.display(),
op,
self.source
)
}
}
impl error::Error for Error {
#[inline]
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
Some(&self.source)
}
}
impl From<Error> for io::Error {
#[inline]
fn from(err: Error) -> io::Error {
err.source
}
}
pub(super) trait IntoScanError {
fn into_scan_error(self, path: PathBuf, operation: ErrorOperation) -> Error;
}
impl<T> IntoScanError for T
where
T: Into<io::Error>,
{
#[inline]
fn into_scan_error(self, path: PathBuf, operation: ErrorOperation) -> Error {
Error::from_io_error(path, operation, self.into())
}
}
#[derive(Debug)]
pub struct FilesystemLoopError {
start_path: PathBuf,
}
impl FilesystemLoopError {
pub fn new(start_path: PathBuf) -> Self {
Self { start_path }
}
pub fn start_path(&self) -> &Path {
&self.start_path
}
pub fn into_start_path(self) -> PathBuf {
self.start_path
}
}
impl fmt::Display for FilesystemLoopError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"File system loop detected: this is the same file system as {}",
self.start_path.display()
)
}
}
impl error::Error for FilesystemLoopError {}