use std::error;
use std::fmt;
use std::io;
#[cfg(windows)]
extern "C" {
#[link_name = "_errno"]
fn crt_errno() -> *mut libc::c_int;
}
#[derive(Debug)]
pub struct Error {
errno: i32,
source: io::Error,
}
pub type Result<T> = std::result::Result<T, Error>;
impl Error {
pub fn last() -> Self {
#[cfg(windows)]
{
let errno = unsafe {
let ptr = crt_errno();
if ptr.is_null() {
0
} else {
*ptr
}
};
if errno > 0 {
return Self::from_errno(errno);
}
}
let source = io::Error::last_os_error();
let errno = source.raw_os_error().unwrap_or(libc::EIO);
Self { errno, source }
}
pub fn from_errno(errno: i32) -> Self {
Self {
errno,
source: io::Error::from_raw_os_error(errno),
}
}
pub fn errno(&self) -> i32 {
self.errno
}
pub fn is_timed_out(&self) -> bool {
self.errno == libc::ETIMEDOUT
}
pub fn is_closed(&self) -> bool {
self.errno == libc::EPIPE
}
pub fn into_io_error(self) -> io::Error {
self.source
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} (errno={})", self.source, self.errno)
}
}
impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
Some(&self.source)
}
}
impl From<Error> for io::Error {
fn from(value: Error) -> Self {
value.into_io_error()
}
}
impl From<io::Error> for Error {
fn from(source: io::Error) -> Self {
let errno = source.raw_os_error().unwrap_or(libc::EIO);
Self { errno, source }
}
}