forked from Proxmox/proxmox
sys: add a bunch of error helpers
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
568ce10624
commit
b659584f23
@ -11,6 +11,7 @@ authors = [
|
||||
failure = "0.1"
|
||||
lazy_static = "1.4"
|
||||
libc = "0.2"
|
||||
nix = "0.16"
|
||||
proxmox-tools = { version = "0.1.1-dev.1", path = "../proxmox-tools" }
|
||||
|
||||
# Docs should be able to reference the proxmox crate.
|
||||
|
165
proxmox-sys/src/error.rs
Normal file
165
proxmox-sys/src/error.rs
Normal file
@ -0,0 +1,165 @@
|
||||
//! Helpers for `io::Error` and `nix::Error`.
|
||||
//!
|
||||
//! When dealing with low level functionality, the `nix` crate contains a lot of helpful
|
||||
//! functionality. Unfortunately it also contains its own error type which doesn't mix all too well
|
||||
//! with `std::io::Error`. Some of the common cases we want to deal with is checking for `EAGAIN`,
|
||||
//! `EWOULDBLOCK` or `ENOENT` specifically. To do this easily, we add the `SysError` trait (rather
|
||||
//! than a type), which is implemented for both these errors and allows checking for the most
|
||||
//! common errors in a unified way.
|
||||
//!
|
||||
//! Another problem with the `nix` error type is that it has no equivalent to `ErrorKind::Other`.
|
||||
//! Unfortunately this is more difficult to deal with, so for now, we consider `io::Error` to be
|
||||
//! the more general error (and require an `into_io_error` implementation in `SysError`).
|
||||
//!
|
||||
//! See the `SysError` and `SysResult` traits for examples.
|
||||
|
||||
use std::io;
|
||||
|
||||
use nix::errno::Errno;
|
||||
use nix::Error;
|
||||
|
||||
/// Helper to convert non-system-errors into an `io::Error` or `io::ErrorKind::Other`.
|
||||
///
|
||||
/// A more convenient way is to use the `io_format_err!` macro.
|
||||
pub fn io_err_other<E: ToString>(e: E) -> io::Error {
|
||||
io::Error::new(std::io::ErrorKind::Other, e.to_string())
|
||||
}
|
||||
|
||||
/// This trait should be implemented for error types which can represent system errors. Note that
|
||||
/// it is discouraged to try to map non-system errors to with this trait, since users of this trait
|
||||
/// assume there to be a relation between the error code and a previous system call. For instance,
|
||||
/// `error.is_errno(Errno::EAGAIN)` can be used when implementing a reactor to drive async I/O.
|
||||
///
|
||||
/// Usage examples:
|
||||
///
|
||||
/// ```
|
||||
/// # use failure::{bail, Error};
|
||||
/// use nix::{dir::Dir, fcntl::OFlag, sys::stat::Mode};
|
||||
///
|
||||
/// use proxmox_sys::error::SysError;
|
||||
///
|
||||
/// # fn test() -> Result<(), Error> {
|
||||
///
|
||||
/// match Dir::open(".", OFlag::O_RDONLY, Mode::empty()) {
|
||||
/// Ok(_dir) => {
|
||||
/// // Do something
|
||||
/// }
|
||||
/// Err(ref err) if err.not_found() => {
|
||||
/// // Handle ENOENT specially
|
||||
/// }
|
||||
/// Err(err) => bail!("failed to open directory: {}", err),
|
||||
/// }
|
||||
///
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub trait SysError {
|
||||
/// Check if this error is a specific error returned from a system call.
|
||||
fn is_errno(&self, value: Errno) -> bool;
|
||||
|
||||
/// Convert this error into a `std::io::Error`. This must use the correct `std::io::ErrorKind`,
|
||||
/// so that for example `ErrorKind::WouldBlock` means that the previous system call failed with
|
||||
/// `EAGAIN`.
|
||||
fn into_io_error(self) -> io::Error;
|
||||
|
||||
/// Convenience shortcut to check for `EAGAIN`.
|
||||
#[inline]
|
||||
fn would_block(&self) -> bool {
|
||||
self.is_errno(Errno::EAGAIN)
|
||||
}
|
||||
|
||||
/// Convenience shortcut to check for `ENOENT`.
|
||||
#[inline]
|
||||
fn not_found(&self) -> bool {
|
||||
self.is_errno(Errno::ENOENT)
|
||||
}
|
||||
|
||||
/// Convenience shortcut to check for `EEXIST`.
|
||||
#[inline]
|
||||
fn already_exists(&self) -> bool {
|
||||
self.is_errno(Errno::EEXIST)
|
||||
}
|
||||
}
|
||||
|
||||
impl SysError for io::Error {
|
||||
#[inline]
|
||||
fn is_errno(&self, value: Errno) -> bool {
|
||||
self.raw_os_error() == Some(value as i32)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_io_error(self) -> io::Error {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl SysError for nix::Error {
|
||||
#[inline]
|
||||
fn is_errno(&self, value: Errno) -> bool {
|
||||
*self == Error::Sys(value)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_io_error(self) -> io::Error {
|
||||
match self {
|
||||
Error::Sys(raw) => io::Error::from_raw_os_error(raw as _),
|
||||
other => io::Error::new(io::ErrorKind::Other, other.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience helper to map a `Result<_, nix::Error>` to a `Result<_, std::io::Error>` quickly.
|
||||
///
|
||||
/// Usage example:
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::os::unix::io::RawFd;
|
||||
/// # use failure::{bail, Error};
|
||||
///
|
||||
/// use proxmox_sys::error::SysResult;
|
||||
///
|
||||
/// struct MyReader(RawFd);
|
||||
///
|
||||
/// impl std::io::Read for MyReader {
|
||||
/// fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
/// nix::unistd::read(self.0, buf).into_io_result()
|
||||
/// }
|
||||
///
|
||||
/// // ... rest
|
||||
/// }
|
||||
/// ```
|
||||
pub trait SysResult {
|
||||
type Ok;
|
||||
|
||||
fn into_io_result(self) -> io::Result<Self::Ok>;
|
||||
}
|
||||
|
||||
impl<T> SysResult for Result<T, nix::Error> {
|
||||
type Ok = T;
|
||||
|
||||
#[inline]
|
||||
fn into_io_result(self) -> io::Result<T> {
|
||||
self.map_err(|e| e.into_io_error())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! other_error {
|
||||
($err:ty) => {
|
||||
impl<T> SysResult for Result<T, $err> {
|
||||
type Ok = T;
|
||||
|
||||
#[inline]
|
||||
fn into_io_result(self) -> io::Result<T> {
|
||||
self.map_err($crate::error::io_err_other)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
other_error!(std::char::ParseCharError);
|
||||
other_error!(std::net::AddrParseError);
|
||||
other_error!(std::num::ParseFloatError);
|
||||
other_error!(std::num::ParseIntError);
|
||||
other_error!(std::str::ParseBoolError);
|
||||
other_error!(std::str::Utf8Error);
|
||||
other_error!(std::string::FromUtf8Error);
|
@ -2,4 +2,5 @@
|
||||
|
||||
pub mod macros;
|
||||
|
||||
pub mod error;
|
||||
pub mod linux;
|
||||
|
Loading…
x
Reference in New Issue
Block a user