use std::{fmt, io};
pub type Result<T> = std::result::Result<T, Error>;
pub type ConvertResult<T, F> = std::result::Result<T, (Error, F)>;
impl<F> From<(Error, F)> for Error {
fn from(value: (Error, F)) -> Error {
value.0
}
}
pub struct Error {
repr: Repr,
op: Operation,
}
enum Repr {
Io(io::Error),
Input(Input),
System(system_error::Error),
}
impl Error {
pub fn io(op: Operation, err: io::Error) -> Self {
Self {
repr: Repr::Io(err),
op,
}
}
pub fn input(op: Operation, input: Input) -> Self {
Self {
repr: Repr::Input(input),
op,
}
}
pub fn system(op: Operation, err: system_error::Error) -> Self {
Self {
repr: Repr::System(err),
op,
}
}
pub fn kernel(op: Operation, code: system_error::KernelCode) -> Self {
Self::system(op, system_error::Error::from_raw_kernel_error(code))
}
pub fn last_os_error(op: Operation) -> Self {
Self::system(op, system_error::Error::last_os_error())
}
pub fn raw_os_error(&self) -> Option<i32> {
match &self.repr {
Repr::Io(err) => err.raw_os_error(),
Repr::Input(_) => None,
Repr::System(err) => err.raw_os_error(),
}
}
pub fn kind(&self) -> io::ErrorKind {
match self.repr {
Repr::Io(ref err) => err.kind(),
Repr::Input(_) => io::ErrorKind::InvalidInput,
Repr::System(ref err) => err.kind(),
}
}
pub fn operation(&self) -> Operation {
self.op
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self.repr {
Repr::Io(ref err) => Some(err),
Repr::Input(_) => None,
Repr::System(_) => None,
}
}
}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Self {
Self {
repr: Repr::Io(err),
op: Operation::None,
}
}
}
impl From<Error> for std::io::Error {
fn from(err: Error) -> Self {
match err.repr {
Repr::Io(io) => io,
Repr::Input(v) => Self::new(io::ErrorKind::InvalidInput, v.as_str()),
Repr::System(sys) => sys.into(),
}
}
}
impl fmt::Debug for Error {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let (field, value) = match self.repr {
Repr::Io(ref err) => ("io", err as &dyn fmt::Debug),
Repr::Input(ref input) => ("input", input as &dyn fmt::Debug),
Repr::System(ref err) => ("system", err as &dyn fmt::Debug),
};
fmt.debug_struct("Error")
.field("op", &self.op)
.field("kind", &self.kind())
.field(field, value)
.finish()
}
}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let value = match self.repr {
Repr::Io(ref err) => err as &dyn fmt::Display,
Repr::Input(ref input) => input as &dyn fmt::Display,
Repr::System(ref err) => err as &dyn fmt::Display,
};
if let Some(op) = self.op.as_str() {
write!(fmt, "failed to {}, {}", op, value)
} else {
value.fmt(fmt)
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[non_exhaustive]
pub enum Operation {
MapFile,
MapFileHandle,
MapFileView,
MapAnonymous,
MapAnonymousHandle,
MapAnonymousView,
Unmap,
Protect,
Advise,
Lock,
Unlock,
Flush,
RingAllocate,
RingDeallocate,
RingEntry,
RingPrimary,
RingSecondary,
MemoryFd,
None,
}
impl Operation {
pub fn as_str(&self) -> Option<&'static str> {
match *self {
Operation::MapFile => Some("map file"),
Operation::MapFileHandle => Some("map file handle"),
Operation::MapFileView => Some("map file view"),
Operation::MapAnonymous => Some("map anonymous"),
Operation::MapAnonymousHandle => Some("map anonymous handle"),
Operation::MapAnonymousView => Some("map anonymous view"),
Operation::Unmap => Some("unmap"),
Operation::Protect => Some("protect mapped memory"),
Operation::Advise => Some("advise mapped memory"),
Operation::Lock => Some("lock mapped memory"),
Operation::Unlock => Some("unlock mapped memory"),
Operation::Flush => Some("flush mapped memory"),
Operation::RingAllocate => Some("allocate full ring"),
Operation::RingDeallocate => Some("deallocate full ring"),
Operation::RingEntry => Some("make ring memory entry"),
Operation::RingPrimary => Some("map ring first half"),
Operation::RingSecondary => Some("map ring second half"),
Operation::MemoryFd => Some("open memory fd"),
Operation::None => None,
}
}
}
impl fmt::Display for Operation {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str(self.as_str().unwrap_or(""))
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[non_exhaustive]
pub enum Input {
InvalidRange,
}
impl Input {
pub fn as_str(&self) -> &'static str {
match *self {
Input::InvalidRange => "invalid range",
}
}
}
impl fmt::Display for Input {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str(self.as_str())
}
}