From 8795f0a1a2cdf6296a1b853019fce0a789d70fc1 Mon Sep 17 00:00:00 2001 From: Avril Date: Sat, 3 Sep 2022 14:22:32 +0100 Subject: [PATCH] Added `err` module: Wrapped OS errors; Ad-hoc inline definitions, and named definitions with pre-defined messages. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fortune for mapped-file's current commit: Future small blessing − 末小吉 --- Cargo.toml | 3 +- src/err.rs | 170 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/ffi.rs | 2 +- src/lib.rs | 8 ++- 4 files changed, 179 insertions(+), 4 deletions(-) create mode 100644 src/err.rs diff --git a/Cargo.toml b/Cargo.toml index 875e0f0..711eca4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "mapped-file" -description = "construct a memory mapping over any file object" +description = "Construct a memory mapping over any file object" +keywords = ["unix", "mmap", "generic", "file", "fd"] version = "0.1.0" edition = "2021" diff --git a/src/err.rs b/src/err.rs new file mode 100644 index 0000000..62c5233 --- /dev/null +++ b/src/err.rs @@ -0,0 +1,170 @@ +//! Wrapping `errno` error types +use super::*; +use std::ffi::c_int; +use std::{ + fmt, error +}; + +/// Construct an ad-hoc error wrapping the last OS error. +macro_rules! os_error { + ($fmt:literal $(, $args:expr)*) => { + { + #[derive(Debug)] + struct AdHoc<'a>(::std::fmt::Arguments<'a>); + impl<'a> ::std::fmt::Display for AdHoc<'a> + { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + write!(f, "{}", self.0) + } + } + $crate::err::WrappedOSError::last_os_error(AdHoc(::std::format_args!($fmt $(, $args)*))) + } + }; + ($(#[$outer:meta])* $vis:vis struct $name:ident => $fmt:literal $(; $($rest:tt)*)?) => { + + $(#[$outer])* + #[derive(Debug)] + #[repr(transparent)] + $vis struct $name($crate::err::WrappedOSError<&'static str>); + + impl ::std::fmt::Display for $name + { + #[inline] + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> fmt::Result + { + f.write_str($fmt) + } + } + impl ::std::error::Error for $name { + #[inline] + fn source(&self) -> Option<&(dyn ::std::error::Error + 'static)> + { + self.0.source() + } + } + + #[allow(unused)] + impl $name { + #[inline(always)] + fn new() -> Self + { + Self($crate::err::WrappedOSError::last_os_error($fmt)) + } + #[inline(always)] + fn into_inner(self) -> $crate::err::WrappedOSError<&'static str> + { + self.0 + } + } + impl ::std::ops::Deref for $name { + type Target = $crate::err::WrappedOSError<&'static str>; + #[inline] + fn deref(&self) -> &Self::Target + { + &self.0 + } + } + impl ::std::ops::DerefMut for $name { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target + { + &mut self.0 + } + } + + $( + $crate::os_error! { + $($rest)* + } + )? + }; + () => {}; +} +pub(crate) use os_error; + +const _: () = { + os_error!(struct Test => "Test error"); + const fn t() {} + fn r(_: &E) {} + fn test() { + r(&os_error!("Some error message")); + } + t::() +}; + +/// Wraps a piece of context over an OS error +pub struct WrappedOSError(io::Error, E); + +impl WrappedOSError +{ + pub(crate) fn last_os_error(ctx: E) -> Self + { + Self(io::Error::last_os_error(), ctx) + } + + pub(crate) fn from_os_error(raw: c_int, ctx: E) -> Self + { + Self(io::Error::from_raw_os_error(raw), ctx) + } +} + +impl WrappedOSError +{ + #[inline] + pub fn error(&self) -> &io::Error + { + &self.0 + } + #[inline] + pub fn raw_error(&self) -> c_int + { + self.0.raw_os_error().unwrap() + } + #[inline] + pub fn context(&self) -> &E + { + &self.1 + } +} + +impl From> for io::Error +{ + #[inline] + fn from(from: WrappedOSError) -> Self + { + from.0 + } +} + + +impl error::Error for WrappedOSError +where WrappedOSError: fmt::Display + fmt::Debug +{ + #[inline] + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + Some(&self.0) + } +} + +impl fmt::Display for WrappedOSError +where E: fmt::Debug +{ + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + write!(f, "{:?}", &self.1) + } +} +impl fmt::Debug for WrappedOSError +where E: fmt::Display +{ + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + write!(f, "{}", &self.1) + } +} + + diff --git a/src/ffi.rs b/src/ffi.rs index 5d09048..071aad3 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -75,7 +75,7 @@ pub(crate) use c_try; /// Error context for a failed C call. /// Returns the invalid return value, the `errno` error, and a message. #[derive(Debug)] -pub(crate) struct FFIError<'a, T>(T, io::Error, fmt::Arguments<'a>); +pub struct FFIError<'a, T>(T, io::Error, fmt::Arguments<'a>); impl<'a, T> FFIError<'a, T> where FFIError<'a, T>: error::Error diff --git a/src/lib.rs b/src/lib.rs index ff21069..13ba068 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,7 @@ use std::{ }, io, fmt, error, - + borrow::{ Borrow, BorrowMut, } @@ -31,6 +31,10 @@ use uniq::UniqueSlice; mod flags; pub use flags::*; +pub mod err; +use err::os_error; + + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] struct MappedSlice(UniqueSlice); @@ -283,7 +287,7 @@ impl MappedFile { } } -/// Contains an OS error and a value. +/// Error returned when mapping operation fails pub struct TryNewError { error: Box,