diff --git a/src/common/cpp_essentials/concentric_finder.rs b/src/common/cpp_essentials/concentric_finder.rs index ac712774..f96341d2 100644 --- a/src/common/cpp_essentials/concentric_finder.rs +++ b/src/common/cpp_essentials/concentric_finder.rs @@ -6,9 +6,7 @@ use crate::{ Point, common::{ BitMatrix, Quadrilateral, - cpp_essentials::{ - Direction, FixedPattern, IsPattern, PatternRow, PatternType, PatternView, - }, + cpp_essentials::{Direction, FixedPattern, IsPattern, PatternType, PatternView}, }, point, }; @@ -110,7 +108,7 @@ pub fn CheckSymmetricPattern< } assert!(range > 0); - let mut res: PatternRow = PatternRow::new(vec![0; LEN]); + let mut res: [PatternType; LEN] = [0; LEN]; let s_2 = (res.len()) / 2; res[s_2] = (centerFwd + centerBwd - 1) as u16; // -1 because the starting pixel is counted twice range -= res[s_2] as i32; @@ -131,7 +129,7 @@ pub fn CheckSymmetricPattern< } if IsPattern::( - &PatternView::new(&res), + &PatternView::from_slice(&res), &FixedPattern::::with_reference(pattern), None, 0.0, diff --git a/src/common/cpp_essentials/pattern.rs b/src/common/cpp_essentials/pattern.rs index fef70bcd..e62db8e6 100644 --- a/src/common/cpp_essentials/pattern.rs +++ b/src/common/cpp_essentials/pattern.rs @@ -5,7 +5,7 @@ use crate::{ Exceptions, - common::{BitMatrix, Result}, + common::{BitArray, BitMatrix, Result}, }; pub type PatternType = u16; @@ -103,7 +103,7 @@ impl Iterator for PatternViewIterator<'_> { self.current_position += 1; Some( - *self.pattern_view.data.0.get( + *self.pattern_view.data.get( self.current_position - 1 + self.pattern_view.start + self.pattern_view.current, )?, ) @@ -112,7 +112,7 @@ impl Iterator for PatternViewIterator<'_> { #[derive(Debug, Clone, Copy)] pub struct PatternView<'a> { - data: &'a PatternRow, + data: &'a [PatternType], start: usize, count: usize, current: usize, @@ -122,10 +122,15 @@ impl<'a> PatternView<'a> { // A PatternRow always starts with the width of whitespace in front of the first black bar. // The first element of the PatternView is the first bar. pub fn new(bars: &'a PatternRow) -> PatternView<'a> { + Self::from_slice(&bars.0) + } + + /// Build a view directly over a slice of bars, avoiding an owning `PatternRow` allocation. + pub fn from_slice(bars: &'a [PatternType]) -> PatternView<'a> { PatternView { data: bars, start: 1, - count: bars.0.len(), + count: bars.len(), current: 0, } } @@ -138,38 +143,37 @@ impl<'a> PatternView<'a> { _end: usize, ) -> PatternView<'a> { PatternView { - data: bars, + data: &bars.0, start, count: size, current: base, } } - pub fn data(&self) -> &PatternRow { + pub fn data(&self) -> &[PatternType] { self.data } pub fn begin(&self) -> Option { - Some(*self.data.0.get(self.start)?) + Some(*self.data.get(self.start)?) } pub fn end(&self) -> Option { - // if self.start + self.count < self.data.0.len() { - // Some(self.data.0[self.start + self.count]) + // if self.start + self.count < self.data.len() { + // Some(self.data[self.start + self.count]) // } else { // None // } - Some(self.data.0.len() as PatternType) + Some(self.data.len() as PatternType) } // int sum(int n = 0) const { return std::accumulate(_data, _data + (n == 0 ? _size : n), 0); } pub fn sum(&self, n: Option) -> PatternType { if self.count == self.data.len() { - return self.data.0.iter().sum::(); + return self.data.iter().sum::(); } let n = n.unwrap_or(self.count); self.data - .0 .iter() .skip(self.start + self.current) .take(n) @@ -194,7 +198,6 @@ impl<'a> PatternView<'a> { } pub fn pixelsInFront(&self) -> PatternType { self.data - .0 .iter() .take(self.start + self.current) .copied() @@ -202,7 +205,6 @@ impl<'a> PatternView<'a> { } pub fn pixelsTillEnd(&self) -> PatternType { self.data - .0 .iter() .take(self.start + self.current + self.count) .copied() @@ -216,9 +218,9 @@ impl<'a> PatternView<'a> { self.current == self.start + self.count - 1 /*return _data + _size == _end - 1;*/ } pub fn isValidWithN(&self, n: usize) -> bool { - !self.data.0.is_empty() + !self.data.is_empty() && self.start <= self.current + self.start - && self.current + n < (self.data.0.len()) + && self.current + n < (self.data.len()) /*return _data && _data >= _base && _data + n <= _end;*/ } pub fn isValid(&self) -> bool { @@ -227,14 +229,12 @@ impl<'a> PatternView<'a> { pub fn has_quiet_zone_before(&self, scale: f32, acceptIfAtFirstBar: Option) -> bool { (acceptIfAtFirstBar.unwrap_or(false) && self.isAtLastBar()) - || Into::::into(self.data.0[self.count]) - >= Into::::into(self.sum(None)) * scale + || Into::::into(self.data[self.count]) >= Into::::into(self.sum(None)) * scale } pub fn hasQuietZoneAfter(&self, scale: f32, acceptIfAtLastBar: Option) -> bool { (acceptIfAtLastBar.unwrap_or(true) && self.isAtLastBar()) - || Into::::into(self.data.0[self.count]) - >= Into::::into(self.sum(None)) * scale + || Into::::into(self.data[self.count]) >= Into::::into(self.sum(None)) * scale } pub fn subView(&self, offset: usize, size: Option) -> PatternView<'a> { @@ -256,7 +256,7 @@ impl<'a> PatternView<'a> { pub fn shift(&mut self, n: usize) -> bool { self.current += n; - !self.data.0.is_empty() //&& self.start + self.count <= (self.start + self.count) + !self.data.is_empty() //&& self.start + self.count <= (self.start + self.count) } pub fn skipPair(&mut self) -> bool { @@ -279,18 +279,18 @@ impl<'a> PatternView<'a> { } fn try_get_index(&self, index: isize) -> Option { - if index.abs() > self.data.0.len() as isize { + if index.abs() > self.data.len() as isize { return None; } if index >= 0 { let fetch_spot = ((self.start + self.current) as isize + index) as usize; - return Some(self.data.0[fetch_spot]); + return Some(self.data[fetch_spot]); } if index.abs() > (self.start + self.current) as isize { return None; } let fetch_spot = ((self.start + self.current) as isize + index) as usize; - Some(self.data.0[fetch_spot]) + Some(self.data[fetch_spot]) } } @@ -302,18 +302,18 @@ impl std::ops::Index for PatternView<'_> { return &self.data[index.unsigned_abs()]; } - if index > self.data.0.len() as isize { + if index > self.data.len() as isize { panic!("array index out of bounds") } if index >= 0 { let fetch_spot = ((self.start + self.current) as isize + index) as usize; - return &self.data.0[fetch_spot]; + return &self.data[fetch_spot]; } if index.abs() > self.start as isize { panic!("array index out of bounds") } let fetch_spot = ((self.start + self.current) as isize + index) as usize; - &self.data.0[fetch_spot] + &self.data[fetch_spot] } } @@ -325,10 +325,10 @@ impl std::ops::Index for PatternView<'_> { return &self.data[index]; } - if index > self.data.0.len() { + if index > self.data.len() { panic!("array index out of bounds") } - self.data.0.get(self.start + self.current + index).unwrap() + self.data.get(self.start + self.current + index).unwrap() } } @@ -362,10 +362,10 @@ impl<'a, const LEN: usize> From<&PatternView<'a>> for [PatternType; LEN] { impl<'a> From<&PatternView<'a>> for &'a [PatternType] { fn from(value: &PatternView<'a>) -> Self { - if value.data.0.len() == value.count { - &value.data.0 + if value.data.len() == value.count { + value.data } else { - &value.data.0[value.current + value.start..=value.current + value.start + value.count] + &value.data[value.current + value.start..=value.current + value.start + value.count] } } } @@ -725,9 +725,39 @@ pub fn GetPatternRowTP(matrix: &BitMatrix, r: u32, pr: &mut PatternRow, transpos matrix.getRow(r) }; - let pixel_states: Vec = row.into(); + // Compute the run-length pattern directly from the bit array, avoiding an + // intermediate Vec allocation (this runs for every scanned image row). + GetPatternRowFromBits(&row, pr) +} + +/// Run-length-encode a BitArray row into `p_row` (white run first, per `PatternRow` convention). +fn GetPatternRowFromBits(b_row: &BitArray, p_row: &mut PatternRow) { + p_row.0.clear(); + + let mut current_color = Color::White; + let mut count: PatternType = 0; + + for i in 0..b_row.get_size() { + let this_color = if b_row.get(i) { + Color::Black + } else { + Color::White + }; + if current_color != this_color { + p_row.0.push(count); + count = 0; + current_color = this_color; + } + count += 1; + } + + if count != 0 { + p_row.0.push(count); + } - GetPatternRow(&pixel_states, pr) + if current_color == Color::Black { + p_row.0.push(0); + } } pub fn GetPatternRow + Copy + Default + From>( @@ -849,7 +879,7 @@ mod tests { let mut pv = PatternView::new(&p_row); - assert_eq!(pv.data().0, p_row.0); + assert_eq!(pv.data(), p_row.0.as_slice()); assert_eq!(pv[0], 1_u16); assert_eq!(pv[1], 1_u16); diff --git a/src/common/reedsolomon/generic_gf_poly.rs b/src/common/reedsolomon/generic_gf_poly.rs index a4bdd4ae..fa8e0780 100644 --- a/src/common/reedsolomon/generic_gf_poly.rs +++ b/src/common/reedsolomon/generic_gf_poly.rs @@ -48,40 +48,36 @@ impl GenericGFPoly { * or if leading coefficient is 0 and this is not a * constant polynomial (that is, it is not the monomial "0") */ - pub fn new(field: GenericGFRef, coefficients: &[i32]) -> Result { + pub fn new(field: GenericGFRef, coefficients: &[T]) -> Result + where + i32: From, + { if coefficients.is_empty() { return Err(Exceptions::illegal_argument_with( "coefficients cannot be empty", )); } + // The only generic work is widening to `i32`; trimming is done once in `from_coefficients`. + Self::from_coefficients(field, coefficients.iter().map(|&c| i32::from(c)).collect()) + } + + /// Build a polynomial from owned `i32` coefficients (most-significant first), stripping any + /// leading zeros. Non-generic so it is compiled once regardless of the input codeword type. + fn from_coefficients(field: GenericGFRef, mut coefficients: Vec) -> Result { + debug_assert!(!coefficients.is_empty()); + if coefficients.len() > 1 && coefficients[0] == 0 { + // Leading term must be non-zero for anything except the constant polynomial "0" + match coefficients.iter().position(|&c| c != 0) { + // All zero: collapse to the monomial "0". + None => coefficients.truncate(1), + Some(first_non_zero) => { + coefficients.drain(..first_non_zero); + } + } + } Ok(Self { field, - coefficients: { - let coefficients_length = coefficients.len(); - if coefficients_length > 1 && coefficients[0] == 0 { - // Leading term must be non-zero for anything except the constant polynomial "0" - let mut first_non_zero = 1; - while first_non_zero < coefficients_length && coefficients[first_non_zero] == 0 - { - first_non_zero += 1; - } - if first_non_zero == coefficients_length { - vec![0] - } else { - let mut new_coefficients = vec![0; coefficients_length - first_non_zero]; - let l = new_coefficients.len() - 1; - new_coefficients[0..=l].clone_from_slice(&coefficients[first_non_zero..]); - // System.arraycopy(coefficients, - // firstNonZero, - // this.coefficients, - // 0, - // this.coefficients.length); - new_coefficients - } - } else { - coefficients.to_vec() - } - }, + coefficients, }) } diff --git a/src/common/reedsolomon/reedsolomon_decoder.rs b/src/common/reedsolomon/reedsolomon_decoder.rs index 4bfa2027..dba99079 100644 --- a/src/common/reedsolomon/reedsolomon_decoder.rs +++ b/src/common/reedsolomon/reedsolomon_decoder.rs @@ -61,8 +61,31 @@ impl ReedSolomonDecoder { * @param twoS number of error-correction codewords available * @throws ReedSolomonException if decoding fails for any reason */ - pub fn decode(&self, received: &mut [i32], twoS: i32) -> Result { + pub fn decode(&self, received: &mut [T], twoS: i32) -> Result + where + i32: From, + T: TryFrom, + { let poly = GenericGFPoly::new(self.field, received)?; + // The error-location/magnitude search is `i32`-only; keep it monomorphization-free. + let corrections = self.computeCorrections(&poly, received.len(), twoS)?; + for &(position, error_magnitude) in &corrections { + let updated = GenericGF::addOrSubtract(i32::from(received[position]), error_magnitude); + received[position] = T::try_from(updated) + .map_err(|_| Exceptions::reed_solomon_with("error magnitude out of range"))?; + } + Ok(corrections.len()) + } + + /// Detect errors in `poly` and return the `(position, magnitude)` corrections to apply to the + /// received codewords. Returns an empty list when no errors are present. Non-generic so it is + /// compiled once regardless of the codeword type passed to [`decode`]. + fn computeCorrections( + &self, + poly: &GenericGFPoly, + received_len: usize, + twoS: i32, + ) -> Result> { let mut syndromeCoefficients = vec![0; twoS as usize]; let mut noError = true; for i in 0..twoS { @@ -75,9 +98,9 @@ impl ReedSolomonDecoder { } } if noError { - return Ok(0); + return Ok(Vec::new()); } - let Ok(syndrome) = GenericGFPoly::new(self.field, &syndromeCoefficients) else { + let Ok(syndrome) = GenericGFPoly::new::(self.field, &syndromeCoefficients) else { return Err(Exceptions::REED_SOLOMON); }; let sigmaOmega = self.runEuclideanAlgorithm( @@ -89,21 +112,21 @@ impl ReedSolomonDecoder { let omega = &sigmaOmega[1]; let errorLocations = self.findErrorLocations(sigma)?; let errorMagnitudes = self.findErrorMagnitudes(omega, &errorLocations)?; + let mut corrections = Vec::with_capacity(errorLocations.len()); for (error_location, error_magnitude) in errorLocations.iter().zip(errorMagnitudes) { // for i in 0..errorLocations.len() { //for (int i = 0; i < errorLocations.length; i++) { let log_value = self.field.log(*error_location as i32)?; - if log_value > received.len() as i32 - 1 { + if log_value > received_len as i32 - 1 { return Err(Exceptions::reed_solomon_with("Bad error location")); } - let position: isize = received.len() as isize - 1 - log_value as isize; + let position: isize = received_len as isize - 1 - log_value as isize; if position < 0 { return Err(Exceptions::reed_solomon_with("Bad error location")); } - received[position as usize] = - GenericGF::addOrSubtract(received[position as usize], error_magnitude); + corrections.push((position as usize, error_magnitude)); } - Ok(errorLocations.len()) + Ok(corrections) } fn runEuclideanAlgorithm( diff --git a/src/qrcode/cpp_port/decoder.rs b/src/qrcode/cpp_port/decoder.rs index 99459b89..d8ca81e8 100644 --- a/src/qrcode/cpp_port/decoder.rs +++ b/src/qrcode/cpp_port/decoder.rs @@ -27,32 +27,12 @@ use crate::qrcode::decoder::DataBlock; * @return false if error correction fails */ pub fn CorrectErrors(codewordBytes: &mut [u8], numDataCodewords: u32) -> Result { - // First read into an array of ints - // std::vector codewordsInts(codewordBytes.begin(), codewordBytes.end()); - let mut codewordsInts: Vec = codewordBytes.iter().copied().map(|b| b as i32).collect(); - let numECCodewords = ((codewordBytes.len() as u32) - numDataCodewords) as i32; let rs = ReedSolomonDecoder::new(get_predefined_genericgf( PredefinedGenericGF::QrCodeField256, )); - rs.decode(&mut codewordsInts, numECCodewords)?; - - // if rs.decode(&mut codewordsInts, numECCodewords)? != 0 - // // if (!ReedSolomonDecode(GenericGF::QRCodeField256(), codewordsInts, numECCodewords)) - // { - // return Ok(false); - // } - - // Copy back into array of bytes -- only need to worry about the bytes that were data - // We don't care about errors in the error-correction codewords - for (dst, &src) in codewordBytes[..numDataCodewords as usize] - .iter_mut() - .zip(&codewordsInts[..numDataCodewords as usize]) - { - *dst = src as u8; - } - // std::copy_n(codewordsInts.begin(), numDataCodewords, codewordBytes.begin()); + rs.decode(codewordBytes, numECCodewords)?; Ok(true) } @@ -402,10 +382,6 @@ pub fn Decode(bits: &BitMatrix) -> Result> { }; let version = pversion; - let Ok(formatInfo) = ReadFormatInformation(bits) else { - return Err(Exceptions::format_with("Invalid format information")); - }; - // Read codewords let codewords = ReadCodewords(bits, version, &formatInfo)?; if codewords.is_empty() { @@ -426,8 +402,10 @@ pub fn Decode(bits: &BitMatrix) -> Result> { let mut resultIterator = 0; //resultBytes.begin(); // Error-correct and copy data blocks together into a stream of bytes + let mut codewordBytes: Vec = Vec::new(); for dataBlock in dataBlocks.iter() { - let mut codewordBytes = dataBlock.getCodewords().to_vec(); + codewordBytes.clear(); + codewordBytes.extend_from_slice(dataBlock.getCodewords()); let numDataCodewords = dataBlock.getNumDataCodewords() as usize; if !CorrectErrors(&mut codewordBytes, numDataCodewords as u32)? { diff --git a/src/qrcode/cpp_port/detector.rs b/src/qrcode/cpp_port/detector.rs index fb69be64..acb504b5 100644 --- a/src/qrcode/cpp_port/detector.rs +++ b/src/qrcode/cpp_port/detector.rs @@ -98,9 +98,9 @@ pub fn FindFinderPatterns( let mut res: Vec = Vec::new(); let mut y = skip - 1; + let mut row = PatternRow::default(); while y < height { // for (int y = skip - 1; y < height; y += skip) { - let mut row = PatternRow::default(); GetPatternRowTP(image, y, &mut row, false); let mut next: PatternView = PatternView::new(&row); @@ -154,25 +154,18 @@ pub fn FindFinderPatterns( // Yields (dx, dy) offsets forming the square ring at exactly the given radius. // Calling for r in 0..=max_r covers every cell in the square exactly once with no duplicates. fn spiral(radius: i32) -> impl Iterator { - let mut pts = Vec::new(); - if radius == 0 { - pts.push((0i32, 0i32)); - } else { - let r = radius; - for x in -r..r { - pts.push((x, -r)); - } - for y in -r..r { - pts.push((r, y)); - } - for x in (-r + 1..=r).rev() { - pts.push((x, r)); - } - for y in (-r + 1..=r).rev() { - pts.push((-r, y)); - } - } - pts.into_iter() + let r = radius; + let center = (r == 0).then_some((0, 0)); + let top = (-r..r).map(move |x| (x, -r)); + let right = (-r..r).map(move |y| (r, y)); + let bottom = (-r + 1..=r).rev().map(move |x| (x, r)); + let left = (-r + 1..=r).rev().map(move |y| (-r, y)); + center + .into_iter() + .chain(top) + .chain(right) + .chain(bottom) + .chain(left) } /** @@ -236,13 +229,14 @@ pub fn GenerateFinderPatternSets(patterns: &mut FinderPatterns) -> FinderPattern const MAX_MODULE_COUNT: f64 = 177.0 * 1.5; const MAX_CANDIDATES: usize = 15; + let mut candidates: Vec = Vec::with_capacity(MAX_CANDIDATES * 2); for i in 0..nb_patterns.saturating_sub(2) { let c0 = &patterns[i]; let max_dist = c0.size as f64 / 7.0 * MAX_MODULE_COUNT; let (cx, cy) = bin_idx(c0.p); let bin_radius = (max_dist / bin_size as f64).ceil() as i32; - let mut candidates: Vec = Vec::with_capacity(MAX_CANDIDATES * 2); + candidates.clear(); 'outer: for r in 0..=bin_radius { for (dx, dy) in spiral(r) { @@ -347,7 +341,7 @@ pub fn EstimateModuleSize(image: &BitMatrix, a: ConcentricPattern, b: Concentric let pattern = pattern.unwrap(); if !(IsPattern::( - &PatternView::new(&PatternRow::new(pattern.to_vec())), + &PatternView::from_slice(&pattern), &PATTERN, None, 0.0, @@ -726,6 +720,8 @@ pub fn SampleQR(image: &BitMatrix, fp: &FinderPatternSet) -> Result Result Result Result { .readPatternFromBlack(1, Some((width / 3 + 1) as i32)) .ok_or(Exceptions::NOT_FOUND)?; - let diag_hld = diagonal.to_vec().into(); - let view = PatternView::new(&diag_hld); + let view = PatternView::from_slice(&diagonal); if !(IsPattern::(&view, &PATTERN, None, 0.0, 0.0, 0.0) != 0.0) { return Err(Exceptions::NOT_FOUND); } @@ -981,8 +974,7 @@ pub fn DetectPureMQR(image: &BitMatrix) -> Result { let diagonal: Pattern = EdgeTracer::new(image, point_i(left, top), point_i(1, 1)) .readPatternFromBlack(1, None) .ok_or(Exceptions::ILLEGAL_STATE)?; - let diag_hld = diagonal.to_vec().into(); - let view = PatternView::new(&diag_hld); + let view = PatternView::from_slice(&diagonal); if !(IsPattern::(&view, &PATTERN, None, 0.0, 0.0, 0.0) != 0.0) { return Err(Exceptions::NOT_FOUND); } @@ -1062,8 +1054,7 @@ pub fn DetectPureRMQR(image: &BitMatrix) -> Result { let diagonal: Pattern = EdgeTracer::new(image, tl, point_i(1, 1)) .readPatternFromBlack(1, None) .ok_or(Exceptions::ILLEGAL_STATE)?; - let diag_hld = diagonal.to_vec().into(); - let view = PatternView::new(&diag_hld); + let view = PatternView::from_slice(&diagonal); if IsPattern::(&view, &PATTERN, None, 0.0, 0.0, 0.0) == 0.0 { return Err(Exceptions::NOT_FOUND); } @@ -1072,8 +1063,7 @@ pub fn DetectPureRMQR(image: &BitMatrix) -> Result { let subdiagonal: SubPattern = EdgeTracer::new(image, br, point_i(-1, -1)) .readPatternFromBlack(1, None) .ok_or(Exceptions::ILLEGAL_STATE)?; - let subdiagonal_hld = subdiagonal.to_vec().into(); - let view = PatternView::new(&subdiagonal_hld); + let view = PatternView::from_slice(&subdiagonal); if IsPattern::(&view, &SUBPATTERN, None, 0.0, 0.0, 0.0) == 0.0 { return Err(Exceptions::NOT_FOUND); } @@ -1093,8 +1083,7 @@ pub fn DetectPureRMQR(image: &BitMatrix) -> Result { // skip corner / finder / sub pattern edge cur.stepToEdge(Some(2 + i32::from(cur.isWhite())), None, None); let timing: TimingPattern = cur.readPattern(None).ok_or(Exceptions::ILLEGAL_STATE)?; - let timing_hld = timing.to_vec().into(); - let view = PatternView::new(&timing_hld); + let view = PatternView::from_slice(&timing); if IsPattern::(&view, &TIMINGPATTERN, None, 0.0, 0.0, 0.0) == 0.0 { return Err(Exceptions::NOT_FOUND); } diff --git a/src/qrcode/decoder/qrcode_decoder.rs b/src/qrcode/decoder/qrcode_decoder.rs index 0f6d0962..3130f72b 100644 --- a/src/qrcode/decoder/qrcode_decoder.rs +++ b/src/qrcode/decoder/qrcode_decoder.rs @@ -181,29 +181,13 @@ fn decode_bitmatrix_parser_with_hints( * @throws ChecksumException if error correction fails */ fn correctErrors(codewordBytes: &mut [u8], numDataCodewords: usize) -> Result<()> { - let numCodewords = codewordBytes.len(); - // First read into an array of ints - let mut codewordsInts = vec![0u8; numCodewords]; - codewordsInts[..numCodewords].copy_from_slice(&codewordBytes[..numCodewords]); - - let mut sending_code_words: Vec = codewordsInts.iter().map(|x| *x as i32).collect(); - + // Decode in place. We don't care about errors in the error-correction codewords. if let Err(Exceptions::ReedSolomonException(error_str)) = RS_DECODER.decode( - &mut sending_code_words, + codewordBytes, (codewordBytes.len() - numDataCodewords) as i32, ) { return Err(Exceptions::ChecksumException(error_str)); } - // Copy back into array of bytes -- only need to worry about the bytes that were data - // We don't care about errors in the error-correction codewords - for (code_word, sent_code_word) in codewordBytes - .iter_mut() - .zip(sending_code_words.iter()) - .take(numDataCodewords) - { - *code_word = *sent_code_word as u8; - } - Ok(()) }