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 UnsignedManifest = 0x0800,
109 ContentHashMismatch = 0x0801,
111 UnknownSigner = 0x0802,
113 EpochDriftExceeded = 0x0803,
115 Level1InvalidSignature = 0x0804,
117
118 QualityBelowThreshold = 0x0900,
121 BudgetTokensExhausted = 0x0901,
123 QueryBlacklisted = 0x0902,
125
126 CowMapCorrupt = 0x0700,
129 ClusterNotFound = 0x0701,
131 ParentChainBroken = 0x0702,
133 DeltaThresholdExceeded = 0x0703,
135 SnapshotFrozen = 0x0704,
137 MembershipInvalid = 0x0705,
139 GenerationStale = 0x0706,
141 KernelBindingMismatch = 0x0707,
143 DoubleRootCorrupt = 0x0708,
145}
146
147impl ErrorCode {
148 #[inline]
150 pub const fn category(self) -> u8 {
151 (self as u16 >> 8) as u8
152 }
153
154 #[inline]
156 pub const fn is_success(self) -> bool {
157 self.category() == 0x00
158 }
159
160 #[inline]
162 pub const fn is_format_error(self) -> bool {
163 self.category() == 0x01
164 }
165
166 #[inline]
168 pub const fn is_security_error(self) -> bool {
169 self.category() == 0x08
170 }
171
172 #[inline]
174 pub const fn is_quality_error(self) -> bool {
175 self.category() == 0x09
176 }
177}
178
179impl TryFrom<u16> for ErrorCode {
180 type Error = u16;
181
182 fn try_from(value: u16) -> Result<Self, Self::Error> {
183 match value {
184 0x0000 => Ok(Self::Ok),
185 0x0001 => Ok(Self::OkPartial),
186
187 0x0100 => Ok(Self::InvalidMagic),
188 0x0101 => Ok(Self::InvalidVersion),
189 0x0102 => Ok(Self::InvalidChecksum),
190 0x0103 => Ok(Self::InvalidSignature),
191 0x0104 => Ok(Self::TruncatedSegment),
192 0x0105 => Ok(Self::InvalidManifest),
193 0x0106 => Ok(Self::ManifestNotFound),
194 0x0107 => Ok(Self::UnknownSegmentType),
195 0x0108 => Ok(Self::AlignmentError),
196
197 0x0200 => Ok(Self::DimensionMismatch),
198 0x0201 => Ok(Self::EmptyIndex),
199 0x0202 => Ok(Self::MetricUnsupported),
200 0x0203 => Ok(Self::FilterParseError),
201 0x0204 => Ok(Self::KTooLarge),
202 0x0205 => Ok(Self::Timeout),
203
204 0x0300 => Ok(Self::LockHeld),
205 0x0301 => Ok(Self::LockStale),
206 0x0302 => Ok(Self::DiskFull),
207 0x0303 => Ok(Self::FsyncFailed),
208 0x0304 => Ok(Self::SegmentTooLarge),
209 0x0305 => Ok(Self::ReadOnly),
210
211 0x0400 => Ok(Self::TileTrap),
212 0x0401 => Ok(Self::TileOom),
213 0x0402 => Ok(Self::TileTimeout),
214 0x0403 => Ok(Self::TileInvalidMsg),
215 0x0404 => Ok(Self::TileUnsupportedOp),
216
217 0x0500 => Ok(Self::KeyNotFound),
218 0x0501 => Ok(Self::KeyExpired),
219 0x0502 => Ok(Self::DecryptFailed),
220 0x0503 => Ok(Self::AlgoUnsupported),
221 0x0504 => Ok(Self::AttestationInvalid),
222 0x0505 => Ok(Self::PlatformUnsupported),
223 0x0506 => Ok(Self::AttestationExpired),
224 0x0507 => Ok(Self::KeyNotBound),
225
226 0x0600 => Ok(Self::ParentNotFound),
227 0x0601 => Ok(Self::ParentHashMismatch),
228 0x0602 => Ok(Self::LineageBroken),
229 0x0603 => Ok(Self::LineageCyclic),
230
231 0x0800 => Ok(Self::UnsignedManifest),
232 0x0801 => Ok(Self::ContentHashMismatch),
233 0x0802 => Ok(Self::UnknownSigner),
234 0x0803 => Ok(Self::EpochDriftExceeded),
235 0x0804 => Ok(Self::Level1InvalidSignature),
236
237 0x0900 => Ok(Self::QualityBelowThreshold),
238 0x0901 => Ok(Self::BudgetTokensExhausted),
239 0x0902 => Ok(Self::QueryBlacklisted),
240
241 0x0700 => Ok(Self::CowMapCorrupt),
242 0x0701 => Ok(Self::ClusterNotFound),
243 0x0702 => Ok(Self::ParentChainBroken),
244 0x0703 => Ok(Self::DeltaThresholdExceeded),
245 0x0704 => Ok(Self::SnapshotFrozen),
246 0x0705 => Ok(Self::MembershipInvalid),
247 0x0706 => Ok(Self::GenerationStale),
248 0x0707 => Ok(Self::KernelBindingMismatch),
249 0x0708 => Ok(Self::DoubleRootCorrupt),
250
251 other => Err(other),
252 }
253 }
254}
255
256#[derive(Clone, Debug, PartialEq, Eq)]
258#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
259pub enum RvfError {
260 Code(ErrorCode),
262 UnknownCode(u16),
264 BadMagic { expected: u32, got: u32 },
266 SizeMismatch { expected: usize, got: usize },
268 InvalidEnumValue {
270 type_name: &'static str,
271 value: u64,
272 },
273 Security(crate::security::SecurityError),
275 QualityBelowThreshold {
278 quality: crate::quality::ResponseQuality,
279 reason: &'static str,
280 },
281}
282
283impl core::fmt::Display for RvfError {
284 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
285 match self {
286 Self::Code(c) => write!(f, "RVF error code 0x{:04X}", *c as u16),
287 Self::UnknownCode(v) => write!(f, "unknown RVF error code 0x{v:04X}"),
288 Self::BadMagic { expected, got } => {
289 write!(f, "bad magic: expected 0x{expected:08X}, got 0x{got:08X}")
290 }
291 Self::SizeMismatch { expected, got } => {
292 write!(f, "size mismatch: expected {expected}, got {got}")
293 }
294 Self::InvalidEnumValue { type_name, value } => {
295 write!(f, "invalid {type_name} value: {value}")
296 }
297 Self::Security(e) => write!(f, "security error: {e}"),
298 Self::QualityBelowThreshold { quality, reason } => {
299 write!(f, "quality below threshold ({quality:?}): {reason}")
300 }
301 }
302 }
303}
304
305#[cfg(test)]
306mod tests {
307 use super::*;
308 use alloc::format;
309
310 #[test]
311 fn error_code_round_trip_all() {
312 let codes: &[(u16, ErrorCode)] = &[
313 (0x0000, ErrorCode::Ok),
314 (0x0001, ErrorCode::OkPartial),
315 (0x0100, ErrorCode::InvalidMagic),
316 (0x0101, ErrorCode::InvalidVersion),
317 (0x0102, ErrorCode::InvalidChecksum),
318 (0x0103, ErrorCode::InvalidSignature),
319 (0x0104, ErrorCode::TruncatedSegment),
320 (0x0105, ErrorCode::InvalidManifest),
321 (0x0106, ErrorCode::ManifestNotFound),
322 (0x0107, ErrorCode::UnknownSegmentType),
323 (0x0108, ErrorCode::AlignmentError),
324 (0x0200, ErrorCode::DimensionMismatch),
325 (0x0201, ErrorCode::EmptyIndex),
326 (0x0202, ErrorCode::MetricUnsupported),
327 (0x0203, ErrorCode::FilterParseError),
328 (0x0204, ErrorCode::KTooLarge),
329 (0x0205, ErrorCode::Timeout),
330 (0x0300, ErrorCode::LockHeld),
331 (0x0301, ErrorCode::LockStale),
332 (0x0302, ErrorCode::DiskFull),
333 (0x0303, ErrorCode::FsyncFailed),
334 (0x0304, ErrorCode::SegmentTooLarge),
335 (0x0305, ErrorCode::ReadOnly),
336 (0x0400, ErrorCode::TileTrap),
337 (0x0401, ErrorCode::TileOom),
338 (0x0402, ErrorCode::TileTimeout),
339 (0x0403, ErrorCode::TileInvalidMsg),
340 (0x0404, ErrorCode::TileUnsupportedOp),
341 (0x0500, ErrorCode::KeyNotFound),
342 (0x0501, ErrorCode::KeyExpired),
343 (0x0502, ErrorCode::DecryptFailed),
344 (0x0503, ErrorCode::AlgoUnsupported),
345 (0x0504, ErrorCode::AttestationInvalid),
346 (0x0505, ErrorCode::PlatformUnsupported),
347 (0x0506, ErrorCode::AttestationExpired),
348 (0x0507, ErrorCode::KeyNotBound),
349 (0x0600, ErrorCode::ParentNotFound),
350 (0x0601, ErrorCode::ParentHashMismatch),
351 (0x0602, ErrorCode::LineageBroken),
352 (0x0603, ErrorCode::LineageCyclic),
353 (0x0800, ErrorCode::UnsignedManifest),
354 (0x0801, ErrorCode::ContentHashMismatch),
355 (0x0802, ErrorCode::UnknownSigner),
356 (0x0803, ErrorCode::EpochDriftExceeded),
357 (0x0804, ErrorCode::Level1InvalidSignature),
358 (0x0900, ErrorCode::QualityBelowThreshold),
359 (0x0901, ErrorCode::BudgetTokensExhausted),
360 (0x0902, ErrorCode::QueryBlacklisted),
361 (0x0700, ErrorCode::CowMapCorrupt),
362 (0x0701, ErrorCode::ClusterNotFound),
363 (0x0702, ErrorCode::ParentChainBroken),
364 (0x0703, ErrorCode::DeltaThresholdExceeded),
365 (0x0704, ErrorCode::SnapshotFrozen),
366 (0x0705, ErrorCode::MembershipInvalid),
367 (0x0706, ErrorCode::GenerationStale),
368 (0x0707, ErrorCode::KernelBindingMismatch),
369 (0x0708, ErrorCode::DoubleRootCorrupt),
370 ];
371 for &(raw, expected) in codes {
372 assert_eq!(ErrorCode::try_from(raw), Ok(expected), "code 0x{raw:04X}");
373 assert_eq!(expected as u16, raw);
374 }
375 }
376
377 #[test]
378 fn unknown_code() {
379 assert_eq!(ErrorCode::try_from(0x9999), Err(0x9999));
380 }
381
382 #[test]
383 fn category_extraction() {
384 assert_eq!(ErrorCode::Ok.category(), 0x00);
385 assert_eq!(ErrorCode::InvalidMagic.category(), 0x01);
386 assert_eq!(ErrorCode::DimensionMismatch.category(), 0x02);
387 assert_eq!(ErrorCode::LockHeld.category(), 0x03);
388 assert_eq!(ErrorCode::TileTrap.category(), 0x04);
389 assert_eq!(ErrorCode::KeyNotFound.category(), 0x05);
390 assert_eq!(ErrorCode::ParentNotFound.category(), 0x06);
391 assert_eq!(ErrorCode::CowMapCorrupt.category(), 0x07);
392 assert_eq!(ErrorCode::UnsignedManifest.category(), 0x08);
393 assert_eq!(ErrorCode::QualityBelowThreshold.category(), 0x09);
394 }
395
396 #[test]
397 fn security_error_check() {
398 assert!(ErrorCode::UnsignedManifest.is_security_error());
399 assert!(!ErrorCode::Ok.is_security_error());
400 }
401
402 #[test]
403 fn quality_error_check() {
404 assert!(ErrorCode::QualityBelowThreshold.is_quality_error());
405 assert!(!ErrorCode::Ok.is_quality_error());
406 }
407
408 #[test]
409 fn success_check() {
410 assert!(ErrorCode::Ok.is_success());
411 assert!(ErrorCode::OkPartial.is_success());
412 assert!(!ErrorCode::InvalidMagic.is_success());
413 }
414
415 #[test]
416 fn format_error_check() {
417 assert!(ErrorCode::InvalidMagic.is_format_error());
418 assert!(!ErrorCode::Ok.is_format_error());
419 assert!(!ErrorCode::DimensionMismatch.is_format_error());
420 }
421
422 #[test]
423 fn rvf_error_display() {
424 let e = RvfError::BadMagic {
425 expected: 0x52564653,
426 got: 0x00000000,
427 };
428 let s = format!("{e}");
429 assert!(s.contains("bad magic"));
430 assert!(s.contains("52564653"));
431 }
432
433 #[test]
434 fn cow_error_check() {
435 assert_eq!(ErrorCode::CowMapCorrupt as u16, 0x0700);
436 assert_eq!(ErrorCode::ClusterNotFound as u16, 0x0701);
437 assert_eq!(ErrorCode::ParentChainBroken as u16, 0x0702);
438 assert_eq!(ErrorCode::DeltaThresholdExceeded as u16, 0x0703);
439 assert_eq!(ErrorCode::SnapshotFrozen as u16, 0x0704);
440 assert_eq!(ErrorCode::MembershipInvalid as u16, 0x0705);
441 assert_eq!(ErrorCode::GenerationStale as u16, 0x0706);
442 assert_eq!(ErrorCode::KernelBindingMismatch as u16, 0x0707);
443 assert_eq!(ErrorCode::DoubleRootCorrupt as u16, 0x0708);
444 assert_eq!(ErrorCode::CowMapCorrupt.category(), 0x07);
446 assert_eq!(ErrorCode::DoubleRootCorrupt.category(), 0x07);
447 }
448
449 #[test]
450 fn error_codes_match_spec() {
451 assert_eq!(ErrorCode::InvalidMagic as u16, 0x0100);
452 assert_eq!(ErrorCode::InvalidChecksum as u16, 0x0102);
453 assert_eq!(ErrorCode::ManifestNotFound as u16, 0x0106);
454 assert_eq!(ErrorCode::AlgoUnsupported as u16, 0x0503);
455 }
456}