1use snafu::Backtrace;
11use snafu::Snafu;
12
13pub type Result<T> = std::result::Result<T, Error>;
14
15#[derive(Snafu, Debug)]
16#[snafu(visibility(pub))]
17pub enum Error {
18 #[snafu(display("NULL pointer on parameter '{}'", param))]
19 NullPointer {
20 param: &'static str,
21 backtrace: Backtrace,
22 },
23 #[snafu(display("Invalid UTF-8"))]
24 InvalidUTF8 {
25 backtrace: Backtrace,
26 source: std::str::Utf8Error,
27 },
28
29 #[snafu(display("Value not found"))]
30 ValueNotFound,
31 #[snafu(display("Invalid compartment: {}", value))]
32 InvalidCompartment { value: u32 },
33 #[snafu(display("Feature not implemented: {}", what))]
34 NotImplemented { what: &'static str },
35
36 #[snafu(display("Unknown backend: '{}'", name))]
37 UnknownBackend { name: String },
38
39 #[snafu(display("Invalid path component: '{}'", component))]
40 InvalidPath { component: String },
41
42 #[snafu(display("Identity signature invalid"))]
43 IdentitySignatureInvalid,
44
45 #[snafu(display("I/O error: {}", source))]
46 Io {
47 source: std::io::Error,
48 backtrace: Backtrace,
49 },
50
51 #[snafu(display("Wrapped error: {}", message))]
52 Wrapped { message: String },
53}
54
55impl Error {
56 pub fn code(&self) -> u32 {
57 error_code(self)
58 }
59}
60
61#[allow(non_camel_case_types)]
65#[repr(u32)]
66pub enum ErrorCode {
67 UNKNOWN = 0x1000,
68 NULL_POINTER = 0x1001,
69 INVALID_UTF8 = 0x1002,
70
71 VALUE_NOT_FOUND = 0x1010,
72 INVALID_COMPARTMENT = 0x1011,
73 NOT_IMPLEMENTED = 0x1012,
74
75 UNKNOWN_BACKEND = 0x1020,
76
77 INVALID_PATH = 0x1031,
78 IO = 0x1032,
79
80 IDENTITY_SIGNATURE_INVALID = 0x1030,
81
82 WRAPPED = 0x1100,
83}
84
85fn error_code(error: &Error) -> u32 {
86 match error {
87 Error::NullPointer { .. } => ErrorCode::NULL_POINTER.into(),
88 Error::InvalidUTF8 { .. } => ErrorCode::INVALID_UTF8.into(),
89
90 Error::ValueNotFound => ErrorCode::VALUE_NOT_FOUND.into(),
91 Error::InvalidCompartment { .. } => ErrorCode::INVALID_COMPARTMENT.into(),
92 Error::NotImplemented { .. } => ErrorCode::NOT_IMPLEMENTED.into(),
93
94 Error::UnknownBackend { .. } => ErrorCode::UNKNOWN_BACKEND.into(),
95
96 Error::InvalidPath { .. } => ErrorCode::INVALID_PATH.into(),
97 Error::Io { .. } => ErrorCode::IO.into(),
98
99 Error::IdentitySignatureInvalid => ErrorCode::IDENTITY_SIGNATURE_INVALID.into(),
100
101 Error::Wrapped { .. } => ErrorCode::WRAPPED.into(),
102 }
103}
104
105impl From<ErrorCode> for u32 {
106 #[inline]
107 fn from(code: ErrorCode) -> u32 {
108 code as u32
109 }
110}
111
112impl From<Error> for u32 {
113 #[inline]
114 fn from(err: Error) -> u32 {
115 error_code(&err)
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122 use snafu::GenerateImplicitData;
123
124 #[test]
125 fn value_not_found_code() {
126 let err = Error::ValueNotFound;
127 assert_eq!(err.code(), ErrorCode::VALUE_NOT_FOUND as u32);
128 }
129
130 #[test]
131 fn not_implemented_carries_context() {
132 let err = Error::NotImplemented {
133 what: "filesystem backend",
134 };
135 assert!(format!("{err}").contains("filesystem backend"));
136 assert_eq!(err.code(), ErrorCode::NOT_IMPLEMENTED as u32);
137 }
138
139 #[test]
140 fn null_pointer_has_param_in_display() {
141 let err = Error::NullPointer {
142 param: "ks",
143 backtrace: Backtrace::generate(),
144 };
145 assert!(format!("{err}").contains("ks"));
146 }
147}