libecc 0.2.2

Library of Error-Correcting Codes for GD
Documentation
use crate::types::*;
use bitvec::prelude::*;

pub fn u32_to_u8vec(num: &u32) -> Vec<u8> {
  let mask: u32 = 0xFF;
  let u8vec: Vec<u8> = (0..4)
    .into_iter()
    .rev()
    .map(|idx| {
      let shift_mask = mask << (idx * 8);
      ((num & shift_mask) >> (idx * 8)) as u8
    })
    .collect();
  u8vec
}

pub fn u8vec_to_msb(u8vec: &[u8]) -> BVRep {
  BitVec::from_slice(u8vec)
}

pub fn u32_to_msb(num: &u32) -> BVRep {
  u8vec_to_msb(&u32_to_u8vec(num))
}

pub fn msb_to_u32(bv: &BSRep) -> u32 {
  assert!(bv.len() <= 32);
  let r = bv.iter().rev().enumerate().fold(
    0u32,
    |acc, (idx, b)| if *b { acc + (1 << idx) } else { acc },
  );
  r
}

#[allow(dead_code)]
pub fn get_residue(num: &BSRep, poly: &BSRep) -> BVRep {
  let first_one = poly.first_one().unwrap();
  let deg = poly.len() - first_one - 1;
  let trailed_poly = poly[first_one..].to_bitvec();

  if trailed_poly.len() > num.len() {
    let mut base = bitvec![u8, Msb0; 0; trailed_poly.len() - num.len() - 1];
    base.extend_from_bitslice(num);
    return base;
  }

  let mut aligned_poly = bitvec![u8, Msb0; 0; num.len() - trailed_poly.len()];
  aligned_poly.extend_from_bitslice(&trailed_poly);

  let res = get_residue_bits(num, &aligned_poly, deg);
  res[res.len() - deg..].to_bitvec()
}

#[allow(dead_code)]
fn get_residue_bits(num: &BSRep, poly: &BSRep, deg: usize) -> BVRep {
  assert_eq!(num.len(), poly.len());

  let ord = if let Some(one) = num.first_one() {
    num.len() - one - 1
  } else {
    return num.to_bitvec();
  };

  if ord < deg {
    num.to_bitvec()
  } else {
    let mut shifted = poly.to_bitvec();
    shifted.shift_left(ord - deg);
    get_residue_bits(&(shifted ^ num), poly, deg)
  }
}

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  fn test_residue_with_leading_zeros() {
    let bit_num = BVRep::from_element(0b10000);
    let bit_poly = BVRep::from_element(0b1011);
    let res = get_residue(&bit_num, &bit_poly);
    assert_eq!(res, bitvec![u8, Msb0; 1, 1, 0]);

    let bit_num = BVRep::from_element(0b1000_0000);
    let bit_poly = BVRep::from_element(0b10011);
    let res = get_residue(&bit_num, &bit_poly);
    assert_eq!(res, bitvec![u8, Msb0; 1, 0, 1, 1]);

    let bit_num = BVRep::from_vec(vec![0x80u8, 0x00u8]);
    let bit_poly = BVRep::from_vec(vec![0b1, 0x1Du8]);
    let res = get_residue(&bit_num, &bit_poly);
    assert_eq!(res, BVRep::from_element(0x26u8));
  }

  #[test]
  fn test_residue() {
    let bit_poly: BVRep = bitvec![u8, Msb0; 1, 0, 0, 1, 1];
    let ba: BVRep = bitvec![u8, Msb0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0];
    assert_eq!(bitvec![u8, Msb0; 0, 1, 0, 1], get_residue(&ba, &bit_poly));

    let bit_poly: BVRep = bitvec![u8, Msb0; 1, 0, 0, 1, 1];
    let ba: BVRep = bitvec![u8, Msb0; 0, 1, 0];
    assert_eq!(bitvec![u8, Msb0; 0, 0, 1, 0], get_residue(&ba, &bit_poly));
  }

  #[test]
  fn test_u32_to_bitvec_msb() {
    let u8vec = u32_to_u8vec(&0xFF10);
    assert_eq!(u8vec, vec![0u8, 0, 0xFF, 0x10]);

    let bv = u8vec_to_msb(&u8vec);
    let exp_bv = bits![
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0,
      0,
    ];
    assert_eq!(bv, exp_bv.to_bitvec());
    let bv = u32_to_msb(&0xFF10);
    assert_eq!(bv, exp_bv.to_bitvec());
  }

  #[test]
  fn test_msb_to_u32() {
    let bv = bitvec![u8, Msb0; 1, 0];
    assert_eq!(2, msb_to_u32(&bv));

    let bv = bitvec![u8, Msb0; 1, 0, 0, 0];
    assert_eq!(8, msb_to_u32(&bv));

    let bv = bitvec![u8, Msb0; 0, 1, 0, 1, 0, 0, 0, 0];
    assert_eq!(80, msb_to_u32(&bv));

    let bv = bitvec![u8, Msb0; 1, 1, 1, 1, 1, 1, 1, 1];
    assert_eq!(255, msb_to_u32(&bv));

    let bv = bitvec![u8, Msb0; 1, 1, 1, 1, 1, 1, 1, 1, 1];
    assert_eq!(511, msb_to_u32(&bv));
  }
}