use nix::libc;
use std::io;
use thiserror::Error;
pub type IbvResult<T> = Result<T, IbvError>;
#[derive(Debug, Error)]
pub enum IbvError {
#[error("Invalid argument: {0}")]
InvalidInput(String),
#[error("Resource exhausted: {0}")]
Resource(String),
#[error("Permission denied: {0}")]
Permission(String),
#[error("Entity not found: {0}")]
NotFound(String),
#[error("Driver/OS error: {0}")]
Driver(io::Error),
}
impl IbvError {
pub(crate) fn from_errno_with_msg(errno: i32, msg: impl Into<String>) -> Self {
match errno {
libc::EINVAL => {
IbvError::InvalidInput(format!("{} (driver rejected params)", msg.into()))
}
libc::ENOMEM => IbvError::Resource(format!("{} (out of memory)", msg.into())),
libc::EMFILE => {
IbvError::Resource(format!("{} (too many open files/objects)", msg.into()))
}
libc::EAGAIN => {
IbvError::Resource(format!("{} (temporary resource shortage)", msg.into()))
}
libc::EACCES | libc::EPERM => IbvError::Permission(msg.into()),
libc::ENOENT => IbvError::NotFound(msg.into()),
_ => IbvError::Driver(io::Error::from_raw_os_error(errno)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn einval_maps_to_invalid_input() {
assert!(matches!(
IbvError::from_errno_with_msg(libc::EINVAL, "test"),
IbvError::InvalidInput(_)
));
}
#[test]
fn enomem_maps_to_resource() {
assert!(matches!(
IbvError::from_errno_with_msg(libc::ENOMEM, "test"),
IbvError::Resource(_)
));
}
#[test]
fn emfile_maps_to_resource() {
assert!(matches!(
IbvError::from_errno_with_msg(libc::EMFILE, "test"),
IbvError::Resource(_)
));
}
#[test]
fn eagain_maps_to_resource() {
assert!(matches!(
IbvError::from_errno_with_msg(libc::EAGAIN, "test"),
IbvError::Resource(_)
));
}
#[test]
fn eacces_maps_to_permission() {
let err = IbvError::from_errno_with_msg(libc::EACCES, "test");
assert!(matches!(err, IbvError::Permission(_)));
}
#[test]
fn eperm_maps_to_permission() {
let err = IbvError::from_errno_with_msg(libc::EPERM, "test");
assert!(matches!(err, IbvError::Permission(_)));
}
#[test]
fn enoent_maps_to_not_found() {
let err = IbvError::from_errno_with_msg(libc::ENOENT, "test");
assert!(matches!(err, IbvError::NotFound(_)));
}
#[test]
fn unknown_errno_maps_to_driver() {
let err = IbvError::from_errno_with_msg(libc::EIO, "test");
assert!(matches!(err, IbvError::Driver(_)));
}
}