Skip to main content

ps_ecc/
error.rs

1#![allow(clippy::module_name_repetitions)]
2
3use std::num::TryFromIntError;
4
5use ps_buffer::BufferError;
6use thiserror::Error;
7
8/// Errors of GF(256) field arithmetic.
9#[derive(Error, Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
10pub enum GFError {
11    /// The divisor of a field division was zero.
12    #[error("Division by zero is undefined.")]
13    DivByZero,
14}
15
16/// Errors returned when constructing a [`Polynomial`](crate::Polynomial)
17/// from a slice.
18#[derive(Error, Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
19pub enum PolynomialFromSliceError {
20    /// The slice holds more coefficients than a polynomial can store.
21    #[error("Slice was {size} bytes; a polynomial over GF(256) holds at most 255 coefficients.")]
22    TooLong {
23        /// Length of the offending slice.
24        size: usize,
25    },
26}
27
28/// Errors returned by
29/// [`Polynomial::set_coefficients`](crate::Polynomial::set_coefficients).
30#[derive(Error, Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
31pub enum PolynomialSetCoefficientsError {
32    /// The coefficient range extends past the maximum coefficient index.
33    #[error("Range {offset}..{end} exceeds maximum coefficient index 254.")]
34    OutOfBounds {
35        /// First coefficient index of the range.
36        offset: u8,
37        /// One past the last coefficient index of the range.
38        end: usize,
39    },
40}
41
42/// Errors of polynomial multiplication.
43#[derive(Error, Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
44pub enum PolynomialMulError {
45    /// The degree of the product exceeds
46    /// [`Polynomial::MAX_DEGREE`](crate::Polynomial::MAX_DEGREE).
47    #[error("Result degree exceeds maximum of 254.")]
48    DegreeOverflow,
49}
50
51/// Errors of polynomial division and remainder.
52#[derive(Error, Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
53pub enum PolynomialDivError {
54    /// The divisor was the zero polynomial.
55    #[error("Division by zero polynomial.")]
56    ZeroDivisor,
57    /// Propagated from GF(256) arithmetic.
58    #[error(transparent)]
59    GFError(#[from] GFError),
60}
61
62/// Errors of polynomial XOR with a coefficient iterator.
63#[derive(Error, Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
64pub enum PolynomialXorError {
65    /// The iterator yielded more coefficients than a polynomial can store.
66    #[error("Coefficient iterator exceeded maximum length of 255.")]
67    TooManyCoefficients,
68}
69
70/// Errors returned by [`euclidean`](crate::euclidean).
71#[derive(Error, Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
72pub enum EuclideanError {
73    /// The error-correction capability `t` requires the polynomial `x^(2t)`,
74    /// whose degree exceeds [`Polynomial::MAX_DEGREE`](crate::Polynomial::MAX_DEGREE).
75    #[error("Error-correction capability {t} exceeds the maximum of 127.")]
76    CapabilityTooHigh {
77        /// The rejected error-correction capability.
78        t: u8,
79    },
80    /// Propagated from polynomial division.
81    #[error(transparent)]
82    PolynomialDiv(#[from] PolynomialDivError),
83    /// Propagated from polynomial multiplication.
84    #[error(transparent)]
85    PolynomialMul(#[from] PolynomialMulError),
86}
87
88/// Errors returned by [`ReedSolomon::new`](crate::ReedSolomon::new) and by
89/// the detached-parity methods when the parity slice itself is invalid.
90#[derive(Error, Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
91pub enum RSConstructorError {
92    /// A detached parity slice holds an odd number of bytes; parity always
93    /// comprises two bytes per correctable error.
94    #[error("Parity byte count {0} is odd; parity comprises two bytes per correctable error.")]
95    OddParityLength(usize),
96    /// The requested error-correction capability exceeds
97    /// [`MAX_PARITY`](crate::MAX_PARITY).
98    #[error("Parity count must be <= 63.")]
99    ParityTooHigh,
100}
101
102/// Errors returned by
103/// [`ReedSolomon::generate_parity`](crate::ReedSolomon::generate_parity).
104#[derive(Error, Debug, Clone, PartialEq, Eq)]
105pub enum RSGenerateParityError {
106    /// Propagated from polynomial division.
107    #[error(transparent)]
108    Division(#[from] PolynomialDivError),
109    /// Propagated from assembling the message polynomial; the message and
110    /// parity together exceed a single codeword.
111    #[error(transparent)]
112    SetCoefficients(#[from] PolynomialSetCoefficientsError),
113}
114
115/// Errors returned by [`ReedSolomon::encode`](crate::ReedSolomon::encode).
116#[derive(Error, Debug, Clone, PartialEq, Eq)]
117pub enum RSEncodeError {
118    /// Propagated from buffer allocation.
119    #[error(transparent)]
120    BufferError(#[from] BufferError),
121    /// Propagated from parity generation.
122    #[error(transparent)]
123    RSGenerateParityError(#[from] RSGenerateParityError),
124}
125
126/// Errors returned by
127/// [`ReedSolomon::compute_errors`](crate::ReedSolomon::compute_errors).
128#[derive(Error, Debug, Clone, PartialEq, Eq)]
129pub enum RSComputeErrorsError {
130    /// Propagated from GF(256) arithmetic.
131    #[error(transparent)]
132    GFError(#[from] GFError),
133    /// Propagated from the extended Euclidean algorithm.
134    #[error(transparent)]
135    EuclideanError(#[from] EuclideanError),
136    /// The codeword holds more errors than the parity can correct.
137    #[error("Too many errors; input is unrecoverable.")]
138    TooManyErrors,
139    /// Forney's formula would divide by zero; not expected to occur.
140    #[error("The error locator derivative evaluated to zero.")]
141    ZeroErrorLocatorDerivative,
142}
143
144/// Errors returned by the decoding and correction methods of
145/// [`ReedSolomon`](crate::ReedSolomon).
146#[derive(Error, Debug, Clone, PartialEq, Eq)]
147pub enum RSDecodeError {
148    /// Propagated from buffer allocation.
149    #[error(transparent)]
150    BufferError(#[from] BufferError),
151    /// The input holds fewer bytes than the parity, so it cannot be a
152    /// codeword.
153    #[error("Input length {received} is less than the parity length {parity_bytes}.")]
154    InsufficientLength {
155        /// Number of parity bytes the codec expects.
156        parity_bytes: u8,
157        /// Number of bytes actually received.
158        received: usize,
159    },
160    /// Propagated from error computation.
161    #[error(transparent)]
162    RSComputeErrorsError(#[from] RSComputeErrorsError),
163    /// Propagated from parity-slice validation.
164    #[error(transparent)]
165    RSConstructorError(#[from] RSConstructorError),
166    /// The corrected bytes still fail validation.
167    #[error("Too many errors to correct. Error computation nevertheless returned a valid polynomial, which is unlikely. Usually you'll get RSComputeErrorsError(TooManyErrors) instead.")]
168    TooManyErrors,
169    /// The input holds more bytes than a single codeword can carry.
170    #[error(transparent)]
171    TryFromIntError(#[from] TryFromIntError),
172}
173
174/// Errors returned by the free [`encode`](crate::encode) function.
175#[derive(Error, Debug, Clone, PartialEq, Eq)]
176pub enum EncodeError {
177    /// Propagated from long ECC encoding.
178    #[error(transparent)]
179    LongEccEncodeError(#[from] LongEccEncodeError),
180    /// Propagated from codec construction.
181    #[error(transparent)]
182    RSConstructorError(#[from] RSConstructorError),
183    /// Propagated from single-codeword encoding.
184    #[error(transparent)]
185    RSEncodeError(#[from] RSEncodeError),
186}
187
188/// Errors returned by the free [`decode`](crate::decode) function.
189#[derive(Error, Debug, Clone)]
190pub enum DecodeError {
191    /// The input is too short to carry the requested parity.
192    #[error("Insufficient input bytes for parity count of {0}: {0} * 2 > {1}.")]
193    InsufficientParityBytes(u8, u8),
194    /// Propagated from long ECC decoding.
195    #[error(transparent)]
196    LongEccDecodeError(#[from] LongEccDecodeError),
197    /// Propagated from codec construction.
198    #[error(transparent)]
199    RSConstructorError(#[from] RSConstructorError),
200    /// Propagated from single-codeword decoding.
201    #[error(transparent)]
202    RSDecodeError(#[from] RSDecodeError),
203}
204
205/// Umbrella error over encoding and decoding.
206#[derive(Error, Debug, Clone)]
207pub enum EccError {
208    /// Propagated from encoding.
209    #[error(transparent)]
210    EncodeError(#[from] EncodeError),
211    /// Propagated from decoding.
212    #[error(transparent)]
213    DecodeError(#[from] DecodeError),
214}
215
216/// Errors returned by [`LongEccHeader::new`](crate::LongEccHeader::new).
217#[derive(Error, Debug, Clone, PartialEq, Eq)]
218pub enum LongEccHeaderConstructorError {
219    /// Propagated from generating the header parity.
220    #[error("Generating parity failed: {0}")]
221    GenerateParity(#[from] RSGenerateParityError),
222    /// The full length does not match the codeword length derived from the
223    /// message length and segment geometry.
224    #[error("Full length {0} does not match the derived codeword length {1}.")]
225    InvalidFullLength(u32, u64),
226    /// The header and message do not fit within the full length.
227    #[error("Message length {0} does not fit within full length {1}.")]
228    InvalidMessageLength(u32, u32),
229    /// The error-correction capability exceeds
230    /// [`MAX_PARITY`](crate::MAX_PARITY).
231    #[error("Invalid parity count: {0}.")]
232    InvalidParityCount(u8),
233    /// The parity bytes leave no room for new data within a segment.
234    #[error("Invalid segment-to-parity ratio: {0} <= 2 * {1}.")]
235    InvalidSegmentParityRatio(u8, u8),
236}
237
238/// Errors returned by
239/// [`LongEccHeader::from_bytes`](crate::LongEccHeader::from_bytes).
240#[derive(Error, Debug, Clone, PartialEq, Eq)]
241pub enum LongEccHeaderFromBytesError {
242    /// The magic number does not identify a long ECC header.
243    #[error("Incorrect magic number: {0:x}.")]
244    IncorrectMagic(u16),
245
246    /// The encoding version is not supported.
247    #[error("Incorrect version number: {0}.")]
248    InvalidVersion(u8),
249
250    /// The header checksum mismatches even after error correction.
251    #[error("Header checksum incorrect.")]
252    IncorrectChecksum,
253
254    /// Propagated from correcting the header bytes with the header parity.
255    #[error("Header error correction failed: {0}")]
256    CorrectionFailed(#[from] RSDecodeError),
257
258    /// The header and message do not fit within the full length.
259    #[error("Message length {0} does not fit within full length {1}.")]
260    InvalidMessageLength(u32, u32),
261
262    /// The parity bytes leave no room for new data within a segment.
263    #[error("Invalid segment-to-parity ratio: {0} <= 2 * {1}.")]
264    InvalidSegmentParityRatio(u8, u8),
265
266    /// The full length does not match the codeword length derived from the
267    /// message length and segment geometry.
268    #[error("Full length {0} does not match the derived codeword length {1}.")]
269    InvalidFullLength(u32, u64),
270}
271
272/// Errors returned by
273/// [`LongEccHeader::from_byte_slice`](crate::LongEccHeader::from_byte_slice).
274#[derive(Error, Debug, Clone, PartialEq, Eq)]
275pub enum LongEccHeaderFromByteSliceError {
276    /// The slice holds fewer than the 32 bytes a header occupies.
277    #[error("Insufficient bytes for header: got {0}, need 32.")]
278    InsufficientBytes(usize),
279
280    /// Propagated from parsing the 32-byte header.
281    #[error(transparent)]
282    FromBytes(#[from] LongEccHeaderFromBytesError),
283}
284
285/// Errors of long ECC encoding.
286#[derive(Error, Debug, Clone, PartialEq, Eq)]
287pub enum LongEccEncodeError {
288    /// Propagated from buffer allocation.
289    #[error(transparent)]
290    BufferError(#[from] BufferError),
291    /// The requested error-correction capability exceeds
292    /// [`MAX_PARITY`](crate::MAX_PARITY).
293    #[error("Parity {0} >= 64, which is too high.")]
294    InvalidParity(u8),
295    /// The parity bytes leave no room for new data within a segment.
296    #[error("Invalid segment-to-parity ratio: {0} <= 2 * {1}.")]
297    InvalidSegmentParityRatio(u8, u8),
298    /// Propagated from header construction.
299    #[error("Long ECC header construction failed: {0}")]
300    LongEccHeaderCtor(#[from] LongEccHeaderConstructorError),
301    /// Propagated from codec construction.
302    #[error(transparent)]
303    RSConstructorError(#[from] RSConstructorError),
304    /// Propagated from parity generation.
305    #[error(transparent)]
306    RSGenerateParityError(#[from] RSGenerateParityError),
307    /// The encoded codeword would exceed `u32::MAX` bytes.
308    #[error(transparent)]
309    TryFromIntError(#[from] TryFromIntError),
310}
311
312/// Errors of long ECC decoding.
313#[derive(Error, Debug, Clone)]
314pub enum LongEccDecodeError {
315    /// Propagated from buffer allocation.
316    #[error(transparent)]
317    BufferError(#[from] BufferError),
318    /// Fast validation failed
319    #[error("Fast validation failed: {0}")]
320    FastValidate(#[from] LongEccFastValidateError),
321    /// The checksum still mismatches after error correction.
322    #[error("Integrity check failed after correction.")]
323    IntegrityCheckFailed,
324    /// The codeword is structurally invalid.
325    #[error("Codeword is invalid.")]
326    InvalidCodeword,
327    /// Propagated from header parsing.
328    #[error("Failed to decode header: {0}")]
329    HeaderDecode(#[from] LongEccHeaderFromByteSliceError),
330    /// The data bytes recorded in the header lie outside the buffer.
331    #[error("Failed to read data bytes.")]
332    ReadDataError,
333    /// The parity bytes recorded in the header lie outside the buffer.
334    #[error("Failed to read parity bytes.")]
335    ReadParityError,
336    /// Propagated from single-codeword decoding of a segment.
337    #[error(transparent)]
338    RSDecodeError(#[from] RSDecodeError),
339    /// A header length field does not fit the platform's `usize`.
340    #[error(transparent)]
341    TryFromIntError(#[from] TryFromIntError),
342}
343
344#[derive(Debug, thiserror::Error, Clone, PartialEq, Eq)]
345pub enum LongEccFastValidateError {
346    #[error("Header parsing failed: {0}")]
347    HeaderParse(#[from] crate::LongEccHeaderFromByteSliceError),
348    #[error("Integer conversion error: {0}")]
349    IntegerConversion(#[from] std::num::TryFromIntError),
350}