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