#![no_std]
#![warn(missing_docs)]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::style))]
#[cfg(feature = "std")]
extern crate std;
use core::{ffi, mem, hash, fmt};
pub const UNKNOWN_ERROR: &str = "Unknown error";
pub const FAIL_ERROR_FORMAT: &str = "Failed to format error into utf-8";
const MESSAGE_BUF_SIZE: usize = 256;
pub type MessageBuf = [mem::MaybeUninit<u8>; MESSAGE_BUF_SIZE];
mod posix;
pub use posix::POSIX_CATEGORY;
mod system;
pub use system::SYSTEM_CATEGORY;
pub struct Category {
pub name: &'static str,
pub message: fn(ffi::c_int, &mut MessageBuf) -> &str,
pub equivalent: fn(ffi::c_int, &ErrorCode) -> bool,
}
#[derive(Copy, Clone)]
pub struct ErrorCode {
code: ffi::c_int,
category: &'static Category
}
impl ErrorCode {
#[inline]
pub const fn new(code: ffi::c_int, category: &'static Category) -> Self {
Self {
code,
category,
}
}
#[inline(always)]
pub fn new_posix(code: ffi::c_int) -> Self {
Self::new(code, &POSIX_CATEGORY)
}
#[inline(always)]
pub fn new_system(code: ffi::c_int) -> Self {
Self::new(code, &SYSTEM_CATEGORY)
}
#[inline]
pub fn last_posix() -> Self {
Self::new_posix(posix::get_last_error())
}
#[inline]
pub fn last_system() -> Self {
Self::new_system(system::get_last_error())
}
#[inline(always)]
pub const fn raw_code(&self) -> ffi::c_int {
self.code
}
#[inline(always)]
pub const fn category(&self) -> &'static Category {
self.category
}
}
impl PartialEq for ErrorCode {
#[inline]
fn eq(&self, other: &Self) -> bool {
(self.category.equivalent)(self.code, other)
}
}
impl Eq for ErrorCode {}
impl hash::Hash for ErrorCode {
#[inline]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.code.hash(state);
}
}
impl fmt::Debug for ErrorCode {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_fmt(format_args!("{}({})", self.category.name, self.code))
}
}
impl fmt::Display for ErrorCode {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut out = [mem::MaybeUninit::uninit(); MESSAGE_BUF_SIZE];
let message = (self.category.message)(self.code, &mut out);
fmt.write_fmt(format_args!("{}({}) {}", self.category.name, self.code, message))
}
}
#[cfg(feature = "std")]
impl std::error::Error for ErrorCode {}
#[cfg(feature = "std")]
impl From<std::io::Error> for ErrorCode {
#[inline]
fn from(err: std::io::Error) -> Self {
match err.raw_os_error() {
Some(err) => Self::new_posix(err),
None => Self::new_posix(-1),
}
}
}