#[macro_use]
mod macros;
mod generated;
#[cfg(feature = "std")]
mod last;
use core::fmt;
pub use self::generated::Errno;
impl Errno {
pub const EWOULDBLOCK: Self = Self::EAGAIN;
pub const EDEADLOCK: Self = Self::EDEADLK;
pub fn new(num: i32) -> Self {
Self(num)
}
pub fn into_raw(self) -> i32 {
self.0
}
pub fn is_valid(&self) -> bool {
self.0 < 4096
}
#[inline(always)]
pub fn from_ret(value: usize) -> Result<usize, Errno> {
if value > -4096isize as usize {
Err(Self(-(value as i32)))
} else {
Ok(value)
}
}
#[cfg(feature = "std")]
pub fn last() -> Self {
Self(unsafe { *last::errno() })
}
#[cfg(feature = "std")]
pub fn result<T>(value: T) -> Result<T, Errno>
where
T: ErrnoSentinel + PartialEq<T>,
{
if value == T::sentinel() {
Err(Self::last())
} else {
Ok(value)
}
}
pub fn name(&self) -> Option<&'static str> {
self.name_and_description().map(|x| x.0)
}
pub fn description(&self) -> Option<&'static str> {
self.name_and_description().map(|x| x.1)
}
#[cfg(feature = "std")]
pub fn from_io_error(err: std::io::Error) -> Option<Self> {
err.raw_os_error().map(Self::new)
}
}
impl fmt::Display for Errno {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.name_and_description() {
Some((name, description)) => {
write!(f, "{} {name} ({description})", -self.0)
}
None => {
if self.is_valid() {
write!(f, "{}", -self.0)
} else {
write!(f, "Invalid errno {:#x}", self.0)
}
}
}
}
}
impl fmt::Debug for Errno {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.name() {
Some(name) => f.write_str(name),
None => write!(f, "Errno({})", self.0),
}
}
}
#[cfg(feature = "std")]
impl From<Errno> for std::io::Error {
fn from(err: Errno) -> Self {
std::io::Error::from_raw_os_error(err.into_raw())
}
}
#[cfg(feature = "std")]
impl std::error::Error for Errno {}
pub trait ErrnoSentinel: Sized {
fn sentinel() -> Self;
}
impl ErrnoSentinel for isize {
fn sentinel() -> Self {
-1
}
}
impl ErrnoSentinel for i32 {
fn sentinel() -> Self {
-1
}
}
impl ErrnoSentinel for i64 {
fn sentinel() -> Self {
-1
}
}
impl ErrnoSentinel for *mut core::ffi::c_void {
fn sentinel() -> Self {
-1isize as *mut core::ffi::c_void
}
}
impl ErrnoSentinel for usize {
fn sentinel() -> Self {
usize::MAX
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn basic() {
assert_eq!(Errno::ENOENT.name(), Some("ENOENT"));
assert_eq!(
Errno::ENOENT.description(),
Some("No such file or directory")
);
#[cfg(feature = "std")]
{
assert_eq!(
format!("{}", Errno::ENOENT),
"-2 ENOENT (No such file or directory)"
);
assert_eq!(format!("{:?}", Errno::ENOENT), "ENOENT");
}
}
#[test]
fn from_ret() {
assert_eq!(Errno::from_ret(-2isize as usize), Err(Errno::ENOENT));
assert_eq!(Errno::from_ret(2), Ok(2));
}
#[cfg(feature = "std")]
#[test]
fn io_error() {
use std::io;
assert_eq!(
io::Error::from(Errno::ENOENT).kind(),
io::ErrorKind::NotFound
);
assert_eq!(
Errno::from_io_error(io::Error::from_raw_os_error(2)),
Some(Errno::ENOENT)
);
assert_eq!(
Errno::from_io_error(io::Error::new(io::ErrorKind::Other, "")),
None
);
}
#[cfg(feature = "std")]
#[test]
fn last_errno() {
assert_eq!(
Errno::result(unsafe {
libc::open(
b"this_should_not_exist\0".as_ptr() as *const _,
libc::O_RDONLY,
)
}),
Err(Errno::ENOENT)
);
}
}