Skip to main content

par2_rs/
error.rs

1use thiserror::Error;
2
3/// Errors that can occur during PAR2 parsing, verification, and repair.
4#[derive(Debug, Error)]
5pub enum Par2Error {
6    // --- Parsing errors ---
7    #[error("invalid magic sequence at offset {offset}")]
8    InvalidMagic { offset: u64 },
9
10    #[error("packet too short: expected at least {expected} bytes, got {actual}")]
11    PacketTooShort { expected: u64, actual: u64 },
12
13    #[error("packet length {length} not a multiple of 4")]
14    InvalidPacketLength { length: u64 },
15
16    #[error("packet hash mismatch at offset {offset}")]
17    PacketHashMismatch { offset: u64 },
18
19    #[error("invalid main packet: {reason}")]
20    InvalidMainPacket { reason: String },
21
22    #[error("invalid file description packet: {reason}")]
23    InvalidFileDescPacket { reason: String },
24
25    #[error("invalid IFSC packet: {reason}")]
26    InvalidIfscPacket { reason: String },
27
28    #[error("invalid recovery slice packet: {reason}")]
29    InvalidRecoveryPacket { reason: String },
30
31    #[error("invalid creator packet: {reason}")]
32    InvalidCreatorPacket { reason: String },
33
34    #[error("duplicate main packet with different recovery set ID")]
35    ConflictingRecoverySet,
36
37    #[error("no main packet found in PAR2 file set")]
38    NoMainPacket,
39
40    #[error("insufficient critical PAR2 data: {reason}")]
41    InsufficientCriticalData { reason: String },
42
43    #[error("PAR2 resource limit exceeded: {reason}")]
44    ResourceLimitExceeded { reason: String },
45
46    // --- Verification errors ---
47    #[error("file not found: {filename}")]
48    FileNotFound { filename: String },
49
50    #[error("file {filename}: {damaged_slices} of {total_slices} slices damaged")]
51    FileDamaged {
52        filename: String,
53        damaged_slices: u32,
54        total_slices: u32,
55    },
56
57    // --- Repair errors ---
58    #[error(
59        "insufficient recovery data: need {needed} blocks, have {available} (deficit: {deficit})"
60    )]
61    InsufficientRecoveryData {
62        needed: u32,
63        available: u32,
64        deficit: u32,
65    },
66
67    #[error("reed-solomon decode failed: {reason}")]
68    ReedSolomonError { reason: String },
69
70    #[error("repair target write failed for {filename} at offset {offset}: {source}")]
71    RepairWriteFailed {
72        filename: String,
73        offset: u64,
74        source: std::io::Error,
75    },
76
77    // --- Cancellation ---
78    #[error("operation cancelled")]
79    Cancelled,
80
81    // --- I/O ---
82    #[error("I/O error: {0}")]
83    Io(#[from] std::io::Error),
84
85    // --- Creation errors ---
86    #[error("invalid PAR2 creation options: {reason}")]
87    InvalidCreationOptions { reason: String },
88
89    #[error("unsafe PAR2 source path {path}: {reason}")]
90    UnsafeCreationSource { path: String, reason: String },
91
92    #[error("source file changed while creating PAR2 data: {path}")]
93    CreationSourceChanged { path: String },
94
95    #[error("PAR2 output already exists: {path}")]
96    CreationOutputExists { path: String },
97
98    #[error("unsafe PAR2 output path {path}: {reason}")]
99    UnsafeCreationOutput { path: String, reason: String },
100
101    #[error("staged PAR2 output validation failed for {path}: {reason}")]
102    CreationValidation { path: String, reason: String },
103
104    #[error("Metal creation backend is unavailable: {reason}")]
105    MetalUnavailable { reason: String },
106
107    #[error("Metal creation failed after staging began: {reason}")]
108    MetalExecutionFailed { reason: String },
109}
110
111pub type Result<T> = std::result::Result<T, Par2Error>;