use std::fmt::{Display, Formatter};
use std::io;
use std::result;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Error(i32);
pub type Result<T> = result::Result<T, Error>;
impl Error {
pub fn new(errno: i32) -> Error {
Error(errno)
}
pub fn last() -> Error {
Error(io::Error::last_os_error().raw_os_error().unwrap())
}
pub fn errno(self) -> i32 {
self.0
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
io::Error::from_raw_os_error(self.0).fmt(f)
}
}
impl std::error::Error for Error {}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
Error::new(e.raw_os_error().unwrap_or_default())
}
}
impl From<Error> for io::Error {
fn from(err: Error) -> io::Error {
io::Error::from_raw_os_error(err.0)
}
}
pub fn errno_result<T>() -> Result<T> {
Err(Error::last())
}
#[cfg(test)]
mod tests {
use super::*;
use std::env::temp_dir;
use std::error::Error as _;
use std::fs::OpenOptions;
use std::io::{self, Read};
#[test]
pub fn test_errno() {
#[cfg(unix)]
let expected_errno = libc::EBADF;
#[cfg(not(unix))]
let expected_errno = libc::EIO;
let mut path = temp_dir();
path.push("test");
let mut file = OpenOptions::new()
.read(false)
.write(true)
.create(true)
.truncate(true)
.open(path)
.unwrap();
let mut buf: Vec<u8> = Vec::new();
assert!(file.read_to_end(&mut buf).is_err());
let last_err = errno_result::<i32>().unwrap_err();
assert_eq!(last_err, Error::new(expected_errno));
assert_eq!(last_err.errno(), expected_errno);
assert!(last_err.source().is_none());
assert_eq!(last_err, Error::from(io::Error::last_os_error()));
assert_eq!(last_err, Error::last());
let last_err: io::Error = last_err.into();
assert_eq!(io::Error::last_os_error().kind(), last_err.kind());
}
#[test]
pub fn test_display() {
#[cfg(target_os = "linux")]
assert_eq!(
format!("{}", Error::new(libc::EBADF)),
"Bad file descriptor (os error 9)"
);
#[cfg(not(unix))]
assert_eq!(
format!("{}", Error::new(libc::EIO)),
"Access is denied. (os error 5)"
);
}
}