Skip to main content

rust_hdf5/
error.rs

1//! Error types for the hdf5 public API crate.
2
3/// Errors that can occur when using the HDF5 public API.
4#[derive(Debug)]
5pub enum Hdf5Error {
6    /// An I/O error from the operating system.
7    Io(std::io::Error),
8    /// A low-level format encoding/decoding error.
9    Format(crate::format::FormatError),
10    /// An I/O-layer error from hdf5-io.
11    IoLayer(crate::io::IoError),
12    /// A requested object (dataset, group, attribute) was not found.
13    ///
14    /// The string contains the name of the missing object (e.g., dataset name).
15    NotFound(String),
16    /// The file or object is in an invalid state for the requested operation.
17    InvalidState(String),
18    /// A type mismatch between the Rust type and the HDF5 datatype.
19    TypeMismatch(String),
20    /// The object exists in the file but uses a feature this crate cannot
21    /// decode. The string names the feature. Distinct from
22    /// [`NotFound`](Self::NotFound): the name is in the listing, the content
23    /// is out of reach.
24    Unsupported(String),
25    /// A soft or external link whose target does not exist. `H5Dopen` on a
26    /// path through such a link fails; the name itself is present in the
27    /// listing. `target` is the link value: a path for a soft link,
28    /// `file::path` for an external one.
29    DanglingLink { link: String, target: String },
30    /// A zero-copy view of a dataset was asked for and the dataset cannot be
31    /// viewed. The reason names why; a copying read still works.
32    #[cfg(feature = "mmap")]
33    NotViewable(crate::mapped::ViewRefusal),
34    /// An external link whose target *file* could not be opened, listing the
35    /// candidate paths that were tried.
36    ExternalFileNotFound {
37        link: String,
38        file: String,
39        searched: Vec<String>,
40    },
41}
42
43impl From<std::io::Error> for Hdf5Error {
44    fn from(e: std::io::Error) -> Self {
45        Self::Io(e)
46    }
47}
48
49impl From<crate::format::FormatError> for Hdf5Error {
50    fn from(e: crate::format::FormatError) -> Self {
51        Self::Format(e)
52    }
53}
54
55/// A caller's hyperslab the extent does not admit is a bad request, not a
56/// malformed file.
57impl From<crate::format::selection::HyperslabError> for Hdf5Error {
58    fn from(e: crate::format::selection::HyperslabError) -> Self {
59        Self::InvalidState(e.to_string())
60    }
61}
62
63impl From<crate::io::IoError> for Hdf5Error {
64    fn from(e: crate::io::IoError) -> Self {
65        // Every outcome that names *why* a lookup failed carries through as
66        // itself so a caller can match on it; everything else keeps its
67        // existing shape. `NotFound` is among them: a `?` on an I/O-layer
68        // lookup must not turn a plain absence into an opaque `IoLayer`,
69        // which is what forced callers to re-map it by hand.
70        match e {
71            crate::io::IoError::NotFound(s) => Self::NotFound(s),
72            crate::io::IoError::Unsupported(s) => Self::Unsupported(s),
73            crate::io::IoError::DanglingLink { link, target } => {
74                Self::DanglingLink { link, target }
75            }
76            crate::io::IoError::ExternalFileNotFound {
77                link,
78                file,
79                searched,
80            } => Self::ExternalFileNotFound {
81                link,
82                file,
83                searched,
84            },
85            other => Self::IoLayer(other),
86        }
87    }
88}
89
90impl std::fmt::Display for Hdf5Error {
91    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92        match self {
93            Self::Io(e) => write!(f, "I/O error: {}", e),
94            Self::Format(e) => write!(f, "format error: {}", e),
95            Self::IoLayer(e) => write!(f, "hdf5-io error: {}", e),
96            Self::NotFound(s) => write!(f, "dataset '{}' not found", s),
97            Self::InvalidState(s) => write!(f, "invalid state: {}", s),
98            Self::TypeMismatch(s) => write!(f, "type mismatch: {}", s),
99            Self::Unsupported(s) => write!(f, "unsupported: {}", s),
100            Self::DanglingLink { link, target } => write!(
101                f,
102                "link '{}' points to '{}', which does not exist",
103                link, target
104            ),
105            #[cfg(feature = "mmap")]
106            Self::NotViewable(reason) => {
107                write!(f, "the dataset cannot be viewed in place: {reason}")
108            }
109            Self::ExternalFileNotFound {
110                link,
111                file,
112                searched,
113            } => write!(
114                f,
115                "external link '{}' names the file '{}', which could not be opened (tried: {})",
116                link,
117                file,
118                searched.join(", ")
119            ),
120        }
121    }
122}
123
124impl std::error::Error for Hdf5Error {}
125
126/// A specialized `Result` type for HDF5 operations.
127pub type Result<T> = std::result::Result<T, Hdf5Error>;
128
129#[cfg(test)]
130mod tests {
131    use super::*;
132
133    #[test]
134    fn display_not_found() {
135        let err = Hdf5Error::NotFound("my_dataset".into());
136        assert!(format!("{}", err).contains("my_dataset"));
137    }
138
139    #[test]
140    fn display_invalid_state() {
141        let err = Hdf5Error::InvalidState("file already closed".into());
142        assert!(format!("{}", err).contains("file already closed"));
143    }
144
145    #[test]
146    fn display_type_mismatch() {
147        let err = Hdf5Error::TypeMismatch("expected f64, got u8".into());
148        assert!(format!("{}", err).contains("expected f64, got u8"));
149    }
150
151    #[test]
152    fn from_io_error() {
153        let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "gone");
154        let err: Hdf5Error = io_err.into();
155        match err {
156            Hdf5Error::Io(_) => {}
157            other => panic!("expected Io variant, got: {:?}", other),
158        }
159    }
160}