use crate::Exceptions;
use crate::common::Result;
use super::{GenericGFPoly, GenericGFRef};
pub struct ReedSolomonEncoder {
field: GenericGFRef,
cachedGenerators: Vec<GenericGFPoly>,
}
impl ReedSolomonEncoder {
pub fn new(field: GenericGFRef) -> Result<Self> {
let n = field;
Ok(Self {
cachedGenerators: vec![GenericGFPoly::new(n, &[1])?],
field: n,
})
}
fn buildGenerator(&mut self, degree: usize) -> Option<&GenericGFPoly> {
if degree >= self.cachedGenerators.len() {
let mut lastGenerator = self.cachedGenerators.last()?;
let cg_len = self.cachedGenerators.len();
let mut nextGenerator;
for d in cg_len..=degree {
nextGenerator = lastGenerator
.multiply(
&GenericGFPoly::new(
self.field,
&[
1,
self.field.exp(d as i32 - 1 + self.field.getGeneratorBase()),
],
)
.ok()?,
)
.ok()?;
self.cachedGenerators.push(nextGenerator);
lastGenerator = self.cachedGenerators.get(d)?;
}
}
let rv = self.cachedGenerators.get(degree)?;
Some(rv)
}
pub fn encode(&mut self, to_encode: &mut [i32], ec_bytes: usize) -> Result<()> {
if ec_bytes == 0 {
return Err(Exceptions::illegal_argument_with(
"No error correction bytes",
));
}
let data_bytes = to_encode.len() - ec_bytes;
if data_bytes == 0 {
return Err(Exceptions::illegal_argument_with("No data bytes provided"));
}
let fld = self.field;
let generator = self.buildGenerator(ec_bytes);
let mut info_coefficients: Vec<i32> = vec![0; data_bytes];
info_coefficients[0..data_bytes].clone_from_slice(&to_encode[0..data_bytes]);
let mut info = GenericGFPoly::new(fld, &info_coefficients)?;
info = info.multiply_by_monomial(ec_bytes, 1)?;
let remainder = &info.divide(generator.ok_or(Exceptions::REED_SOLOMON)?)?.1;
let coefficients = remainder.getCoefficients();
let num_zero_coefficients = ec_bytes - coefficients.len();
for i in 0..num_zero_coefficients {
to_encode[data_bytes + i] = 0;
}
to_encode[data_bytes + num_zero_coefficients
..(coefficients.len() + data_bytes + num_zero_coefficients)]
.clone_from_slice(&coefficients[0..coefficients.len()]);
Ok(())
}
}