Skip to main content

hdf5_pure/
error.rs

1//! Error types for HDF5 format parsing.
2
3#[cfg(not(feature = "std"))]
4extern crate alloc;
5
6#[cfg(not(feature = "std"))]
7use alloc::string::String;
8
9#[cfg(feature = "std")]
10use std::string::String;
11
12use core::fmt;
13
14/// Errors that can occur when parsing HDF5 binary format structures.
15#[derive(Debug, Clone, PartialEq, Eq)]
16#[non_exhaustive]
17pub enum FormatError {
18    /// The HDF5 magic signature was not found at any valid offset.
19    SignatureNotFound,
20    /// The superblock version is not supported.
21    UnsupportedVersion(u8),
22    /// Unexpected end of data.
23    UnexpectedEof {
24        /// Number of bytes expected.
25        expected: usize,
26        /// Number of bytes actually available.
27        available: usize,
28    },
29    /// Invalid offset size (must be 2, 4, or 8).
30    InvalidOffsetSize(u8),
31    /// Invalid length size (must be 2, 4, or 8).
32    InvalidLengthSize(u8),
33    /// Invalid object header signature.
34    InvalidObjectHeaderSignature,
35    /// Invalid object header version.
36    InvalidObjectHeaderVersion(u8),
37    /// Unknown message type that is marked as must-understand.
38    UnsupportedMessage(u16),
39    /// Invalid datatype class.
40    InvalidDatatypeClass(u8),
41    /// Invalid datatype version for a given class.
42    InvalidDatatypeVersion {
43        /// The type class.
44        class: u8,
45        /// The version found.
46        version: u8,
47    },
48    /// Invalid string padding type.
49    InvalidStringPadding(u8),
50    /// Invalid character set.
51    InvalidCharacterSet(u8),
52    /// Invalid byte order.
53    InvalidByteOrder(u8),
54    /// Invalid reference type.
55    InvalidReferenceType(u8),
56    /// Invalid file-space management strategy code in a File Space Info message.
57    InvalidFileSpaceStrategy(u8),
58    /// Unsupported File Space Info message version (only version 1 is handled).
59    UnsupportedFileSpaceInfoVersion(u8),
60    /// A free-space manager block (`FSHD`/`FSSE`) is malformed.
61    InvalidFreeSpaceManager,
62    /// A compound datatype has a zero total size.
63    InvalidCompoundSize,
64    /// A compound datatype contains no fields.
65    EmptyCompoundType,
66    /// A compound datatype contains the same field name more than once.
67    DuplicateCompoundField(String),
68    /// A compound field extends past the declared compound size.
69    CompoundFieldOutOfBounds {
70        /// Field name.
71        name: String,
72        /// Field byte offset.
73        offset: u64,
74        /// Field size in bytes.
75        field_size: u32,
76        /// Declared compound size in bytes.
77        compound_size: u32,
78    },
79    /// Two compound fields overlap.
80    CompoundFieldOverlap {
81        /// Earlier field in byte order.
82        first: String,
83        /// Later field in byte order.
84        second: String,
85    },
86    /// A named compound field was not present.
87    CompoundFieldMissing(String),
88    /// A compound field has an incompatible datatype.
89    CompoundFieldTypeMismatch(String),
90    /// Invalid dataspace version.
91    InvalidDataspaceVersion(u8),
92    /// Invalid dataspace type.
93    InvalidDataspaceType(u8),
94    /// Invalid data layout version.
95    InvalidLayoutVersion(u8),
96    /// Invalid data layout class.
97    InvalidLayoutClass(u8),
98    /// No data allocated for contiguous layout.
99    NoDataAllocated,
100    /// Type mismatch when reading data.
101    TypeMismatch {
102        /// Expected type description.
103        expected: &'static str,
104        /// Actual type description.
105        actual: &'static str,
106    },
107    /// Data size mismatch.
108    DataSizeMismatch {
109        /// Expected size in bytes.
110        expected: usize,
111        /// Actual size in bytes.
112        actual: usize,
113    },
114    /// Invalid local heap signature.
115    InvalidLocalHeapSignature,
116    /// Invalid local heap version.
117    InvalidLocalHeapVersion(u8),
118    /// Invalid B-tree v1 signature.
119    InvalidBTreeSignature,
120    /// Invalid B-tree node type.
121    InvalidBTreeNodeType(u8),
122    /// Invalid symbol table node signature.
123    InvalidSymbolTableNodeSignature,
124    /// Invalid symbol table node version.
125    InvalidSymbolTableNodeVersion(u8),
126    /// Path not found during group traversal.
127    PathNotFound(String),
128    /// Invalid Link message version.
129    InvalidLinkVersion(u8),
130    /// Invalid link type code.
131    InvalidLinkType(u8),
132    /// Invalid Link Info message version.
133    InvalidLinkInfoVersion(u8),
134    /// Invalid B-tree v2 signature.
135    InvalidBTreeV2Signature,
136    /// Invalid B-tree v2 version.
137    InvalidBTreeV2Version(u8),
138    /// Invalid fractal heap signature.
139    InvalidFractalHeapSignature,
140    /// Invalid fractal heap version.
141    InvalidFractalHeapVersion(u8),
142    /// Invalid heap ID type.
143    InvalidHeapIdType(u8),
144    /// A fractal-heap "huge" object's heap ID referenced a B-tree key that is
145    /// not present in the heap's huge-objects v2 B-tree.
146    HugeObjectNotFound(u64),
147    /// A fractal-heap object lives in an I/O-filter-encoded heap (filtered
148    /// managed or huge storage), whose filtered bytes this reader does not
149    /// decode. Link and attribute heaps are never filtered, so this does not
150    /// arise for them.
151    UnsupportedFilteredHeapObject,
152    /// A dataset uses the Virtual (VDS) data layout, which maps its elements to
153    /// regions of other datasets, possibly in other files. This reader does not
154    /// yet resolve virtual mappings, so such a dataset is refused rather than
155    /// read as empty or wrong.
156    UnsupportedVirtualLayout,
157    /// Invalid attribute message version.
158    InvalidAttributeVersion(u8),
159    /// Invalid Attribute Info message version.
160    InvalidAttributeInfoVersion(u8),
161    /// Invalid shared message version.
162    InvalidSharedMessageVersion(u8),
163    /// Invalid global heap collection signature.
164    InvalidGlobalHeapSignature,
165    /// Invalid global heap version.
166    InvalidGlobalHeapVersion(u8),
167    /// Global heap object not found.
168    GlobalHeapObjectNotFound {
169        /// Address of the collection.
170        collection_address: u64,
171        /// Index that was not found.
172        index: u16,
173    },
174    /// Variable-length data error.
175    VlDataError(String),
176    /// A variable-length read exceeded its configured element limit.
177    VariableLengthElementLimitExceeded {
178        /// Maximum number of elements permitted by the caller.
179        limit: usize,
180        /// Number of elements present in the selected data.
181        actual: u64,
182    },
183    /// A variable-length read exceeded its configured payload-byte limit.
184    VariableLengthByteLimitExceeded {
185        /// Maximum number of payload bytes permitted by the caller.
186        limit: usize,
187        /// Number of payload bytes required by the selected data.
188        required: u64,
189    },
190    /// Serialization error.
191    SerializationError(String),
192    /// Dataset is missing data.
193    DatasetMissingData,
194    /// Dataset is missing shape.
195    DatasetMissingShape,
196    /// A variable-length string dataset was requested with chunked, filtered,
197    /// or resizable storage. VL element references live in the global heap,
198    /// whose addresses are only known after data layout, so they cannot be
199    /// patched into compressed chunks written beforehand.
200    ChunkedVlenStringUnsupported,
201    /// The dataset's element count implied by its shape does not match the
202    /// amount of data supplied (`shape.product() * element_size != data.len()`).
203    ShapeDataMismatch {
204        /// Number of data bytes the shape requires (`product(shape) * element_size`).
205        expected: usize,
206        /// Number of data bytes actually supplied.
207        actual: usize,
208        /// Size in bytes of one element (the dataset's datatype size). Always
209        /// non-zero; used to report the mismatch in elements as well as bytes.
210        element_size: usize,
211    },
212    /// A chunked/filtered/extensible dataset's chunk geometry is invalid — for
213    /// example chunk dimensions whose rank disagrees with the shape, a zero chunk
214    /// dimension, a maximum shape whose rank disagrees with the shape or that is
215    /// smaller than the current shape, or chunking requested on a scalar dataset.
216    /// Reported up front so a malformed request is refused instead of panicking
217    /// in the chunk splitter or producing an unreadable dataset. The payload is a
218    /// human-readable reason.
219    InvalidChunkGeometry(&'static str),
220    /// Invalid filter pipeline version.
221    InvalidFilterPipelineVersion(u8),
222    /// Unsupported filter ID.
223    UnsupportedFilter(u16),
224    /// Filter processing error.
225    FilterError(String),
226    /// Decompression error.
227    DecompressionError(String),
228    /// Compression error.
229    CompressionError(String),
230    /// Fletcher32 checksum mismatch.
231    Fletcher32Mismatch {
232        /// Expected checksum.
233        expected: u32,
234        /// Computed checksum.
235        computed: u32,
236    },
237    /// Chunked dataset read error.
238    ChunkedReadError(String),
239    /// Chunk assembly error.
240    ChunkAssemblyError(String),
241    /// CRC32C checksum mismatch.
242    ChecksumMismatch {
243        /// The checksum stored in the file.
244        expected: u32,
245        /// The checksum we computed.
246        computed: u32,
247    },
248    /// Maximum nesting/continuation depth exceeded (malformed data protection).
249    NestingDepthExceeded,
250    /// Duplicate dataset name detected during parallel metadata merge.
251    DuplicateDatasetName(String),
252    /// ZFP filter configuration is invalid (e.g. missing element type, rank out of range).
253    UnsupportedZfp(String),
254    /// A file-derived 64-bit value (an offset, length, size, or element count)
255    /// does not fit in the target integer type on this platform. This is the
256    /// guard that replaces silent `as usize` / `as u32` truncation: on a 32-bit
257    /// host, `usize` is 32 bits, so an HDF5 offset or length above `usize::MAX`
258    /// would otherwise wrap and read the wrong bytes. The original value is
259    /// preserved for diagnostics, and `target` names the type we tried to
260    /// narrow to (e.g. `"usize"`, `"u32"`).
261    ValueTooLargeForPlatform {
262        /// The original 64-bit value read from the file.
263        value: u64,
264        /// The platform integer type the value could not fit into.
265        target: &'static str,
266    },
267    /// Two file-derived values (typically an offset and a length) overflow `u64`
268    /// when added to form a slice bound. Reported instead of wrapping so a
269    /// malformed file cannot produce a wrapped or out-of-range index.
270    OffsetOverflow {
271        /// First operand (typically the base offset/address).
272        offset: u64,
273        /// Second operand (typically the length/size).
274        length: u64,
275    },
276    /// A random-access byte source (see [`crate::source::FileSource`]) failed to
277    /// supply the requested bytes. The string carries a backend-specific reason
278    /// (e.g. an underlying `std::io::Error` rendered to text), so this stays
279    /// `no_std`/`alloc`-friendly and free of an `std::io` dependency.
280    Source(String),
281    /// The library-version bounds requested via
282    /// [`FileBuilder::with_libver_bounds`](crate::FileBuilder::with_libver_bounds)
283    /// cannot be satisfied. This crate's writer emits exactly one on-disk format
284    /// (the version 3 / HDF5 1.10 superblock), so a bound that excludes it — an
285    /// upper bound older than 1.10, or a lower bound newer than 1.10 — is
286    /// unsatisfiable. The fields carry the format produced and the bounds asked
287    /// for, as [`LibVer::name`](crate::LibVer::name) labels.
288    LibverBoundsUnsatisfiable {
289        /// The library-version label of the format this crate writes.
290        writes: &'static str,
291        /// The requested lower bound.
292        requested_low: &'static str,
293        /// The requested upper bound.
294        requested_high: &'static str,
295    },
296    /// An HDF5 object reference (`H5R_OBJECT`) could not be resolved to an
297    /// object: the stored address is null or undefined (`HADDR_UNDEF`), or it
298    /// does not point at a group or dataset object header. The payload is the
299    /// stored (base-relative) address, preserved for diagnostics.
300    InvalidObjectReference(u64),
301}
302
303impl fmt::Display for FormatError {
304    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305        match self {
306            FormatError::SignatureNotFound => {
307                write!(f, "HDF5 signature not found at any valid offset")
308            }
309            FormatError::UnsupportedVersion(v) => {
310                write!(f, "unsupported superblock version: {v}")
311            }
312            FormatError::UnexpectedEof {
313                expected,
314                available,
315            } => {
316                write!(f, "unexpected EOF: need {expected} bytes, have {available}")
317            }
318            FormatError::InvalidOffsetSize(s) => {
319                write!(f, "invalid offset size: {s} (must be 2, 4, or 8)")
320            }
321            FormatError::InvalidLengthSize(s) => {
322                write!(f, "invalid length size: {s} (must be 2, 4, or 8)")
323            }
324            FormatError::InvalidObjectHeaderSignature => {
325                write!(f, "invalid object header signature")
326            }
327            FormatError::InvalidObjectHeaderVersion(v) => {
328                write!(f, "invalid object header version: {v}")
329            }
330            FormatError::UnsupportedMessage(id) => {
331                write!(
332                    f,
333                    "unsupported message type {id:#06x} marked as must-understand"
334                )
335            }
336            FormatError::InvalidDatatypeClass(c) => {
337                write!(f, "invalid datatype class: {c}")
338            }
339            FormatError::InvalidDatatypeVersion { class, version } => {
340                write!(f, "invalid datatype version {version} for class {class}")
341            }
342            FormatError::InvalidStringPadding(p) => {
343                write!(f, "invalid string padding type: {p}")
344            }
345            FormatError::InvalidCharacterSet(c) => {
346                write!(f, "invalid character set: {c}")
347            }
348            FormatError::InvalidByteOrder(b) => {
349                write!(f, "invalid byte order: {b}")
350            }
351            FormatError::InvalidReferenceType(r) => {
352                write!(f, "invalid reference type: {r}")
353            }
354            FormatError::InvalidFileSpaceStrategy(s) => {
355                write!(f, "invalid file-space strategy code: {s}")
356            }
357            FormatError::UnsupportedFileSpaceInfoVersion(v) => {
358                write!(f, "unsupported File Space Info message version: {v}")
359            }
360            FormatError::InvalidFreeSpaceManager => {
361                write!(f, "malformed free-space manager block (FSHD/FSSE)")
362            }
363            FormatError::InvalidCompoundSize => {
364                write!(f, "compound datatype size must be greater than zero")
365            }
366            FormatError::EmptyCompoundType => {
367                write!(f, "compound datatype must contain at least one field")
368            }
369            FormatError::DuplicateCompoundField(name) => {
370                write!(f, "duplicate compound field name: {name}")
371            }
372            FormatError::CompoundFieldOutOfBounds {
373                name,
374                offset,
375                field_size,
376                compound_size,
377            } => {
378                write!(
379                    f,
380                    "compound field {name:?} at offset {offset} with size {field_size} \
381                     exceeds compound size {compound_size}"
382                )
383            }
384            FormatError::CompoundFieldOverlap { first, second } => {
385                write!(f, "compound fields {first:?} and {second:?} overlap")
386            }
387            FormatError::CompoundFieldMissing(name) => {
388                write!(f, "compound field {name:?} is missing")
389            }
390            FormatError::CompoundFieldTypeMismatch(name) => {
391                write!(f, "compound field {name:?} has an incompatible datatype")
392            }
393            FormatError::InvalidDataspaceVersion(v) => {
394                write!(f, "invalid dataspace version: {v}")
395            }
396            FormatError::InvalidDataspaceType(t) => {
397                write!(f, "invalid dataspace type: {t}")
398            }
399            FormatError::InvalidLayoutVersion(v) => {
400                write!(f, "invalid data layout version: {v}")
401            }
402            FormatError::InvalidLayoutClass(c) => {
403                write!(f, "invalid data layout class: {c}")
404            }
405            FormatError::NoDataAllocated => {
406                write!(f, "no data allocated for contiguous layout")
407            }
408            FormatError::TypeMismatch { expected, actual } => {
409                write!(f, "type mismatch: expected {expected}, got {actual}")
410            }
411            FormatError::DataSizeMismatch { expected, actual } => {
412                write!(
413                    f,
414                    "data size mismatch: expected {expected} bytes, got {actual} bytes"
415                )
416            }
417            FormatError::InvalidLocalHeapSignature => {
418                write!(f, "invalid local heap signature")
419            }
420            FormatError::InvalidLocalHeapVersion(v) => {
421                write!(f, "invalid local heap version: {v}")
422            }
423            FormatError::InvalidBTreeSignature => {
424                write!(f, "invalid B-tree v1 signature")
425            }
426            FormatError::InvalidBTreeNodeType(t) => {
427                write!(f, "invalid B-tree node type: {t}")
428            }
429            FormatError::InvalidSymbolTableNodeSignature => {
430                write!(f, "invalid symbol table node signature")
431            }
432            FormatError::InvalidSymbolTableNodeVersion(v) => {
433                write!(f, "invalid symbol table node version: {v}")
434            }
435            FormatError::PathNotFound(p) => {
436                write!(f, "path not found: {p}")
437            }
438            FormatError::InvalidLinkVersion(v) => {
439                write!(f, "invalid link message version: {v}")
440            }
441            FormatError::InvalidLinkType(t) => {
442                write!(f, "invalid link type: {t}")
443            }
444            FormatError::InvalidLinkInfoVersion(v) => {
445                write!(f, "invalid link info message version: {v}")
446            }
447            FormatError::InvalidBTreeV2Signature => {
448                write!(f, "invalid B-tree v2 signature")
449            }
450            FormatError::InvalidBTreeV2Version(v) => {
451                write!(f, "invalid B-tree v2 version: {v}")
452            }
453            FormatError::InvalidFractalHeapSignature => {
454                write!(f, "invalid fractal heap signature")
455            }
456            FormatError::InvalidFractalHeapVersion(v) => {
457                write!(f, "invalid fractal heap version: {v}")
458            }
459            FormatError::InvalidHeapIdType(t) => {
460                write!(f, "invalid heap ID type: {t}")
461            }
462            FormatError::HugeObjectNotFound(id) => {
463                write!(f, "fractal-heap huge object {id} not found in B-tree")
464            }
465            FormatError::UnsupportedFilteredHeapObject => {
466                write!(f, "filtered fractal-heap objects are not supported")
467            }
468            FormatError::UnsupportedVirtualLayout => {
469                write!(f, "virtual (VDS) data layout is not supported")
470            }
471            FormatError::InvalidAttributeVersion(v) => {
472                write!(f, "invalid attribute message version: {v}")
473            }
474            FormatError::InvalidAttributeInfoVersion(v) => {
475                write!(f, "invalid attribute info message version: {v}")
476            }
477            FormatError::InvalidSharedMessageVersion(v) => {
478                write!(f, "invalid shared message version: {v}")
479            }
480            FormatError::InvalidGlobalHeapSignature => {
481                write!(f, "invalid global heap collection signature")
482            }
483            FormatError::InvalidGlobalHeapVersion(v) => {
484                write!(f, "invalid global heap version: {v}")
485            }
486            FormatError::GlobalHeapObjectNotFound {
487                collection_address,
488                index,
489            } => {
490                write!(
491                    f,
492                    "global heap object not found: collection {collection_address:#x}, index {index}"
493                )
494            }
495            FormatError::VlDataError(msg) => {
496                write!(f, "variable-length data error: {msg}")
497            }
498            FormatError::VariableLengthElementLimitExceeded { limit, actual } => {
499                write!(
500                    f,
501                    "variable-length element limit exceeded: limit is {limit}, data contains {actual}"
502                )
503            }
504            FormatError::VariableLengthByteLimitExceeded { limit, required } => {
505                write!(
506                    f,
507                    "variable-length payload limit exceeded: limit is {limit} bytes, \
508                     data requires {required} bytes"
509                )
510            }
511            FormatError::SerializationError(msg) => {
512                write!(f, "serialization error: {msg}")
513            }
514            FormatError::DatasetMissingData => {
515                write!(f, "dataset is missing data")
516            }
517            FormatError::DatasetMissingShape => {
518                write!(f, "dataset is missing shape")
519            }
520            FormatError::ChunkedVlenStringUnsupported => {
521                write!(
522                    f,
523                    "chunked, filtered, or resizable variable-length string datasets cannot be written"
524                )
525            }
526            FormatError::ShapeDataMismatch {
527                expected,
528                actual,
529                element_size,
530            } => {
531                // `element_size` is guaranteed non-zero at construction, so the
532                // element counts below are well defined.
533                write!(
534                    f,
535                    "shape/data mismatch: shape requires {} elements ({expected} bytes), \
536                     but {} elements ({actual} bytes) were supplied",
537                    expected / element_size,
538                    actual / element_size,
539                )
540            }
541            FormatError::InvalidChunkGeometry(reason) => {
542                write!(f, "invalid chunk geometry: {reason}")
543            }
544            FormatError::InvalidFilterPipelineVersion(v) => {
545                write!(f, "invalid filter pipeline version: {v}")
546            }
547            FormatError::UnsupportedFilter(id) => {
548                write!(f, "unsupported filter: {id}")
549            }
550            FormatError::FilterError(msg) => {
551                write!(f, "filter error: {msg}")
552            }
553            FormatError::DecompressionError(msg) => {
554                write!(f, "decompression error: {msg}")
555            }
556            FormatError::CompressionError(msg) => {
557                write!(f, "compression error: {msg}")
558            }
559            FormatError::Fletcher32Mismatch { expected, computed } => {
560                write!(
561                    f,
562                    "fletcher32 mismatch: expected {expected:#010x}, computed {computed:#010x}"
563                )
564            }
565            FormatError::ChunkedReadError(msg) => {
566                write!(f, "chunked read error: {msg}")
567            }
568            FormatError::ChunkAssemblyError(msg) => {
569                write!(f, "chunk assembly error: {msg}")
570            }
571            FormatError::ChecksumMismatch { expected, computed } => {
572                write!(
573                    f,
574                    "checksum mismatch: expected {expected:#010x}, computed {computed:#010x}"
575                )
576            }
577            FormatError::NestingDepthExceeded => {
578                write!(f, "maximum nesting/continuation depth exceeded")
579            }
580            FormatError::DuplicateDatasetName(name) => {
581                write!(f, "duplicate dataset name during parallel merge: {name}")
582            }
583            FormatError::UnsupportedZfp(msg) => {
584                write!(f, "unsupported ZFP configuration: {msg}")
585            }
586            FormatError::ValueTooLargeForPlatform { value, target } => {
587                write!(
588                    f,
589                    "file value {value} does not fit in {target} on this platform \
590                     (a 64-bit HDF5 offset/length exceeds this target's address width)"
591                )
592            }
593            FormatError::OffsetOverflow { offset, length } => {
594                write!(
595                    f,
596                    "offset arithmetic overflow: {offset} + {length} exceeds u64"
597                )
598            }
599            FormatError::Source(msg) => {
600                write!(f, "byte source error: {msg}")
601            }
602            FormatError::LibverBoundsUnsatisfiable {
603                writes,
604                requested_low,
605                requested_high,
606            } => {
607                write!(
608                    f,
609                    "requested library-version bounds [{requested_low}, {requested_high}] \
610                     cannot be satisfied: this crate writes the {writes} format"
611                )
612            }
613            FormatError::InvalidObjectReference(addr) => {
614                write!(
615                    f,
616                    "invalid HDF5 object reference: address {addr:#x} is null/undefined \
617                     or does not point at a group or dataset"
618                )
619            }
620        }
621    }
622}
623
624#[cfg(feature = "std")]
625impl std::error::Error for FormatError {}
626
627// ---------------------------------------------------------------------------
628// High-level Error type
629// ---------------------------------------------------------------------------
630
631/// Errors that can occur when using the high-level API.
632#[cfg(feature = "std")]
633#[derive(Debug)]
634#[non_exhaustive]
635pub enum Error {
636    /// I/O error from the filesystem.
637    Io(std::io::Error),
638    /// Low-level format parsing error.
639    Format(FormatError),
640    /// The object at the given path is not a dataset.
641    NotADataset(String),
642    /// A required header message was not found.
643    MissingMessage(crate::message_type::MessageType),
644    /// Alignment or size error for zero-copy typed access.
645    AlignmentError(String),
646    /// An array shape error from the `ndarray` integration: either the flat
647    /// data could not be reshaped to the dataset's dimensions, or a requested
648    /// static rank (e.g. `read_array::<_, Ix2>`) did not match the dataset's
649    /// runtime rank. Only constructed when the `ndarray` feature is enabled.
650    Shape(String),
651    /// A SWMR operation (e.g. [`crate::File::refresh`]) was requested on a file
652    /// that was not opened for SWMR reading via `File::open_swmr`.
653    SwmrUnsupported,
654    /// The file or dataset is not a supported target for the SWMR append writer
655    /// (e.g. a userblock or non-latest-format file, or a dataset that is
656    /// filtered, not rank-1 with an unlimited dimension, or not
657    /// Extensible-Array indexed). The payload is a human-readable reason.
658    SwmrAppendUnsupported(&'static str),
659    /// The file or the requested object is not a supported target for the
660    /// in-place editor ([`crate::EditSession`]) — for example a userblock or
661    /// non-latest-format file, a group whose links are densely stored, or a
662    /// dataset shape/datatype/filter combination the in-place writer cannot
663    /// emit yet. The payload is a human-readable reason.
664    EditUnsupported(&'static str),
665    /// An object in the source file cannot be reproduced faithfully by
666    /// [`repack`](crate::repack), so the repack was refused rather than write a
667    /// silently degraded file — for example a variable-length, time, bitfield,
668    /// or opaque datatype, a virtual/external data layout, an unsupported
669    /// filter, or an object reference. The payload names the object and reason.
670    RepackUnsupported(String),
671    /// The file could not be opened because another process holds a conflicting
672    /// OS advisory lock — for a writer ([`crate::SwmrWriter`],
673    /// [`crate::EditSession`]) this means another writer or reader is active;
674    /// for a plain reader it means a writer is active. The lock is released
675    /// automatically when the holder's process exits, so a crashed writer does
676    /// not leave a stale lock. Locking can be disabled per open with
677    /// [`crate::FileLocking::Disabled`] or globally with
678    /// `HDF5_USE_FILE_LOCKING=FALSE`. The payload is a human-readable reason.
679    FileLocked(String),
680}
681
682#[cfg(feature = "std")]
683impl fmt::Display for Error {
684    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
685        match self {
686            Error::Io(e) => write!(f, "I/O error: {e}"),
687            Error::Format(e) => write!(f, "HDF5 format error: {e}"),
688            Error::NotADataset(path) => write!(f, "not a dataset: {path}"),
689            Error::MissingMessage(mt) => write!(f, "missing required message: {mt:?}"),
690            Error::AlignmentError(msg) => write!(f, "alignment error: {msg}"),
691            Error::Shape(msg) => write!(f, "array shape error: {msg}"),
692            Error::SwmrUnsupported => write!(
693                f,
694                "refresh requires a file opened with File::open_swmr (live handle)"
695            ),
696            Error::SwmrAppendUnsupported(reason) => {
697                write!(f, "unsupported SWMR append target: {reason}")
698            }
699            Error::EditUnsupported(reason) => {
700                write!(f, "unsupported in-place edit target: {reason}")
701            }
702            Error::RepackUnsupported(reason) => {
703                write!(f, "cannot repack faithfully: {reason}")
704            }
705            Error::FileLocked(reason) => write!(f, "file is locked: {reason}"),
706        }
707    }
708}
709
710#[cfg(feature = "std")]
711impl std::error::Error for Error {
712    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
713        match self {
714            Error::Io(e) => Some(e),
715            Error::Format(e) => Some(e),
716            _ => None,
717        }
718    }
719}
720
721#[cfg(feature = "std")]
722impl From<FormatError> for Error {
723    fn from(e: FormatError) -> Self {
724        Error::Format(e)
725    }
726}
727
728#[cfg(feature = "std")]
729impl From<std::io::Error> for Error {
730    fn from(e: std::io::Error) -> Self {
731        Error::Io(e)
732    }
733}