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
55impl From<crate::io::IoError> for Hdf5Error {
56    fn from(e: crate::io::IoError) -> Self {
57        // Every outcome that names *why* a lookup failed carries through as
58        // itself so a caller can match on it; everything else keeps its
59        // existing shape. `NotFound` is among them: a `?` on an I/O-layer
60        // lookup must not turn a plain absence into an opaque `IoLayer`,
61        // which is what forced callers to re-map it by hand.
62        match e {
63            crate::io::IoError::NotFound(s) => Self::NotFound(s),
64            crate::io::IoError::Unsupported(s) => Self::Unsupported(s),
65            crate::io::IoError::DanglingLink { link, target } => {
66                Self::DanglingLink { link, target }
67            }
68            crate::io::IoError::ExternalFileNotFound {
69                link,
70                file,
71                searched,
72            } => Self::ExternalFileNotFound {
73                link,
74                file,
75                searched,
76            },
77            other => Self::IoLayer(other),
78        }
79    }
80}
81
82impl std::fmt::Display for Hdf5Error {
83    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84        match self {
85            Self::Io(e) => write!(f, "I/O error: {}", e),
86            Self::Format(e) => write!(f, "format error: {}", e),
87            Self::IoLayer(e) => write!(f, "hdf5-io error: {}", e),
88            Self::NotFound(s) => write!(f, "dataset '{}' not found", s),
89            Self::InvalidState(s) => write!(f, "invalid state: {}", s),
90            Self::TypeMismatch(s) => write!(f, "type mismatch: {}", s),
91            Self::Unsupported(s) => write!(f, "unsupported: {}", s),
92            Self::DanglingLink { link, target } => write!(
93                f,
94                "link '{}' points to '{}', which does not exist",
95                link, target
96            ),
97            #[cfg(feature = "mmap")]
98            Self::NotViewable(reason) => {
99                write!(f, "the dataset cannot be viewed in place: {reason}")
100            }
101            Self::ExternalFileNotFound {
102                link,
103                file,
104                searched,
105            } => write!(
106                f,
107                "external link '{}' names the file '{}', which could not be opened (tried: {})",
108                link,
109                file,
110                searched.join(", ")
111            ),
112        }
113    }
114}
115
116impl std::error::Error for Hdf5Error {}
117
118/// A specialized `Result` type for HDF5 operations.
119pub type Result<T> = std::result::Result<T, Hdf5Error>;
120
121#[cfg(test)]
122mod tests {
123    use super::*;
124
125    #[test]
126    fn display_not_found() {
127        let err = Hdf5Error::NotFound("my_dataset".into());
128        assert!(format!("{}", err).contains("my_dataset"));
129    }
130
131    #[test]
132    fn display_invalid_state() {
133        let err = Hdf5Error::InvalidState("file already closed".into());
134        assert!(format!("{}", err).contains("file already closed"));
135    }
136
137    #[test]
138    fn display_type_mismatch() {
139        let err = Hdf5Error::TypeMismatch("expected f64, got u8".into());
140        assert!(format!("{}", err).contains("expected f64, got u8"));
141    }
142
143    #[test]
144    fn from_io_error() {
145        let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "gone");
146        let err: Hdf5Error = io_err.into();
147        match err {
148            Hdf5Error::Io(_) => {}
149            other => panic!("expected Io variant, got: {:?}", other),
150        }
151    }
152}