ps_ecc/methods/decode.rs
1use crate::{codeword::Codeword, long, DecodeError, ReedSolomon};
2
3/// Verifies the error-correcting code and returns the message.
4///
5/// Correctable corruption is repaired. For codewords longer than 255 bytes,
6/// the `parity` argument is ignored, since the header records the parity, and
7/// bytes beyond the full length recorded in the header are discarded, so
8/// input rejected by [`validate`](crate::validate) may still decode
9/// successfully.
10/// # Errors
11/// For codewords of at most 255 bytes:
12/// - `InsufficientParityBytes` is returned if `parity > length / 2`.
13/// - `RSConstructorError` is returned if `parity` otherwise exceeds [`crate::MAX_PARITY`].
14/// - `RSDecodeError` is returned if decoding fails.
15///
16/// For longer codewords:
17/// - `LongEccDecodeError` is returned if decoding fails.
18pub fn decode(received: &[u8], parity: u8) -> Result<Codeword<'_>, DecodeError> {
19 if let Ok(length) = u8::try_from(received.len()) {
20 if parity > length >> 1 {
21 return Err(DecodeError::InsufficientParityBytes(parity, length));
22 }
23
24 let rs = ReedSolomon::new(parity)?;
25
26 Ok(rs.decode(received)?)
27 } else {
28 Ok(long::decode(received)?)
29 }
30}
31
32#[cfg(test)]
33mod tests {
34 use crate::{decode, encode, EccError};
35
36 #[test]
37 fn ecc_works() -> Result<(), EccError> {
38 let test_str = "Strč prst skrz krk! ¯\\_(ツ)_/¯".as_bytes();
39 let mut encoded = encode(test_str, 13)?;
40
41 for i in 0..13 {
42 let index = (i * 37) % encoded.len();
43
44 encoded[index] ^= (i * index + 13).to_le_bytes()[0];
45 let decoded = decode(&encoded, 13)?;
46
47 assert_eq!(test_str, &decoded[..]);
48 }
49
50 Ok(())
51 }
52}