reed_solomon/
encoder.rs

1use ::gf::poly_math::*;
2use ::gf::poly::Polynom;
3use ::buffer::Buffer;
4use ::gf;
5
6/// Reed-Solomon BCH encoder
7#[derive(Debug)]
8pub struct Encoder {
9    generator: Polynom,
10}
11
12impl Encoder {
13    /// Constructs a new `Encoder` and calculates generator polynomial of given `ecc_len`.
14    ///
15    /// # Example
16    /// ```rust
17    /// use reed_solomon::Encoder;
18    ///
19    /// let encoder = Encoder::new(8);
20    /// ```
21    pub fn new(ecc_len: usize) -> Self {
22        Encoder { generator: generator_poly(ecc_len) }
23    }
24
25    /// Encodes passed `&[u8]` slice and returns `Buffer` with result and `ecc` offset.
26    ///
27    /// # Example
28    /// ```rust
29    /// use reed_solomon::Encoder;
30    ///
31    /// let data = "Hello World".as_bytes();
32    /// let encoder = Encoder::new(8);
33    ///
34    /// let encoded = encoder.encode(&data);
35    ///
36    /// println!("whole: {:?}", &encoded[..]);
37    /// println!("data:  {:?}", encoded.data());
38    /// println!("ecc:   {:?}", encoded.ecc());
39    /// ```
40    pub fn encode(&self, data: &[u8]) -> Buffer {
41        let mut data_out = Polynom::from(data);
42        let data_len = data.len();
43
44        data_out.set_length(data_len + self.generator.len() - 1);
45
46        let gen = self.generator;
47        let mut lgen = Polynom::with_length(self.generator.len());
48        for (i, gen_i) in gen.iter().enumerate() {
49            uncheck_mut!(lgen[i]) = gf::LOG[*gen_i as usize];
50        } 
51        
52        for i in 0..data_len {
53            let coef = uncheck!(data_out[i]);
54            if coef != 0 {
55                let lcoef = gf::LOG[coef as usize] as usize;
56                for j in 1..gen.len() {
57                    uncheck_mut!(data_out[i + j]) ^= gf::EXP[(lcoef + lgen[j] as usize)];
58                }
59            }
60        }
61
62        data_out[..data_len].copy_from_slice(data);
63        Buffer::from_polynom(data_out, data_len)
64    }
65}
66
67fn generator_poly(ecclen: usize) -> Polynom {
68    let mut gen = polynom![1];
69    let mut mm = [1, 0];
70    for i in 0..ecclen {
71        mm[1] = gf::pow(2, i as i32);
72        gen = gen.mul(&mm);
73    }
74    gen
75}
76
77
78#[cfg(test)]
79mod tests {
80    #[test]
81    fn generator_poly() {
82        let answers =
83            [polynom![1, 3, 2],
84             polynom![1, 15, 54, 120, 64],
85             polynom![1, 255, 11, 81, 54, 239, 173, 200, 24],
86             polynom![1, 59, 13, 104, 189, 68, 209, 30, 8, 163, 65, 41, 229, 98, 50, 36, 59],
87             polynom![1, 116, 64, 52, 174, 54, 126, 16, 194, 162, 33, 33, 157, 176, 197, 225, 12,
88                      59, 55, 253, 228, 148, 47, 179, 185, 24, 138, 253, 20, 142, 55, 172, 88],
89             polynom![1, 193, 10, 255, 58, 128, 183, 115, 140, 153, 147, 91, 197, 219, 221, 220,
90                      142, 28, 120, 21, 164, 147, 6, 204, 40, 230, 182, 14, 121, 48, 143, 77,
91                      228, 81, 85, 43, 162, 16, 195, 163, 35, 149, 154, 35, 132, 100, 100, 51,
92                      176, 11, 161, 134, 208, 132, 244, 176, 192, 221, 232, 171, 125, 155, 228,
93                      242, 245]];
94
95        let mut ecclen = 2;
96        for i in 0..6 {
97            assert_eq!(*answers[i], *super::generator_poly(ecclen));
98            ecclen *= 2;
99        }
100    }
101
102    #[test]
103    fn encode() {
104        let data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
105                    22, 23, 24, 25, 26, 27, 28, 29];
106        let ecc = [99, 26, 219, 193, 9, 94, 186, 143];
107
108        let encoder = super::Encoder::new(ecc.len());
109        let encoded = encoder.encode(&data[..]);
110
111        assert_eq!(data, encoded.data());
112        assert_eq!(ecc, encoded.ecc());
113    }
114
115}