xisf_header/error.rs
1//! Error and result types for the crate.
2
3use thiserror::Error;
4
5/// A specialized [`Result`](std::result::Result) alias for header operations.
6pub type Result<T> = std::result::Result<T, Error>;
7
8/// Errors that can occur while parsing, reading, or writing an XISF header.
9///
10/// ```
11/// use xisf_header::{Error, Header};
12///
13/// let mut header = Header::new();
14/// header.append("HISTORY", "reduced with siril").unwrap();
15/// header.append("HISTORY", "stacked 20x300s").unwrap();
16///
17/// assert!(matches!(
18/// header.get_str("HISTORY"),
19/// Err(Error::Ambiguous { count: 2, .. })
20/// ));
21/// ```
22#[derive(Debug, Error)]
23#[non_exhaustive]
24pub enum Error {
25 /// The input was shorter than required (the 16-byte preamble, or the
26 /// preamble plus the declared XML-header length).
27 #[error("input too small: need at least {needed} bytes, got {got}")]
28 TooSmall {
29 /// Minimum number of bytes required.
30 needed: usize,
31 /// Number of bytes actually supplied.
32 got: usize,
33 },
34
35 /// The first eight bytes were not the `XISF0100` monolithic-signature.
36 #[error("invalid XISF signature (expected `XISF0100`)")]
37 InvalidSignature,
38
39 /// The declared XML-header length exceeded the 8 MiB safety cap.
40 #[error("XML header too large: {len} bytes exceeds the {max}-byte cap")]
41 HeaderTooLarge {
42 /// Declared header length, in bytes.
43 len: usize,
44 /// Maximum accepted header length, in bytes.
45 max: usize,
46 },
47
48 /// The XML header was not valid UTF-8.
49 #[error("XML header is not valid UTF-8")]
50 Utf8(#[from] std::str::Utf8Error),
51
52 /// The XML header was syntactically malformed.
53 #[error("malformed XML header: {0}")]
54 Xml(#[from] quick_xml::Error),
55
56 /// An attribute in the XML header was malformed.
57 #[error("malformed XML attribute: {0}")]
58 Attr(#[from] quick_xml::events::attributes::AttrError),
59
60 /// A singular access (`get`/`set`/`remove` by bare name) targeted a keyword
61 /// that appears more than once. Disambiguate with an `(name, n)` key, or use
62 /// [`get_all`](crate::Header::get_all)/[`count`](crate::Header::count).
63 #[error("keyword `{name}` is ambiguous: it appears {count} times")]
64 Ambiguous {
65 /// The keyword name.
66 name: String,
67 /// Number of occurrences.
68 count: usize,
69 },
70
71 /// A [`Key::Nth`](crate::Key::Nth) `(name, n)` access referenced an
72 /// occurrence index that does not exist.
73 #[error("keyword `{name}` has no occurrence {index} ({count} present)")]
74 IndexOutOfRange {
75 /// The keyword name.
76 name: String,
77 /// The requested occurrence index.
78 index: usize,
79 /// Number of occurrences present.
80 count: usize,
81 },
82
83 /// A write supplied a name that is not a valid FITS keyword (≤ 8 printable
84 /// ASCII characters) or valid XISF property id.
85 #[error("invalid identifier `{name}`: {reason}")]
86 InvalidName {
87 /// The rejected identifier.
88 name: String,
89 /// Why it was rejected.
90 reason: &'static str,
91 },
92
93 /// An I/O error occurred while reading or writing a file.
94 #[error(transparent)]
95 Io(#[from] std::io::Error),
96
97 /// [`Header::update_file`](crate::Header::update_file) cannot safely
98 /// splice this file's XML: the common case is exactly one `<Image
99 /// location="attachment:OFFSET:SIZE">` element. Multiple attachments
100 /// (e.g. a `Thumbnail` alongside the `Image`), no attachment at all, or a
101 /// self-closing `<Image/>` that needs new child elements inserted are
102 /// rejected rather than risking data loss.
103 #[error("unsupported XISF layout for update_file: {0}")]
104 Unsupported(String),
105}