use crate::{
Display, Error, FmtResult, Formatter, IoError, IoErrorKind, LINUX_ERRNO as ERRNO,
LINUX_EXIT as EXIT, Overflow, is,
};
#[doc = crate::_tags!(linux result)]
#[doc = crate::_doc_location!("sys/os/linux")]
pub type LinuxResult<T> = crate::Result<T, LinuxError>;
#[doc = crate::_tags!(linux error_composite)]
#[doc = crate::_doc_location!("sys/os/linux")]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LinuxError {
Sys(isize),
NoInput,
InvalidUtf8,
Other(&'static str),
}
impl Error for LinuxError {}
impl Display for LinuxError {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult<()> {
match self {
LinuxError::Sys(errno) => write!(f, "System error ERRNO:{errno}."),
LinuxError::NoInput => f.write_str("No input available"),
LinuxError::InvalidUtf8 => f.write_str("Invalid UTF-8 data"),
LinuxError::Other(s) => f.write_str(s),
}
}
}
macro_rules! match_linux_to_io {
($self:ident) => {
match $self {
LinuxError::Sys(errno) => {
let kind = match errno {
ERRNO::EPERM => IoErrorKind::PermissionDenied,
ERRNO::ENOENT => IoErrorKind::NotFound,
ERRNO::EINTR => IoErrorKind::Interrupted,
ERRNO::EIO => IoErrorKind::Other,
ERRNO::ENXIO => IoErrorKind::NotFound,
ERRNO::EAGAIN => IoErrorKind::WouldBlock,
ERRNO::ENOMEM => IoErrorKind::OutOfMemory,
ERRNO::EACCES => IoErrorKind::PermissionDenied,
ERRNO::EFAULT => IoErrorKind::InvalidInput,
ERRNO::EBUSY => IoErrorKind::ResourceBusy,
ERRNO::EEXIST => IoErrorKind::AlreadyExists,
ERRNO::ENOTDIR => IoErrorKind::NotADirectory,
ERRNO::EISDIR => IoErrorKind::IsADirectory,
ERRNO::EINVAL => IoErrorKind::InvalidInput,
ERRNO::ENOSPC => IoErrorKind::StorageFull,
ERRNO::EROFS => IoErrorKind::ReadOnlyFilesystem,
ERRNO::EMLINK => IoErrorKind::TooManyLinks,
ERRNO::EPIPE => IoErrorKind::BrokenPipe,
ERRNO::EDOM => IoErrorKind::InvalidInput,
ERRNO::ERANGE => IoErrorKind::InvalidInput,
ERRNO::EDEADLK => IoErrorKind::Deadlock,
ERRNO::ENOLCK => IoErrorKind::ResourceBusy,
ERRNO::ENOSYS => IoErrorKind::Unsupported,
ERRNO::ENOTEMPTY => IoErrorKind::DirectoryNotEmpty,
ERRNO::ENODEV => IoErrorKind::NotFound,
ERRNO::ETIMEDOUT => IoErrorKind::TimedOut,
ERRNO::EXDEV => IoErrorKind::CrossesDevices,
ERRNO::ETXTBSY => IoErrorKind::ExecutableFileBusy,
_ => IoErrorKind::Other,
};
IoError::new(kind, "system call failed")
}
LinuxError::NoInput => IoError::new(IoErrorKind::UnexpectedEof, "no input available"),
LinuxError::InvalidUtf8 => IoError::new(IoErrorKind::InvalidData, "invalid UTF-8 data"),
LinuxError::Other(s) => IoError::new(IoErrorKind::Other, s),
}
};
}
macro_rules! match_io_to_linux {
($err:ident) => {
match $err.kind() {
IoErrorKind::PermissionDenied => LinuxError::Sys(ERRNO::EACCES),
IoErrorKind::NotFound => LinuxError::Sys(ERRNO::ENOENT),
IoErrorKind::Interrupted => LinuxError::Sys(ERRNO::EINTR),
IoErrorKind::WouldBlock => LinuxError::Sys(ERRNO::EAGAIN),
IoErrorKind::OutOfMemory => LinuxError::Sys(ERRNO::ENOMEM),
IoErrorKind::InvalidInput => LinuxError::Sys(ERRNO::EINVAL),
IoErrorKind::StorageFull => LinuxError::Sys(ERRNO::ENOSPC),
IoErrorKind::BrokenPipe => LinuxError::Sys(ERRNO::EPIPE),
IoErrorKind::UnexpectedEof => LinuxError::NoInput,
IoErrorKind::InvalidData => LinuxError::InvalidUtf8,
_ => LinuxError::Sys(ERRNO::EIO), }
};
}
#[rustfmt::skip]
impl LinuxError {
#[cfg(feature = "std")]
pub fn to_io(self) -> IoError { match_linux_to_io!(self) }
#[cfg(not(feature = "std"))]
pub const fn to_io(self) -> IoError { match_linux_to_io!(self) }
#[cfg(feature = "std")]
pub fn from_io(err: IoError) -> LinuxError { match_io_to_linux!(err) }
#[cfg(not(feature = "std"))]
pub const fn from_io(err: IoError) -> LinuxError { match_io_to_linux!(err) }
}
impl From<LinuxError> for IoError {
fn from(err: LinuxError) -> Self {
err.to_io()
}
}
impl From<IoError> for LinuxError {
fn from(err: IoError) -> Self {
LinuxError::from_io(err)
}
}
impl From<Overflow> for LinuxError {
fn from(_err: Overflow) -> Self {
LinuxError::Other("Overflow.")
}
}
impl LinuxError {
pub const fn to_exit_code(self) -> i32 {
let code = self.to_raw_exit_code();
is![code >= EXIT::SUCCESS && code <= EXIT::MAX, code, EXIT::INTERNAL_ERROR]
}
pub const fn to_raw_exit_code(self) -> i32 {
match self {
LinuxError::Sys(errno) => {
match errno {
ERRNO::EPERM => EXIT::NOPERM,
ERRNO::ENOENT => EXIT::NOINPUT,
ERRNO::EACCES => EXIT::NOPERM,
ERRNO::EINVAL => EXIT::USAGE,
ERRNO::ENOSYS => EXIT::SOFTWARE,
ERRNO::ENOMEM => EXIT::OSERR,
ERRNO::EIO => EXIT::IOERR,
ERRNO::ENFILE | ERRNO::EMFILE => EXIT::OSFILE,
ERRNO::EEXIST => EXIT::CANTCREAT,
ERRNO::ENOTDIR => EXIT::DATAERR,
ERRNO::EISDIR => EXIT::DATAERR,
ERRNO::ETIMEDOUT => EXIT::TEMPFAIL,
_ => EXIT::OSERR,
}
}
LinuxError::NoInput => EXIT::NOINPUT,
LinuxError::InvalidUtf8 => EXIT::DATAERR,
LinuxError::Other(_s) => EXIT::FAILURE,
}
}
}