oxgraph_snapshot/container_error.rs
1//! Concrete error types for snapshot reading, viewing, and writing.
2//!
3//! Each error type implements [`Display`](core::fmt::Display) and
4//! [`core::error::Error`] without depending on `alloc`, `std`, or external
5//! error frameworks.
6
7use core::fmt;
8
9/// Snapshot container validation error.
10///
11/// Returned by [`Snapshot::open`](crate::Snapshot::open) and
12/// [`Snapshot::open_with`](crate::Snapshot::open_with) for any header,
13/// section table, or layout-level invariant violation.
14///
15/// # Performance
16///
17/// `perf: unspecified`; errors are returned only from validation paths.
18#[derive(Clone, Debug, Eq, PartialEq)]
19pub enum SnapshotError {
20 /// Snapshot bytes were shorter than the fixed header.
21 TruncatedHeader {
22 /// Bytes required for the fixed header.
23 needed: usize,
24 /// Bytes actually provided.
25 actual: usize,
26 },
27 /// Header bytes were present but could not be interpreted.
28 MalformedHeader,
29 /// Magic bytes did not match [`FORMAT_MAGIC`](crate::FORMAT_MAGIC).
30 BadMagic {
31 /// Actual magic bytes from the snapshot.
32 actual: [u8; 8],
33 },
34 /// Format major version did not equal the supported value.
35 FormatMajorMismatch {
36 /// Major version recorded in the snapshot.
37 actual: u32,
38 /// Major version this library supports.
39 supported: u32,
40 },
41 /// Format minor version was newer than this library can read.
42 FormatMinorTooNew {
43 /// Minor version recorded in the snapshot.
44 actual: u32,
45 /// Highest minor version this library accepts.
46 max_supported: u32,
47 },
48 /// Header `header_size` field did not match the expected value.
49 HeaderSizeMismatch {
50 /// `header_size` value recorded in the snapshot.
51 actual: u32,
52 /// Header size this library expects.
53 expected: u32,
54 },
55 /// Header reserved bytes were not all zero.
56 NonZeroHeaderReserved,
57 /// `section_count` exceeded the v1 cap.
58 SectionCountTooLarge {
59 /// Section count recorded in the snapshot.
60 count: u32,
61 /// Maximum permitted section count.
62 max: u32,
63 },
64 /// Bytes after the header were too short for the declared section table.
65 TruncatedSectionTable {
66 /// Bytes required for the declared section table.
67 needed: usize,
68 /// Bytes available after the header.
69 actual: usize,
70 },
71 /// Section table bytes could not be interpreted.
72 MalformedSectionTable,
73 /// A section entry's `reserved_checksum` bytes were not all zero.
74 NonZeroEntryChecksum {
75 /// Section kind whose entry violated the invariant.
76 kind: u32,
77 },
78 /// A section entry's trailing reserved bytes were not all zero.
79 NonZeroEntryReserved {
80 /// Section kind whose entry violated the invariant.
81 kind: u32,
82 },
83 /// A section entry declared an unsupported flags bit.
84 UnsupportedFlags {
85 /// Section kind whose entry violated the invariant.
86 kind: u32,
87 /// Flags byte recorded in the entry.
88 flags: u8,
89 },
90 /// A section entry declared an `alignment_log2` larger than permitted.
91 AlignmentLog2TooLarge {
92 /// Section kind whose entry violated the invariant.
93 kind: u32,
94 /// Declared `alignment_log2` value.
95 alignment_log2: u8,
96 },
97 /// `offset + length` overflowed `u64` for one entry.
98 SectionRangeOverflow {
99 /// Section kind whose entry violated the invariant.
100 kind: u32,
101 },
102 /// A section's byte range fell outside the snapshot.
103 SectionOutOfBounds {
104 /// Section kind whose entry violated the invariant.
105 kind: u32,
106 /// Declared byte offset.
107 offset: u64,
108 /// Declared byte length.
109 length: u64,
110 /// Total snapshot byte length.
111 snapshot_len: u64,
112 },
113 /// Section table entries were not in monotonic non-decreasing offset order
114 /// or one entry overlapped its predecessor.
115 UnsortedSectionTable {
116 /// Index of the entry whose offset violated monotonicity.
117 index: usize,
118 },
119 /// Two section entries shared the same kind.
120 DuplicateKind {
121 /// Duplicated section kind.
122 kind: u32,
123 },
124 /// A `u64` value could not be represented as `usize` on this target.
125 UsizeOverflow {
126 /// Value that could not be represented as `usize`.
127 value: u64,
128 },
129}
130
131impl fmt::Display for SnapshotError {
132 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
133 match self {
134 Self::TruncatedHeader { needed, actual } => write!(
135 formatter,
136 "snapshot header is truncated: needed {needed} bytes, got {actual}"
137 ),
138 Self::MalformedHeader => formatter.write_str("snapshot header is malformed"),
139 Self::BadMagic { actual } => write!(formatter, "bad snapshot magic: {actual:?}"),
140 Self::FormatMajorMismatch { actual, supported } => write!(
141 formatter,
142 "unsupported snapshot format major: snapshot is {actual}, this reader supports {supported}"
143 ),
144 Self::FormatMinorTooNew {
145 actual,
146 max_supported,
147 } => write!(
148 formatter,
149 "snapshot format minor {actual} is newer than this reader's maximum {max_supported}"
150 ),
151 Self::HeaderSizeMismatch { actual, expected } => write!(
152 formatter,
153 "header_size mismatch: snapshot reports {actual}, this reader expects {expected}"
154 ),
155 Self::NonZeroHeaderReserved => {
156 formatter.write_str("snapshot header reserved bytes are not all zero")
157 }
158 Self::SectionCountTooLarge { count, max } => {
159 write!(formatter, "section count {count} exceeds maximum {max}")
160 }
161 Self::TruncatedSectionTable { needed, actual } => write!(
162 formatter,
163 "section table is truncated: needed {needed} bytes, got {actual}"
164 ),
165 Self::MalformedSectionTable => formatter.write_str("section table bytes are malformed"),
166 Self::NonZeroEntryChecksum { kind } => write!(
167 formatter,
168 "section {kind} entry reserved checksum bytes are not all zero"
169 ),
170 Self::NonZeroEntryReserved { kind } => write!(
171 formatter,
172 "section {kind} entry trailing reserved bytes are not all zero"
173 ),
174 Self::UnsupportedFlags { kind, flags } => write!(
175 formatter,
176 "section {kind} entry has unsupported flags byte {flags:#04x}"
177 ),
178 Self::AlignmentLog2TooLarge {
179 kind,
180 alignment_log2,
181 } => write!(
182 formatter,
183 "section {kind} alignment_log2 {alignment_log2} exceeds maximum"
184 ),
185 Self::SectionRangeOverflow { kind } => {
186 write!(formatter, "section {kind} offset + length overflows u64")
187 }
188 Self::SectionOutOfBounds {
189 kind,
190 offset,
191 length,
192 snapshot_len,
193 } => write!(
194 formatter,
195 "section {kind} is out of bounds: offset {offset}, length {length}, snapshot length {snapshot_len}"
196 ),
197 Self::UnsortedSectionTable { index } => write!(
198 formatter,
199 "section table entry at index {index} is unsorted or overlaps its predecessor"
200 ),
201 Self::DuplicateKind { kind } => write!(formatter, "duplicate section kind {kind}"),
202 Self::UsizeOverflow { value } => {
203 write!(formatter, "u64 value {value} does not fit usize")
204 }
205 }
206 }
207}
208
209impl core::error::Error for SnapshotError {}
210
211/// Error returned when borrowing a section payload as a typed slice fails.
212///
213/// # Performance
214///
215/// `perf: unspecified`; errors are returned only from typed-view paths.
216#[derive(Clone, Copy, Debug, Eq, PartialEq)]
217pub enum SectionViewError {
218 /// The requested element type is zero-sized, so it cannot tile a payload.
219 ZeroSizedType,
220 /// Payload byte length is not an exact multiple of `size_of::<T>()`.
221 LengthNotMultipleOfSize {
222 /// Section payload length in bytes.
223 length: usize,
224 /// `core::mem::size_of::<T>()` for the requested element type.
225 elem_size: usize,
226 },
227 /// Payload base address does not satisfy `align_of::<T>()`.
228 AlignmentMismatch {
229 /// Address of the payload's first byte.
230 ptr_addr: usize,
231 /// `core::mem::align_of::<T>()` for the requested element type.
232 required: usize,
233 },
234}
235
236impl fmt::Display for SectionViewError {
237 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
238 match self {
239 Self::ZeroSizedType => {
240 formatter.write_str("cannot borrow a section payload as a zero-sized type")
241 }
242 Self::LengthNotMultipleOfSize { length, elem_size } => write!(
243 formatter,
244 "section length {length} is not a multiple of element size {elem_size}"
245 ),
246 Self::AlignmentMismatch { ptr_addr, required } => write!(
247 formatter,
248 "section payload at address {ptr_addr:#x} is not aligned to {required}"
249 ),
250 }
251 }
252}
253
254impl core::error::Error for SectionViewError {}
255
256/// Error returned when binding a width-typed section by kind and version.
257///
258/// Returned by [`Snapshot::typed_section`](crate::Snapshot::typed_section): a
259/// single error covering the lookup, version check, and typed-view steps that
260/// every layout crate previously open-coded with its own variants.
261///
262/// # Performance
263///
264/// `perf: unspecified`; errors are returned only from section-binding paths.
265#[derive(Clone, Copy, Debug, Eq, PartialEq)]
266pub enum SectionBindError {
267 /// No section with the requested kind was present.
268 Missing {
269 /// Requested section kind.
270 kind: u32,
271 },
272 /// The section was present but its version did not match.
273 VersionMismatch {
274 /// Requested section kind.
275 kind: u32,
276 /// Version the caller required.
277 expected: u32,
278 /// Version recorded in the section entry.
279 actual: u32,
280 },
281 /// The payload could not be borrowed as the requested little-endian word.
282 View {
283 /// Requested section kind.
284 kind: u32,
285 /// Underlying typed-view failure.
286 error: SectionViewError,
287 },
288}
289
290impl fmt::Display for SectionBindError {
291 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
292 match self {
293 Self::Missing { kind } => write!(formatter, "snapshot section {kind} is missing"),
294 Self::VersionMismatch {
295 kind,
296 expected,
297 actual,
298 } => write!(
299 formatter,
300 "snapshot section {kind} version {actual} does not match expected {expected}"
301 ),
302 Self::View { kind, error } => {
303 write!(
304 formatter,
305 "snapshot section {kind} typed view failed: {error}"
306 )
307 }
308 }
309 }
310}
311
312impl core::error::Error for SectionBindError {}
313
314/// Error returned by snapshot writers.
315///
316/// Returned by [`SnapshotPlan::new`](crate::SnapshotPlan::new),
317/// [`SnapshotPlan::write_into`](crate::SnapshotPlan::write_into), and the
318/// alloc-gated [`SnapshotBuilder`](crate::SnapshotBuilder) methods.
319///
320/// # Performance
321///
322/// `perf: unspecified`; errors are returned only from writer paths.
323#[derive(Clone, Copy, Debug, Eq, PartialEq)]
324pub enum PlanError {
325 /// The output buffer is smaller than the snapshot's encoded length.
326 BufferTooSmall {
327 /// Bytes required by the encoded snapshot.
328 needed: usize,
329 /// Bytes provided in the output buffer.
330 actual: usize,
331 },
332 /// A section's `alignment_log2` exceeds [`MAX_ALIGNMENT_LOG2`](crate::MAX_ALIGNMENT_LOG2).
333 AlignmentTooLarge {
334 /// Declared `alignment_log2` value.
335 alignment_log2: u8,
336 },
337 /// Computed offsets or lengths overflowed `u64` or `usize`.
338 PayloadOverflow,
339 /// More sections were supplied than the v1 cap permits.
340 TooManySections {
341 /// Section count actually supplied.
342 count: usize,
343 },
344 /// Two pending sections shared the same kind.
345 DuplicateKind {
346 /// Duplicated section kind.
347 kind: u32,
348 },
349}
350
351impl fmt::Display for PlanError {
352 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
353 match self {
354 Self::BufferTooSmall { needed, actual } => write!(
355 formatter,
356 "output buffer too small: needed {needed} bytes, got {actual}"
357 ),
358 Self::AlignmentTooLarge { alignment_log2 } => write!(
359 formatter,
360 "alignment_log2 {alignment_log2} exceeds the v1 maximum"
361 ),
362 Self::PayloadOverflow => {
363 formatter.write_str("snapshot payload arithmetic overflowed u64 or usize")
364 }
365 Self::TooManySections { count } => {
366 write!(formatter, "section count {count} exceeds the v1 maximum")
367 }
368 Self::DuplicateKind { kind } => write!(formatter, "duplicate section kind {kind}"),
369 }
370 }
371}
372
373impl core::error::Error for PlanError {}