Skip to main content

fitsio_pure/
error.rs

1/// All errors that can occur during FITS I/O operations.
2#[derive(Debug)]
3pub enum Error {
4    /// Malformed FITS header block.
5    InvalidHeader(&'static str),
6    /// Premature end of data while reading.
7    UnexpectedEof,
8    /// Unrecognized BITPIX value.
9    InvalidBitpix(i64),
10    /// Malformed keyword name in a header card.
11    InvalidKeyword,
12    /// Unknown or unsupported XTENSION type.
13    UnsupportedExtension(&'static str),
14    /// A header value could not be parsed correctly.
15    InvalidValue,
16    /// A required keyword was not found in the header.
17    MissingKeyword(&'static str),
18    /// Unsupported or unknown tile compression algorithm.
19    UnsupportedCompression(&'static str),
20    /// Error during tile decompression (Rice/GZIP).
21    DecompressionError(&'static str),
22    /// An I/O error from the standard library.
23    #[cfg(feature = "std")]
24    Io(std::io::Error),
25}
26
27/// Convenience alias used throughout the crate.
28pub 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}