Skip to main content

ps_ecc/reed_solomon/methods/
apply_corrections_detached.rs

1use crate::ReedSolomon;
2
3impl ReedSolomon {
4    /// Applies XOR corrections to a detached `(parity, data)` pair.
5    ///
6    /// The `corrections` slice is laid out parity-first, matching the
7    /// `parity || data` codeword layout: its first `parity.len()` bytes are
8    /// `XORed` onto `parity`, and the remaining bytes onto `data`.
9    ///
10    /// Like [`ReedSolomon::apply_corrections`], this method uses truncating
11    /// zip semantics. If `corrections` holds fewer bytes than `parity` and
12    /// `data` combined, the uncovered tail is left unmodified; excess
13    /// correction bytes are ignored.
14    pub fn apply_corrections_detached(
15        parity: &mut [u8],
16        data: &mut [u8],
17        corrections: impl AsRef<[u8]>,
18    ) {
19        let corrections = corrections.as_ref();
20        let split = corrections.len().min(parity.len());
21        let (parity_corrections, data_corrections) = corrections.split_at(split);
22
23        Self::apply_corrections(parity, parity_corrections);
24        Self::apply_corrections(data, data_corrections);
25    }
26}
27
28#[cfg(test)]
29#[allow(clippy::decimal_bitwise_operands)]
30mod tests {
31    use ps_buffer::Buffer;
32
33    use crate::ReedSolomon;
34
35    type TestError = Box<dyn std::error::Error>;
36
37    #[test]
38    fn test_apply_corrections_detached() -> Result<(), TestError> {
39        let mut parity = Buffer::from_slice([10, 20])?;
40        let mut data = Buffer::from_slice([30, 40, 50])?;
41        let corrections = [1, 2, 3, 4, 5];
42
43        ReedSolomon::apply_corrections_detached(&mut parity, &mut data, corrections);
44
45        assert_eq!(parity.as_slice(), &[10 ^ 1, 20 ^ 2]);
46        assert_eq!(data.as_slice(), &[30 ^ 3, 40 ^ 4, 50 ^ 5]);
47
48        Ok(())
49    }
50
51    #[test]
52    fn test_apply_corrections_detached_empty() -> Result<(), TestError> {
53        let mut parity = Buffer::from_slice([])?;
54        let mut data = Buffer::from_slice([])?;
55        let corrections = [];
56
57        ReedSolomon::apply_corrections_detached(&mut parity, &mut data, corrections);
58
59        assert_eq!(parity.as_slice(), &[]);
60        assert_eq!(data.as_slice(), &[]);
61
62        Ok(())
63    }
64
65    #[test]
66    fn test_corrections_shorter_than_parity() -> Result<(), TestError> {
67        // Previously panicked on `corrections[..parity.len()]`; now the
68        // uncovered parity tail and all of `data` are left unmodified.
69        let mut parity = Buffer::from_slice([10, 20, 30])?;
70        let mut data = Buffer::from_slice([40, 50])?;
71        let corrections = [1];
72
73        ReedSolomon::apply_corrections_detached(&mut parity, &mut data, corrections);
74
75        assert_eq!(parity.as_slice(), &[10 ^ 1, 20, 30]);
76        assert_eq!(data.as_slice(), &[40, 50]);
77
78        Ok(())
79    }
80
81    #[test]
82    fn test_corrections_cover_parity_only() -> Result<(), TestError> {
83        let mut parity = Buffer::from_slice([10, 20])?;
84        let mut data = Buffer::from_slice([30, 40])?;
85        let corrections = [1, 2];
86
87        ReedSolomon::apply_corrections_detached(&mut parity, &mut data, corrections);
88
89        assert_eq!(parity.as_slice(), &[10 ^ 1, 20 ^ 2]);
90        assert_eq!(data.as_slice(), &[30, 40]);
91
92        Ok(())
93    }
94
95    #[test]
96    fn test_corrections_cover_parity_and_partial_data() -> Result<(), TestError> {
97        let mut parity = Buffer::from_slice([10, 20])?;
98        let mut data = Buffer::from_slice([30, 40, 50])?;
99        let corrections = [1, 2, 3];
100
101        ReedSolomon::apply_corrections_detached(&mut parity, &mut data, corrections);
102
103        assert_eq!(parity.as_slice(), &[10 ^ 1, 20 ^ 2]);
104        assert_eq!(data.as_slice(), &[30 ^ 3, 40, 50]);
105
106        Ok(())
107    }
108
109    #[test]
110    fn test_corrections_longer_than_codeword() -> Result<(), TestError> {
111        let mut parity = Buffer::from_slice([10])?;
112        let mut data = Buffer::from_slice([20])?;
113        let corrections = [1, 2, 3, 4];
114
115        ReedSolomon::apply_corrections_detached(&mut parity, &mut data, corrections);
116
117        assert_eq!(parity.as_slice(), &[10 ^ 1]);
118        assert_eq!(data.as_slice(), &[20 ^ 2]);
119
120        Ok(())
121    }
122
123    #[test]
124    fn test_empty_parity_with_corrections() -> Result<(), TestError> {
125        let mut parity = Buffer::from_slice([])?;
126        let mut data = Buffer::from_slice([30, 40])?;
127        let corrections = [1, 2];
128
129        ReedSolomon::apply_corrections_detached(&mut parity, &mut data, corrections);
130
131        assert_eq!(parity.as_slice(), &[]);
132        assert_eq!(data.as_slice(), &[30 ^ 1, 40 ^ 2]);
133
134        Ok(())
135    }
136}