Skip to main content

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}