Skip to main content

hurray_io/
error.rs

1/// Crate-level error type for `hurray-io`.
2#[derive(Debug, thiserror::Error)]
3#[non_exhaustive]
4pub enum Error {
5    /// An I/O error from the underlying stream or file.
6    #[error("I/O error: {0}")]
7    Io(#[from] std::io::Error),
8
9    /// A core format error.
10    #[error("format error: {0}")]
11    Core(#[from] hurray_core::Error),
12
13    /// The stream ended before a complete record was read.
14    #[error("unexpected end of stream")]
15    UnexpectedEof,
16
17    /// A frame or record header is malformed.
18    #[error("invalid frame header: {0}")]
19    InvalidHeader(String),
20
21    /// The number of supplied buffer slices does not match the descriptor's buffer table.
22    #[error("buffer count mismatch: descriptor declares {declared}, got {actual}")]
23    MultiBufferLengthMismatch { declared: usize, actual: usize },
24
25    /// A supplied buffer's byte length does not match the corresponding handle's `byte_size`.
26    #[error("buffer[{index}] size mismatch: declared {declared}, got {actual}")]
27    BufferSizeMismatch {
28        index: usize,
29        declared: u64,
30        actual: u64,
31    },
32
33    /// A descriptor or buffer exceeded the configured size limit.
34    #[error("frame too large: {kind} = {value}, limit = {limit}")]
35    FrameTooLarge {
36        kind: &'static str,
37        value: u64,
38        limit: u64,
39    },
40
41    /// A buffer handle's `sync_mode` is invalid for a cross-machine transport.
42    #[error(
43        "buffer[{index}] sync_mode 0x{actual:02X} is invalid for cross-machine transport \
44         (must be 0x00 ProducerSynced)"
45    )]
46    InvalidCrossMachineSyncMode { index: usize, actual: u8 },
47
48    /// A buffer handle's declared size and alignment do not form an allocatable layout on
49    /// this host (a `byte_size` beyond the address space, or a non-power-of-two alignment).
50    #[error(
51        "buffer[{index}]: {byte_size} bytes at alignment {alignment} is not an allocatable \
52         layout on this host"
53    )]
54    UnallocatableBuffer {
55        index: usize,
56        byte_size: u64,
57        alignment: u32,
58    },
59
60    /// A composite head's members were truncated: the stream ended before the head's
61    /// declared `member_count` members had been read.
62    #[error("torn composite: head declares {declared} member(s), stream ended after {actual}")]
63    TornComposite { declared: u32, actual: u32 },
64
65    /// Composite nesting exceeded the configured maximum depth. Guards against stack
66    /// exhaustion from a maliciously deep composite on an untrusted stream.
67    #[error("composite nesting too deep: exceeded limit of {limit}")]
68    CompositeNestingTooDeep { limit: usize },
69
70    /// A composite read was requested for a tensor whose head is not a composite.
71    #[error("tensor {0:?} is not a composite head")]
72    NotAComposite(String),
73
74    // ── Sans-io core (ADR-041 §§ 4, 6) ────────────────────────────────────────
75    /// The core was marked unusable: a transport moved bytes whose count was lost, so the
76    /// core's position no longer matches the transport's.
77    #[error("stream core is unusable: {0}")]
78    CoreUnusable(crate::stream::Unusable),
79
80    /// A previous call returned an error and this core cannot continue. Distinct from
81    /// [`Error::CoreUnusable`]: the position is known, the stream is simply over.
82    #[error("stream core failed earlier and cannot continue")]
83    CoreFailed,
84
85    /// A driver reported more bytes than the core offered it.
86    #[error("invalid progress report: {reported} byte(s) reported, {offered} offered")]
87    InvalidProgressReport { reported: usize, offered: usize },
88
89    /// A driver reported a zero-length write, which is never progress.
90    #[error("zero-length write is not progress")]
91    ZeroLengthWrite,
92
93    /// The sink was closed while an item was in flight, so a truncated item is on the
94    /// wire. The core and the sink are both poisoned.
95    #[error("sink closed mid-item: the item on the wire is truncated")]
96    SinkClosed,
97
98    /// A tensor or footer was submitted to a file writer core before its header.
99    #[error("the file header has not been written; drive FileWriterCore::header first")]
100    HeaderNotWritten,
101
102    // ── File format ───────────────────────────────────────────────────────────
103    /// The file header magic is not `HRRYFILE`.
104    #[error("invalid file magic: expected HRRYFILE")]
105    InvalidFileMagic,
106
107    /// The trailer magic is not `HRRY`.
108    #[error("invalid trailer magic")]
109    InvalidTrailerMagic,
110
111    /// The container major version is higher than this reader supports.
112    #[error("unsupported container version {major}.x (reader supports 1.x)")]
113    UnsupportedContainerVersion { major: u8 },
114
115    /// A tensor name was requested but is not in the file index.
116    #[error("tensor not found: {0:?}")]
117    TensorNotFound(String),
118
119    /// Two tensors in the same file share a name.
120    #[error("duplicate tensor name: {0:?}")]
121    DuplicateTensorName(String),
122
123    /// A tensor name is empty.
124    #[error("tensor name must not be empty")]
125    TensorNameEmpty,
126
127    /// A tensor name exceeds the 65 535-byte `uint16` limit.
128    #[error("tensor name too long: {len} bytes (max 65535)")]
129    TensorNameTooLong { len: usize },
130
131    /// The index CRC-32C does not match the stored value.
132    #[error("index CRC-32C mismatch: stored 0x{stored:08X}, computed 0x{computed:08X}")]
133    IndexCrc32cMismatch { stored: u32, computed: u32 },
134
135    /// Two KV entries share the same key.
136    #[error("duplicate KV key: {0:?}")]
137    DuplicateKvKey(String),
138
139    /// A KV key is empty.
140    #[error("KV key must not be empty")]
141    KvKeyEmpty,
142
143    /// A KV key exceeds the 65 535-byte `uint16` limit.
144    #[error("KV key too long: {len} bytes (max 65535)")]
145    KvKeyTooLong { len: usize },
146
147    /// A reserved flag bit was set in the file header.
148    #[error("file header has reserved flag bits set: 0x{flags:08X}")]
149    ReservedFileFlagBits { flags: u32 },
150
151    /// The index section overlaps the trailer.
152    #[error("index section overruns trailer boundary")]
153    IndexOverrunsTrailer,
154}
155
156/// Convenience alias for `Result` with [`Error`].
157pub type Result<T> = std::result::Result<T, Error>;