1use std::fmt;
4
5pub mod code {
7 pub const OK: i32 = 0;
8 pub const INVALID_ARG: i32 = 1;
9 pub const NOT_FOUND: i32 = 2;
10 pub const KERNEL: i32 = 3;
11 pub const PANIC: i32 = 4;
12 pub const WOULD_BLOCK: i32 = 5;
13 pub const TIMEOUT: i32 = 6;
14 pub const CANCELLED: i32 = 7;
15 pub const CLOSED: i32 = 8;
16 pub const ABI: i32 = 9;
17 pub const UNSUPPORTED: i32 = 10;
18 pub const STATE: i32 = 11;
19}
20
21#[derive(Debug, Clone, PartialEq, Eq)]
22pub enum Error {
23 InvalidArg(String),
25 NotFound(String),
27 Kernel(String),
29 Panic(String),
31 WouldBlock,
33 Timeout,
34 Cancelled,
35 Closed,
37 Abi(String),
39 Unsupported(String),
41 State(String),
43}
44
45impl Error {
46 pub fn code(&self) -> i32 {
47 match self {
48 Error::InvalidArg(_) => code::INVALID_ARG,
49 Error::NotFound(_) => code::NOT_FOUND,
50 Error::Kernel(_) => code::KERNEL,
51 Error::Panic(_) => code::PANIC,
52 Error::WouldBlock => code::WOULD_BLOCK,
53 Error::Timeout => code::TIMEOUT,
54 Error::Cancelled => code::CANCELLED,
55 Error::Closed => code::CLOSED,
56 Error::Abi(_) => code::ABI,
57 Error::Unsupported(_) => code::UNSUPPORTED,
58 Error::State(_) => code::STATE,
59 }
60 }
61
62 pub(crate) fn context(self, context: impl AsRef<str>) -> Self {
63 let context = context.as_ref();
64 match self {
65 Error::InvalidArg(message) => Error::InvalidArg(format!("{context}: {message}")),
66 Error::NotFound(message) => Error::NotFound(format!("{context}: {message}")),
67 Error::Kernel(message) => Error::Kernel(format!("{context}: {message}")),
68 Error::Panic(message) => Error::Panic(format!("{context}: {message}")),
69 Error::Abi(message) => Error::Abi(format!("{context}: {message}")),
70 Error::Unsupported(message) => Error::Unsupported(format!("{context}: {message}")),
71 Error::State(message) => Error::State(format!("{context}: {message}")),
72 other => other,
73 }
74 }
75}
76
77impl fmt::Display for Error {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 match self {
80 Error::InvalidArg(m) => write!(f, "invalid argument or config: {m}"),
81 Error::NotFound(m) => write!(f, "not found: {m}"),
82 Error::Kernel(m) => write!(f, "kernel failed: {m}"),
83 Error::Panic(m) => write!(f, "internal panic: {m}"),
84 Error::WouldBlock => f.write_str("temporarily unavailable (queue full or no data)"),
85 Error::Timeout => f.write_str("timeout"),
86 Error::Cancelled => f.write_str("cancelled"),
87 Error::Closed => f.write_str("closed"),
88 Error::Abi(m) => write!(f, "ABI mismatch: {m}"),
89 Error::Unsupported(m) => write!(f, "unsupported in this version: {m}"),
90 Error::State(m) => write!(f, "operation not allowed in current state: {m}"),
91 }
92 }
93}
94
95impl std::error::Error for Error {}
96
97pub type Result<T> = std::result::Result<T, Error>;
98
99pub fn invalid_arg<T>(msg: impl Into<String>) -> Result<T> {
101 Err(Error::InvalidArg(msg.into()))
102}
103pub fn not_found<T>(msg: impl Into<String>) -> Result<T> {
104 Err(Error::NotFound(msg.into()))
105}
106pub fn unsupported<T>(msg: impl Into<String>) -> Result<T> {
107 Err(Error::Unsupported(msg.into()))
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[test]
115 fn codes_match_c_abi() {
116 assert_eq!(Error::InvalidArg(String::new()).code(), 1);
117 assert_eq!(Error::Unsupported(String::new()).code(), 10);
118 assert_eq!(Error::State(String::new()).code(), 11);
119 }
120
121 #[test]
122 fn messages_are_non_empty() {
123 for e in [
124 Error::WouldBlock,
125 Error::Timeout,
126 Error::Cancelled,
127 Error::Closed,
128 ] {
129 assert!(!e.to_string().is_empty());
130 }
131 }
132}