1#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10#[repr(u16)]
11pub enum ErrorCode {
12 Ok = 0x0000,
15 OkPartial = 0x0001,
17
18 InvalidMagic = 0x0100,
21 InvalidVersion = 0x0101,
23 InvalidChecksum = 0x0102,
25 InvalidSignature = 0x0103,
27 TruncatedSegment = 0x0104,
29 InvalidManifest = 0x0105,
31 ManifestNotFound = 0x0106,
33 UnknownSegmentType = 0x0107,
35 AlignmentError = 0x0108,
37
38 DimensionMismatch = 0x0200,
41 EmptyIndex = 0x0201,
43 MetricUnsupported = 0x0202,
45 FilterParseError = 0x0203,
47 KTooLarge = 0x0204,
49 Timeout = 0x0205,
51
52 LockHeld = 0x0300,
55 LockStale = 0x0301,
57 DiskFull = 0x0302,
59 FsyncFailed = 0x0303,
61 SegmentTooLarge = 0x0304,
63 ReadOnly = 0x0305,
65
66 TileTrap = 0x0400,
69 TileOom = 0x0401,
71 TileTimeout = 0x0402,
73 TileInvalidMsg = 0x0403,
75 TileUnsupportedOp = 0x0404,
77
78 KeyNotFound = 0x0500,
81 KeyExpired = 0x0501,
83 DecryptFailed = 0x0502,
85 AlgoUnsupported = 0x0503,
87 AttestationInvalid = 0x0504,
89 PlatformUnsupported = 0x0505,
91 AttestationExpired = 0x0506,
93 KeyNotBound = 0x0507,
95
96 ParentNotFound = 0x0600,
99 ParentHashMismatch = 0x0601,
101 LineageBroken = 0x0602,
103 LineageCyclic = 0x0603,
105
106 CowMapCorrupt = 0x0700,
109 ClusterNotFound = 0x0701,
111 ParentChainBroken = 0x0702,
113 DeltaThresholdExceeded = 0x0703,
115 SnapshotFrozen = 0x0704,
117 MembershipInvalid = 0x0705,
119 GenerationStale = 0x0706,
121 KernelBindingMismatch = 0x0707,
123 DoubleRootCorrupt = 0x0708,
125}
126
127impl ErrorCode {
128 #[inline]
130 pub const fn category(self) -> u8 {
131 (self as u16 >> 8) as u8
132 }
133
134 #[inline]
136 pub const fn is_success(self) -> bool {
137 self.category() == 0x00
138 }
139
140 #[inline]
142 pub const fn is_format_error(self) -> bool {
143 self.category() == 0x01
144 }
145}
146
147impl TryFrom<u16> for ErrorCode {
148 type Error = u16;
149
150 fn try_from(value: u16) -> Result<Self, Self::Error> {
151 match value {
152 0x0000 => Ok(Self::Ok),
153 0x0001 => Ok(Self::OkPartial),
154
155 0x0100 => Ok(Self::InvalidMagic),
156 0x0101 => Ok(Self::InvalidVersion),
157 0x0102 => Ok(Self::InvalidChecksum),
158 0x0103 => Ok(Self::InvalidSignature),
159 0x0104 => Ok(Self::TruncatedSegment),
160 0x0105 => Ok(Self::InvalidManifest),
161 0x0106 => Ok(Self::ManifestNotFound),
162 0x0107 => Ok(Self::UnknownSegmentType),
163 0x0108 => Ok(Self::AlignmentError),
164
165 0x0200 => Ok(Self::DimensionMismatch),
166 0x0201 => Ok(Self::EmptyIndex),
167 0x0202 => Ok(Self::MetricUnsupported),
168 0x0203 => Ok(Self::FilterParseError),
169 0x0204 => Ok(Self::KTooLarge),
170 0x0205 => Ok(Self::Timeout),
171
172 0x0300 => Ok(Self::LockHeld),
173 0x0301 => Ok(Self::LockStale),
174 0x0302 => Ok(Self::DiskFull),
175 0x0303 => Ok(Self::FsyncFailed),
176 0x0304 => Ok(Self::SegmentTooLarge),
177 0x0305 => Ok(Self::ReadOnly),
178
179 0x0400 => Ok(Self::TileTrap),
180 0x0401 => Ok(Self::TileOom),
181 0x0402 => Ok(Self::TileTimeout),
182 0x0403 => Ok(Self::TileInvalidMsg),
183 0x0404 => Ok(Self::TileUnsupportedOp),
184
185 0x0500 => Ok(Self::KeyNotFound),
186 0x0501 => Ok(Self::KeyExpired),
187 0x0502 => Ok(Self::DecryptFailed),
188 0x0503 => Ok(Self::AlgoUnsupported),
189 0x0504 => Ok(Self::AttestationInvalid),
190 0x0505 => Ok(Self::PlatformUnsupported),
191 0x0506 => Ok(Self::AttestationExpired),
192 0x0507 => Ok(Self::KeyNotBound),
193
194 0x0600 => Ok(Self::ParentNotFound),
195 0x0601 => Ok(Self::ParentHashMismatch),
196 0x0602 => Ok(Self::LineageBroken),
197 0x0603 => Ok(Self::LineageCyclic),
198
199 0x0700 => Ok(Self::CowMapCorrupt),
200 0x0701 => Ok(Self::ClusterNotFound),
201 0x0702 => Ok(Self::ParentChainBroken),
202 0x0703 => Ok(Self::DeltaThresholdExceeded),
203 0x0704 => Ok(Self::SnapshotFrozen),
204 0x0705 => Ok(Self::MembershipInvalid),
205 0x0706 => Ok(Self::GenerationStale),
206 0x0707 => Ok(Self::KernelBindingMismatch),
207 0x0708 => Ok(Self::DoubleRootCorrupt),
208
209 other => Err(other),
210 }
211 }
212}
213
214#[derive(Clone, Debug, PartialEq, Eq)]
216#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
217pub enum RvfError {
218 Code(ErrorCode),
220 UnknownCode(u16),
222 BadMagic { expected: u32, got: u32 },
224 SizeMismatch { expected: usize, got: usize },
226 InvalidEnumValue {
228 type_name: &'static str,
229 value: u64,
230 },
231}
232
233impl core::fmt::Display for RvfError {
234 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
235 match self {
236 Self::Code(c) => write!(f, "RVF error code 0x{:04X}", *c as u16),
237 Self::UnknownCode(v) => write!(f, "unknown RVF error code 0x{v:04X}"),
238 Self::BadMagic { expected, got } => {
239 write!(f, "bad magic: expected 0x{expected:08X}, got 0x{got:08X}")
240 }
241 Self::SizeMismatch { expected, got } => {
242 write!(f, "size mismatch: expected {expected}, got {got}")
243 }
244 Self::InvalidEnumValue { type_name, value } => {
245 write!(f, "invalid {type_name} value: {value}")
246 }
247 }
248 }
249}
250
251#[cfg(test)]
252mod tests {
253 use super::*;
254 use alloc::format;
255
256 #[test]
257 fn error_code_round_trip_all() {
258 let codes: &[(u16, ErrorCode)] = &[
259 (0x0000, ErrorCode::Ok),
260 (0x0001, ErrorCode::OkPartial),
261 (0x0100, ErrorCode::InvalidMagic),
262 (0x0101, ErrorCode::InvalidVersion),
263 (0x0102, ErrorCode::InvalidChecksum),
264 (0x0103, ErrorCode::InvalidSignature),
265 (0x0104, ErrorCode::TruncatedSegment),
266 (0x0105, ErrorCode::InvalidManifest),
267 (0x0106, ErrorCode::ManifestNotFound),
268 (0x0107, ErrorCode::UnknownSegmentType),
269 (0x0108, ErrorCode::AlignmentError),
270 (0x0200, ErrorCode::DimensionMismatch),
271 (0x0201, ErrorCode::EmptyIndex),
272 (0x0202, ErrorCode::MetricUnsupported),
273 (0x0203, ErrorCode::FilterParseError),
274 (0x0204, ErrorCode::KTooLarge),
275 (0x0205, ErrorCode::Timeout),
276 (0x0300, ErrorCode::LockHeld),
277 (0x0301, ErrorCode::LockStale),
278 (0x0302, ErrorCode::DiskFull),
279 (0x0303, ErrorCode::FsyncFailed),
280 (0x0304, ErrorCode::SegmentTooLarge),
281 (0x0305, ErrorCode::ReadOnly),
282 (0x0400, ErrorCode::TileTrap),
283 (0x0401, ErrorCode::TileOom),
284 (0x0402, ErrorCode::TileTimeout),
285 (0x0403, ErrorCode::TileInvalidMsg),
286 (0x0404, ErrorCode::TileUnsupportedOp),
287 (0x0500, ErrorCode::KeyNotFound),
288 (0x0501, ErrorCode::KeyExpired),
289 (0x0502, ErrorCode::DecryptFailed),
290 (0x0503, ErrorCode::AlgoUnsupported),
291 (0x0504, ErrorCode::AttestationInvalid),
292 (0x0505, ErrorCode::PlatformUnsupported),
293 (0x0506, ErrorCode::AttestationExpired),
294 (0x0507, ErrorCode::KeyNotBound),
295 (0x0600, ErrorCode::ParentNotFound),
296 (0x0601, ErrorCode::ParentHashMismatch),
297 (0x0602, ErrorCode::LineageBroken),
298 (0x0603, ErrorCode::LineageCyclic),
299 (0x0700, ErrorCode::CowMapCorrupt),
300 (0x0701, ErrorCode::ClusterNotFound),
301 (0x0702, ErrorCode::ParentChainBroken),
302 (0x0703, ErrorCode::DeltaThresholdExceeded),
303 (0x0704, ErrorCode::SnapshotFrozen),
304 (0x0705, ErrorCode::MembershipInvalid),
305 (0x0706, ErrorCode::GenerationStale),
306 (0x0707, ErrorCode::KernelBindingMismatch),
307 (0x0708, ErrorCode::DoubleRootCorrupt),
308 ];
309 for &(raw, expected) in codes {
310 assert_eq!(ErrorCode::try_from(raw), Ok(expected), "code 0x{raw:04X}");
311 assert_eq!(expected as u16, raw);
312 }
313 }
314
315 #[test]
316 fn unknown_code() {
317 assert_eq!(ErrorCode::try_from(0x9999), Err(0x9999));
318 }
319
320 #[test]
321 fn category_extraction() {
322 assert_eq!(ErrorCode::Ok.category(), 0x00);
323 assert_eq!(ErrorCode::InvalidMagic.category(), 0x01);
324 assert_eq!(ErrorCode::DimensionMismatch.category(), 0x02);
325 assert_eq!(ErrorCode::LockHeld.category(), 0x03);
326 assert_eq!(ErrorCode::TileTrap.category(), 0x04);
327 assert_eq!(ErrorCode::KeyNotFound.category(), 0x05);
328 assert_eq!(ErrorCode::ParentNotFound.category(), 0x06);
329 assert_eq!(ErrorCode::CowMapCorrupt.category(), 0x07);
330 }
331
332 #[test]
333 fn success_check() {
334 assert!(ErrorCode::Ok.is_success());
335 assert!(ErrorCode::OkPartial.is_success());
336 assert!(!ErrorCode::InvalidMagic.is_success());
337 }
338
339 #[test]
340 fn format_error_check() {
341 assert!(ErrorCode::InvalidMagic.is_format_error());
342 assert!(!ErrorCode::Ok.is_format_error());
343 assert!(!ErrorCode::DimensionMismatch.is_format_error());
344 }
345
346 #[test]
347 fn rvf_error_display() {
348 let e = RvfError::BadMagic {
349 expected: 0x52564653,
350 got: 0x00000000,
351 };
352 let s = format!("{e}");
353 assert!(s.contains("bad magic"));
354 assert!(s.contains("52564653"));
355 }
356
357 #[test]
358 fn cow_error_check() {
359 assert_eq!(ErrorCode::CowMapCorrupt as u16, 0x0700);
360 assert_eq!(ErrorCode::ClusterNotFound as u16, 0x0701);
361 assert_eq!(ErrorCode::ParentChainBroken as u16, 0x0702);
362 assert_eq!(ErrorCode::DeltaThresholdExceeded as u16, 0x0703);
363 assert_eq!(ErrorCode::SnapshotFrozen as u16, 0x0704);
364 assert_eq!(ErrorCode::MembershipInvalid as u16, 0x0705);
365 assert_eq!(ErrorCode::GenerationStale as u16, 0x0706);
366 assert_eq!(ErrorCode::KernelBindingMismatch as u16, 0x0707);
367 assert_eq!(ErrorCode::DoubleRootCorrupt as u16, 0x0708);
368 assert_eq!(ErrorCode::CowMapCorrupt.category(), 0x07);
370 assert_eq!(ErrorCode::DoubleRootCorrupt.category(), 0x07);
371 }
372
373 #[test]
374 fn error_codes_match_spec() {
375 assert_eq!(ErrorCode::InvalidMagic as u16, 0x0100);
376 assert_eq!(ErrorCode::InvalidChecksum as u16, 0x0102);
377 assert_eq!(ErrorCode::ManifestNotFound as u16, 0x0106);
378 assert_eq!(ErrorCode::AlgoUnsupported as u16, 0x0503);
379 }
380}