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 /// Payload byte length is not an exact multiple of `size_of::<T>()`.
219 LengthNotMultipleOfSize {
220 /// Section payload length in bytes.
221 length: usize,
222 /// `core::mem::size_of::<T>()` for the requested element type.
223 elem_size: usize,
224 },
225 /// Payload base address does not satisfy `align_of::<T>()`.
226 AlignmentMismatch {
227 /// Address of the payload's first byte.
228 ptr_addr: usize,
229 /// `core::mem::align_of::<T>()` for the requested element type.
230 required: usize,
231 },
232}
233
234impl fmt::Display for SectionViewError {
235 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
236 match self {
237 Self::LengthNotMultipleOfSize { length, elem_size } => write!(
238 formatter,
239 "section length {length} is not a multiple of element size {elem_size}"
240 ),
241 Self::AlignmentMismatch { ptr_addr, required } => write!(
242 formatter,
243 "section payload at address {ptr_addr:#x} is not aligned to {required}"
244 ),
245 }
246 }
247}
248
249impl core::error::Error for SectionViewError {}
250
251/// Error returned by snapshot writers.
252///
253/// Returned by [`SnapshotPlan::new`](crate::SnapshotPlan::new),
254/// [`SnapshotPlan::write_into`](crate::SnapshotPlan::write_into), and the
255/// alloc-gated [`SnapshotBuilder`](crate::SnapshotBuilder) methods.
256///
257/// # Performance
258///
259/// `perf: unspecified`; errors are returned only from writer paths.
260#[derive(Clone, Copy, Debug, Eq, PartialEq)]
261pub enum PlanError {
262 /// The output buffer is smaller than the snapshot's encoded length.
263 BufferTooSmall {
264 /// Bytes required by the encoded snapshot.
265 needed: usize,
266 /// Bytes provided in the output buffer.
267 actual: usize,
268 },
269 /// A section's `alignment_log2` exceeds [`MAX_ALIGNMENT_LOG2`](crate::MAX_ALIGNMENT_LOG2).
270 AlignmentTooLarge {
271 /// Declared `alignment_log2` value.
272 alignment_log2: u8,
273 },
274 /// Computed offsets or lengths overflowed `u64` or `usize`.
275 PayloadOverflow,
276 /// More sections were supplied than the v1 cap permits.
277 TooManySections {
278 /// Section count actually supplied.
279 count: usize,
280 },
281 /// Two pending sections shared the same kind.
282 DuplicateKind {
283 /// Duplicated section kind.
284 kind: u32,
285 },
286}
287
288impl fmt::Display for PlanError {
289 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
290 match self {
291 Self::BufferTooSmall { needed, actual } => write!(
292 formatter,
293 "output buffer too small: needed {needed} bytes, got {actual}"
294 ),
295 Self::AlignmentTooLarge { alignment_log2 } => write!(
296 formatter,
297 "alignment_log2 {alignment_log2} exceeds the v1 maximum"
298 ),
299 Self::PayloadOverflow => {
300 formatter.write_str("snapshot payload arithmetic overflowed u64 or usize")
301 }
302 Self::TooManySections { count } => {
303 write!(formatter, "section count {count} exceeds the v1 maximum")
304 }
305 Self::DuplicateKind { kind } => write!(formatter, "duplicate section kind {kind}"),
306 }
307 }
308}
309
310impl core::error::Error for PlanError {}