use core::fmt;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(i32)]
pub enum ErrorCode {
None = 0,
UnknownState,
StreamInitFailed,
StreamReadOnly,
InvalidAsdfHeader,
UnexpectedEof,
InvalidBlockHeader,
BlockMagicMismatch,
YamlParserInitFailed,
YamlParseFailed,
OutOfMemory,
System,
InvalidArgument,
UnknownCompression,
CompressionFailed,
ExtensionNotFound,
OverLimit,
}
#[derive(Debug)]
pub struct Error {
code: ErrorCode,
message: String,
errno: Option<i32>,
}
impl Error {
pub fn new(code: ErrorCode, message: impl Into<String>) -> Self {
Self { code, message: message.into(), errno: None }
}
pub fn system(errno: i32, message: impl Into<String>) -> Self {
Self { code: ErrorCode::System, message: message.into(), errno: Some(errno) }
}
pub fn code(&self) -> ErrorCode {
self.code
}
pub fn errno(&self) -> Option<i32> {
self.errno
}
pub fn message(&self) -> &str {
&self.message
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.message)
}
}
impl core::error::Error for Error {}
impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
let errno = e.raw_os_error();
match errno {
Some(n) => Error::system(n, e.to_string()),
None => Error::new(ErrorCode::System, e.to_string()),
}
}
}
impl From<asdf_yaml::ParseError> for Error {
fn from(e: asdf_yaml::ParseError) -> Self {
Error::new(ErrorCode::YamlParseFailed, e.to_string())
}
}
pub type Result<T> = core::result::Result<T, Error>;
macro_rules! err {
($code:ident, $($arg:tt)*) => {
$crate::error::Error::new($crate::error::ErrorCode::$code, format!($($arg)*))
};
}
pub(crate) use err;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn discriminants_match_the_c_abi() {
assert_eq!(ErrorCode::None as i32, 0);
assert_eq!(ErrorCode::UnknownState as i32, 1);
assert_eq!(ErrorCode::StreamInitFailed as i32, 2);
assert_eq!(ErrorCode::StreamReadOnly as i32, 3);
assert_eq!(ErrorCode::InvalidAsdfHeader as i32, 4);
assert_eq!(ErrorCode::UnexpectedEof as i32, 5);
assert_eq!(ErrorCode::InvalidBlockHeader as i32, 6);
assert_eq!(ErrorCode::BlockMagicMismatch as i32, 7);
assert_eq!(ErrorCode::YamlParserInitFailed as i32, 8);
assert_eq!(ErrorCode::YamlParseFailed as i32, 9);
assert_eq!(ErrorCode::OutOfMemory as i32, 10);
assert_eq!(ErrorCode::System as i32, 11);
assert_eq!(ErrorCode::InvalidArgument as i32, 12);
assert_eq!(ErrorCode::UnknownCompression as i32, 13);
assert_eq!(ErrorCode::CompressionFailed as i32, 14);
assert_eq!(ErrorCode::ExtensionNotFound as i32, 15);
assert_eq!(ErrorCode::OverLimit as i32, 16);
}
#[test]
fn io_errors_carry_errno() {
let io = std::io::Error::from_raw_os_error(2);
let e = Error::from(io);
assert_eq!(e.code(), ErrorCode::System);
assert_eq!(e.errno(), Some(2));
}
}