#[derive(Debug)]
#[non_exhaustive]
pub enum Error<T> {
Io(T),
UnexpectedEof,
WriteZero,
InvalidInput,
NotFound,
AlreadyExists,
DirectoryIsNotEmpty,
CorruptedFileSystem,
NotEnoughSpace,
InvalidFileNameLength,
UnsupportedFileNameCharacter,
}
impl<T: IoError> From<T> for Error<T> {
fn from(error: T) -> Self {
Error::Io(error)
}
}
impl From<Error<std::io::Error>> for std::io::Error {
fn from(error: Error<Self>) -> Self {
match error {
Error::Io(io_error) => io_error,
Error::UnexpectedEof | Error::NotEnoughSpace => {
Self::new(std::io::ErrorKind::UnexpectedEof, error)
}
Error::WriteZero => Self::new(std::io::ErrorKind::WriteZero, error),
Error::InvalidInput
| Error::InvalidFileNameLength
| Error::UnsupportedFileNameCharacter
| Error::DirectoryIsNotEmpty => Self::new(std::io::ErrorKind::InvalidInput, error),
Error::NotFound => Self::new(std::io::ErrorKind::NotFound, error),
Error::AlreadyExists => Self::new(std::io::ErrorKind::AlreadyExists, error),
Error::CorruptedFileSystem => Self::new(std::io::ErrorKind::InvalidData, error),
}
}
}
impl<T: core::fmt::Display> core::fmt::Display for Error<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Error::Io(io_error) => write!(f, "IO error: {}", io_error),
Error::UnexpectedEof => write!(f, "Unexpected end of file"),
Error::NotEnoughSpace => write!(f, "Not enough space"),
Error::WriteZero => write!(f, "Write zero"),
Error::InvalidInput => write!(f, "Invalid input"),
Error::InvalidFileNameLength => write!(f, "Invalid file name length"),
Error::UnsupportedFileNameCharacter => write!(f, "Unsupported file name character"),
Error::DirectoryIsNotEmpty => write!(f, "Directory is not empty"),
Error::NotFound => write!(f, "No such file or directory"),
Error::AlreadyExists => write!(f, "File or directory already exists"),
Error::CorruptedFileSystem => write!(f, "Corrupted file system"),
}
}
}
impl<T: std::error::Error + 'static> std::error::Error for Error<T> {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
if let Error::Io(io_error) = self {
Some(io_error)
} else {
None
}
}
}
pub trait IoError: core::fmt::Debug {
fn is_interrupted(&self) -> bool;
fn new_unexpected_eof_error() -> Self;
fn new_write_zero_error() -> Self;
}
impl<T: core::fmt::Debug + IoError> IoError for Error<T> {
fn is_interrupted(&self) -> bool {
match self {
Error::<T>::Io(io_error) => io_error.is_interrupted(),
_ => false,
}
}
fn new_unexpected_eof_error() -> Self {
Error::<T>::UnexpectedEof
}
fn new_write_zero_error() -> Self {
Error::<T>::WriteZero
}
}
impl IoError for () {
fn is_interrupted(&self) -> bool {
false
}
fn new_unexpected_eof_error() -> Self {
}
fn new_write_zero_error() -> Self {
}
}
impl IoError for std::io::Error {
fn is_interrupted(&self) -> bool {
self.kind() == std::io::ErrorKind::Interrupted
}
fn new_unexpected_eof_error() -> Self {
Self::new(
std::io::ErrorKind::UnexpectedEof,
"failed to fill whole buffer",
)
}
fn new_write_zero_error() -> Self {
Self::new(
std::io::ErrorKind::WriteZero,
"failed to write whole buffer",
)
}
}