ps_ecc/reed_solomon/methods/
decode.rs1use crate::{Codeword, RSDecodeError, ReedSolomon};
2
3impl ReedSolomon {
4 pub fn decode<'lt>(&self, received: &'lt [u8]) -> Result<Codeword<'lt>, RSDecodeError> {
16 let parity_bytes = self.parity_bytes();
17
18 if received.len() < usize::from(parity_bytes) {
19 return Err(RSDecodeError::InsufficientLength {
20 parity_bytes,
21 received: received.len(),
22 });
23 }
24
25 let corrected = self.correct(received)?;
26 let codeword = Codeword {
27 codeword: corrected,
28 range: usize::from(parity_bytes)..received.len(),
29 };
30
31 Ok(codeword)
32 }
33}
34
35#[cfg(test)]
36#[allow(clippy::decimal_bitwise_operands)]
37mod tests {
38 use ps_buffer::{Buffer, ToBuffer};
39
40 use crate::{RSComputeErrorsError, RSDecodeError, ReedSolomon};
41
42 type TestError = Box<dyn std::error::Error>;
43
44 #[test]
45 fn test_encode_decode() -> Result<(), TestError> {
46 let rs = ReedSolomon::new(4)?;
47 let message = b"Hello, World!".to_buffer()?;
48 let encoded = rs.encode(&message)?;
49
50 let mut corrupted = Buffer::with_capacity(encoded.len())?;
51
52 corrupted.extend_from_slice(&encoded)?;
53 corrupted[2] ^= 1;
54
55 let decoded = rs.decode(&corrupted)?;
56
57 assert_eq!(&decoded[..], &message[..]);
58
59 Ok(())
60 }
61
62 #[test]
63 fn test_too_many_errors() -> Result<(), TestError> {
64 let rs = ReedSolomon::new(2)?;
65 let message = b"Hello, World!".to_buffer()?;
66 let encoded = rs.encode(&message)?;
67
68 let mut corrupted = Buffer::with_capacity(encoded.len())?;
69
70 corrupted.extend_from_slice(&encoded)?;
71 corrupted[5] ^= 113;
72 corrupted[6] ^= 59;
73 corrupted[7] ^= 3;
74
75 assert_eq!(
76 rs.decode(&corrupted),
77 Err(RSDecodeError::RSComputeErrorsError(
78 RSComputeErrorsError::TooManyErrors
79 ))
80 );
81
82 Ok(())
83 }
84
85 #[test]
86 fn test_encode_correct_no_errors() -> Result<(), TestError> {
87 let rs = ReedSolomon::new(2)?;
88 let message = b"Data".to_buffer()?;
89 let encoded = rs.encode(&message)?;
90
91 let decoded = rs.decode(&encoded)?;
92
93 assert_eq!(&decoded[..], &message[..]);
94
95 Ok(())
96 }
97
98 #[test]
99 fn test_encode_correct_one_error() -> Result<(), TestError> {
100 let rs = ReedSolomon::new(3)?;
101 let message = b"Example".to_buffer()?;
102 let encoded = rs.encode(&message)?;
103
104 let mut corrupted = encoded.clone()?;
105
106 corrupted[1] ^= 0b1010_1010;
107
108 let decoded = rs.decode(&corrupted)?;
109
110 assert_eq!(&decoded[..], &message[..]);
111
112 Ok(())
113 }
114
115 #[test]
116 fn test_encode_correct_multiple_recoverable_errors() -> Result<(), TestError> {
117 let rs = ReedSolomon::new(4)?;
118 let message = b"Multiple".to_buffer()?;
119 let encoded = rs.encode(&message)?;
120
121 let mut corrupted = encoded.clone()?;
122
123 corrupted[3] ^= 0b0011_0011;
124 corrupted[7] ^= 0b1100_1100;
125
126 let decoded = rs.decode(&corrupted)?;
127
128 assert_eq!(&decoded[..], &message[..]);
129
130 Ok(())
131 }
132
133 #[test]
134 fn test_decode_no_errors() -> Result<(), TestError> {
135 let rs = ReedSolomon::new(2)?;
136 let message = b"DecodeOk".to_buffer()?;
137 let encoded = rs.encode(&message)?;
138
139 let decoded = rs.decode(&encoded)?;
140
141 assert_eq!(&decoded[..], &message[..]);
142
143 Ok(())
144 }
145
146 #[test]
147 fn test_decode_one_error() -> Result<(), TestError> {
148 let rs = ReedSolomon::new(3)?;
149 let message = b"DecodeErr".to_buffer()?;
150 let encoded = rs.encode(&message)?;
151
152 let mut corrupted = encoded.clone()?;
153
154 corrupted[5] ^= 32;
155
156 let decoded = rs.decode(&corrupted)?;
157
158 assert_eq!(&decoded[..], &message[..]);
159
160 Ok(())
161 }
162
163 #[test]
164 fn test_decode_too_many_errors() -> Result<(), TestError> {
165 let rs = ReedSolomon::new(1)?;
166 let message = b"DecodeMany".to_buffer()?;
167 let encoded = rs.encode(&message)?;
168
169 let mut corrupted = encoded.clone()?;
170
171 corrupted[0] ^= 1;
172 corrupted[2] ^= 2;
173
174 assert_eq!(
175 rs.decode(&corrupted),
176 Err(RSDecodeError::RSComputeErrorsError(
177 RSComputeErrorsError::TooManyErrors
178 ))
179 );
180
181 Ok(())
182 }
183
184 #[test]
185 fn test_decode_with_errors_in_parity_only() -> Result<(), TestError> {
186 let rs = ReedSolomon::new(3)?;
187 let message = b"ParityErr".to_buffer()?;
188 let encoded = rs.encode(&message)?;
189
190 let mut corrupted = encoded.clone()?;
191
192 corrupted[1] ^= 4; corrupted[3] ^= 8; let decoded = rs.decode(&corrupted)?;
196
197 assert_eq!(&decoded[..], &message[..]);
198
199 Ok(())
200 }
201
202 #[test]
203 fn test_decode_empty_input_rejected() -> Result<(), TestError> {
204 let rs = ReedSolomon::new(4)?;
205
206 assert_eq!(
209 rs.decode(&[]),
210 Err(RSDecodeError::InsufficientLength {
211 parity_bytes: 8,
212 received: 0,
213 })
214 );
215
216 Ok(())
217 }
218
219 #[test]
220 fn test_decode_input_shorter_than_parity_rejected() -> Result<(), TestError> {
221 let rs = ReedSolomon::new(4)?;
222
223 assert_eq!(
224 rs.decode(&[0u8; 7]),
225 Err(RSDecodeError::InsufficientLength {
226 parity_bytes: 8,
227 received: 7,
228 })
229 );
230
231 Ok(())
232 }
233
234 #[test]
235 fn test_decode_parity_only_codeword() -> Result<(), TestError> {
236 let rs = ReedSolomon::new(4)?;
237 let encoded = rs.encode(&[])?;
238
239 assert_eq!(encoded.len(), usize::from(rs.parity_bytes()));
240
241 let decoded = rs.decode(&encoded)?;
242
243 assert!(decoded.is_empty());
244
245 Ok(())
246 }
247
248 #[test]
249 fn test_decode_zero_parity_empty_input() -> Result<(), TestError> {
250 let rs = ReedSolomon::new(0)?;
251 let decoded = rs.decode(&[])?;
252
253 assert!(decoded.is_empty());
254
255 Ok(())
256 }
257
258 #[test]
259 fn test_correct_maximum_correctable_errors() -> Result<(), TestError> {
260 let rs = ReedSolomon::new(4)?;
261 let message = b"MaxErrors".to_buffer()?;
262 let encoded = rs.encode(&message)?;
263
264 let mut corrupted = encoded.clone()?;
265
266 corrupted[0] ^= 1;
267 corrupted[2] ^= 2;
268 corrupted[4] ^= 4;
269 corrupted[6] ^= 8;
270
271 let decoded = rs.decode(&corrupted)?;
272
273 assert_eq!(&decoded[..], &message[..]);
274
275 Ok(())
276 }
277}