1use core::fmt;
4
5#[derive(Clone, Copy, PartialEq, Eq, Debug)]
9#[repr(i32)]
10pub enum ErrorCode {
11 None = 0,
13 UnknownState,
15 StreamInitFailed,
17 StreamReadOnly,
19 InvalidAsdfHeader,
21 UnexpectedEof,
23 InvalidBlockHeader,
25 BlockMagicMismatch,
27 YamlParserInitFailed,
29 YamlParseFailed,
31 OutOfMemory,
33 System,
35 InvalidArgument,
37 UnknownCompression,
39 CompressionFailed,
41 ExtensionNotFound,
43 OverLimit,
45}
46
47#[derive(Debug)]
49pub struct Error {
50 code: ErrorCode,
51 message: String,
52 errno: Option<i32>,
53}
54
55impl Error {
56 pub fn new(code: ErrorCode, message: impl Into<String>) -> Self {
58 Self { code, message: message.into(), errno: None }
59 }
60
61 pub fn system(errno: i32, message: impl Into<String>) -> Self {
63 Self { code: ErrorCode::System, message: message.into(), errno: Some(errno) }
64 }
65
66 pub fn code(&self) -> ErrorCode {
68 self.code
69 }
70
71 pub fn errno(&self) -> Option<i32> {
73 self.errno
74 }
75
76 pub fn message(&self) -> &str {
78 &self.message
79 }
80}
81
82impl fmt::Display for Error {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 f.write_str(&self.message)
85 }
86}
87
88impl core::error::Error for Error {}
89
90impl From<std::io::Error> for Error {
91 fn from(e: std::io::Error) -> Self {
92 let errno = e.raw_os_error();
93 match errno {
94 Some(n) => Error::system(n, e.to_string()),
95 None => Error::new(ErrorCode::System, e.to_string()),
96 }
97 }
98}
99
100impl From<asdf_yaml::ParseError> for Error {
101 fn from(e: asdf_yaml::ParseError) -> Self {
102 Error::new(ErrorCode::YamlParseFailed, e.to_string())
103 }
104}
105
106pub type Result<T> = core::result::Result<T, Error>;
108
109macro_rules! err {
111 ($code:ident, $($arg:tt)*) => {
112 $crate::error::Error::new($crate::error::ErrorCode::$code, format!($($arg)*))
113 };
114}
115
116pub(crate) use err;
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 #[test]
123 fn discriminants_match_the_c_abi() {
124 assert_eq!(ErrorCode::None as i32, 0);
127 assert_eq!(ErrorCode::UnknownState as i32, 1);
128 assert_eq!(ErrorCode::StreamInitFailed as i32, 2);
129 assert_eq!(ErrorCode::StreamReadOnly as i32, 3);
130 assert_eq!(ErrorCode::InvalidAsdfHeader as i32, 4);
131 assert_eq!(ErrorCode::UnexpectedEof as i32, 5);
132 assert_eq!(ErrorCode::InvalidBlockHeader as i32, 6);
133 assert_eq!(ErrorCode::BlockMagicMismatch as i32, 7);
134 assert_eq!(ErrorCode::YamlParserInitFailed as i32, 8);
135 assert_eq!(ErrorCode::YamlParseFailed as i32, 9);
136 assert_eq!(ErrorCode::OutOfMemory as i32, 10);
137 assert_eq!(ErrorCode::System as i32, 11);
138 assert_eq!(ErrorCode::InvalidArgument as i32, 12);
139 assert_eq!(ErrorCode::UnknownCompression as i32, 13);
140 assert_eq!(ErrorCode::CompressionFailed as i32, 14);
141 assert_eq!(ErrorCode::ExtensionNotFound as i32, 15);
142 assert_eq!(ErrorCode::OverLimit as i32, 16);
143 }
144
145 #[test]
146 fn io_errors_carry_errno() {
147 let io = std::io::Error::from_raw_os_error(2);
148 let e = Error::from(io);
149 assert_eq!(e.code(), ErrorCode::System);
150 assert_eq!(e.errno(), Some(2));
151 }
152}