use std::fmt;
pub mod code {
pub const OK: i32 = 0;
pub const INVALID_ARG: i32 = 1;
pub const NOT_FOUND: i32 = 2;
pub const KERNEL: i32 = 3;
pub const PANIC: i32 = 4;
pub const WOULD_BLOCK: i32 = 5;
pub const TIMEOUT: i32 = 6;
pub const CANCELLED: i32 = 7;
pub const CLOSED: i32 = 8;
pub const ABI: i32 = 9;
pub const UNSUPPORTED: i32 = 10;
pub const STATE: i32 = 11;
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
InvalidArg(String),
NotFound(String),
Kernel(String),
Panic(String),
WouldBlock,
Timeout,
Cancelled,
Closed,
Abi(String),
Unsupported(String),
State(String),
}
impl Error {
pub fn code(&self) -> i32 {
match self {
Error::InvalidArg(_) => code::INVALID_ARG,
Error::NotFound(_) => code::NOT_FOUND,
Error::Kernel(_) => code::KERNEL,
Error::Panic(_) => code::PANIC,
Error::WouldBlock => code::WOULD_BLOCK,
Error::Timeout => code::TIMEOUT,
Error::Cancelled => code::CANCELLED,
Error::Closed => code::CLOSED,
Error::Abi(_) => code::ABI,
Error::Unsupported(_) => code::UNSUPPORTED,
Error::State(_) => code::STATE,
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::InvalidArg(m) => write!(f, "invalid argument or config: {m}"),
Error::NotFound(m) => write!(f, "not found: {m}"),
Error::Kernel(m) => write!(f, "kernel failed: {m}"),
Error::Panic(m) => write!(f, "internal panic: {m}"),
Error::WouldBlock => f.write_str("temporarily unavailable (queue full or no data)"),
Error::Timeout => f.write_str("timeout"),
Error::Cancelled => f.write_str("cancelled"),
Error::Closed => f.write_str("closed"),
Error::Abi(m) => write!(f, "ABI mismatch: {m}"),
Error::Unsupported(m) => write!(f, "unsupported in this version: {m}"),
Error::State(m) => write!(f, "operation not allowed in current state: {m}"),
}
}
}
impl std::error::Error for Error {}
pub type Result<T> = std::result::Result<T, Error>;
pub fn invalid_arg<T>(msg: impl Into<String>) -> Result<T> {
Err(Error::InvalidArg(msg.into()))
}
pub fn not_found<T>(msg: impl Into<String>) -> Result<T> {
Err(Error::NotFound(msg.into()))
}
pub fn unsupported<T>(msg: impl Into<String>) -> Result<T> {
Err(Error::Unsupported(msg.into()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn codes_match_c_abi() {
assert_eq!(Error::InvalidArg(String::new()).code(), 1);
assert_eq!(Error::Unsupported(String::new()).code(), 10);
assert_eq!(Error::State(String::new()).code(), 11);
}
#[test]
fn messages_are_non_empty() {
for e in [
Error::WouldBlock,
Error::Timeout,
Error::Cancelled,
Error::Closed,
] {
assert!(!e.to_string().is_empty());
}
}
}