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