1#[derive(Debug)]
3pub enum Error {
4 InvalidHeader(&'static str),
6 UnexpectedEof,
8 InvalidBitpix(i64),
10 InvalidKeyword,
12 UnsupportedExtension(&'static str),
14 InvalidValue,
16 MissingKeyword(&'static str),
18 UnsupportedCompression(&'static str),
20 DecompressionError(&'static str),
22 #[cfg(feature = "std")]
24 Io(std::io::Error),
25}
26
27pub type Result<T> = core::result::Result<T, Error>;
29
30impl core::fmt::Display for Error {
31 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
32 match self {
33 Error::InvalidHeader(ctx) => write!(f, "invalid FITS header: {ctx}"),
34 Error::UnexpectedEof => write!(f, "unexpected end of file"),
35 Error::InvalidBitpix(v) => write!(f, "invalid BITPIX value: {v}"),
36 Error::InvalidKeyword => write!(f, "invalid keyword name"),
37 Error::UnsupportedExtension(ctx) => write!(f, "unsupported XTENSION type: {ctx}"),
38 Error::InvalidValue => write!(f, "invalid header value"),
39 Error::MissingKeyword(kw) => write!(f, "missing required keyword: {kw}"),
40 Error::UnsupportedCompression(ctx) => {
41 write!(f, "unsupported compression algorithm: {ctx}")
42 }
43 Error::DecompressionError(ctx) => write!(f, "decompression error: {ctx}"),
44 #[cfg(feature = "std")]
45 Error::Io(e) => write!(f, "I/O error: {e}"),
46 }
47 }
48}
49
50#[cfg(feature = "std")]
51impl std::error::Error for Error {
52 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
53 match self {
54 Error::Io(e) => Some(e),
55 _ => None,
56 }
57 }
58}
59
60#[cfg(feature = "std")]
61impl From<std::io::Error> for Error {
62 fn from(e: std::io::Error) -> Self {
63 Error::Io(e)
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn display_invalid_header() {
73 let e = Error::InvalidHeader("bad block");
74 assert_eq!(e.to_string(), "invalid FITS header: bad block");
75 }
76
77 #[test]
78 fn display_unexpected_eof() {
79 let e = Error::UnexpectedEof;
80 assert_eq!(e.to_string(), "unexpected end of file");
81 }
82
83 #[test]
84 fn display_invalid_bitpix() {
85 let e = Error::InvalidBitpix(-99);
86 assert_eq!(e.to_string(), "invalid BITPIX value: -99");
87 }
88
89 #[test]
90 fn display_invalid_keyword() {
91 let e = Error::InvalidKeyword;
92 assert_eq!(e.to_string(), "invalid keyword name");
93 }
94
95 #[test]
96 fn display_unsupported_extension() {
97 let e = Error::UnsupportedExtension("FOREIGN");
98 assert_eq!(e.to_string(), "unsupported XTENSION type: FOREIGN");
99 }
100
101 #[test]
102 fn display_invalid_value() {
103 let e = Error::InvalidValue;
104 assert_eq!(e.to_string(), "invalid header value");
105 }
106
107 #[test]
108 fn display_missing_keyword() {
109 let e = Error::MissingKeyword("NAXIS");
110 assert_eq!(e.to_string(), "missing required keyword: NAXIS");
111 }
112
113 #[cfg(feature = "std")]
114 #[test]
115 fn display_io_error() {
116 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
117 let e = Error::Io(io_err);
118 assert_eq!(e.to_string(), "I/O error: file not found");
119 }
120
121 #[cfg(feature = "std")]
122 #[test]
123 fn io_error_from_conversion() {
124 let io_err = std::io::Error::other("oops");
125 let e: Error = io_err.into();
126 assert!(matches!(e, Error::Io(_)));
127 }
128
129 #[test]
130 fn result_type_alias() {
131 let ok: Result<u32> = Ok(42);
132 assert!(ok.is_ok());
133
134 let err: Result<u32> = Err(Error::InvalidHeader("test"));
135 assert!(err.is_err());
136 }
137
138 #[test]
139 fn debug_formatting() {
140 let e = Error::InvalidBitpix(99);
141 let debug = alloc::format!("{e:?}");
142 assert!(debug.contains("InvalidBitpix"));
143 assert!(debug.contains("99"));
144 }
145
146 #[cfg(feature = "std")]
147 #[test]
148 fn std_error_source() {
149 use std::error::Error as StdError;
150
151 let e = Error::InvalidHeader("test");
152 assert!(e.source().is_none());
153
154 let io_err = std::io::Error::other("inner");
155 let e = Error::Io(io_err);
156 assert!(e.source().is_some());
157 }
158}