Skip to main content

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}