use binfield_matrix::{matrix_mul, matrix_mul_systematic};
use num_traits::PrimInt;
pub mod standard {
use super::*;
pub fn encode(data: u16) -> u16 {
assert!(data >> 11 == 0);
matrix_mul_systematic(data, GEN)
}
pub fn decode(word: u16) -> Option<(u16, usize)> {
assert!(word >> 15 == 0);
super::decode(word, PAR, LOCATIONS).map(|(w, n)| (w >> 4, n))
}
const GEN: &[u16] = &[0b11111110000, 0b11110001110, 0b11001101101, 0b10101011011];
const PAR: &[u16] = &[
0b111111100001000,
0b111100011100100,
0b110011011010010,
0b101010110110001,
];
const LOCATIONS: &[u16] = &[
0,
0b0000000000000001,
0b0000000000000010,
0b0000000000010000,
0b0000000000000100,
0b0000000000100000,
0b0000000001000000,
0b0000000010000000,
0b0000000000001000,
0b0000000100000000,
0b0000001000000000,
0b0000010000000000,
0b0000100000000000,
0b0001000000000000,
0b0010000000000000,
0b0100000000000000,
];
}
pub mod shortened {
use super::*;
pub fn encode(data: u8) -> u16 {
assert!(data >> 6 == 0);
matrix_mul_systematic(data, GEN)
}
pub fn decode(word: u16) -> Option<(u8, usize)> {
assert!(word >> 10 == 0);
super::decode(word, PAR, LOCATIONS).map(|(w, n)| ((w >> 4) as u8, n))
}
const GEN: &[u8] = &[0b111001, 0b110101, 0b101110, 0b011110];
const PAR: &[u16] = &[0b1110011000, 0b1101010100, 0b1011100010, 0b0111100001];
const LOCATIONS: &[u16] = &[
0,
0b0000000000000001,
0b0000000000000010,
0b0000000000100000,
0b0000000000000100,
0,
0,
0b0000000001000000,
0b0000000000001000,
0,
0,
0b0000000010000000,
0b0000000000010000,
0b0000000100000000,
0b0000001000000000,
0,
];
}
fn decode<T: PrimInt>(word: T, par: &[T], locs: &[T]) -> Option<(T, usize)> {
let s: usize = matrix_mul(word, par);
if s == 0 {
return Some((word, 0));
}
locs.get(s).and_then(|&loc| {
if loc == T::zero() {
None
} else {
Some((word ^ loc, 1))
}
})
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_standard() {
assert_eq!(standard::encode(0), 0);
assert_eq!(standard::encode(0b11111111111), 0b11111111111_1111);
for w in 0..1 << 11 {
assert_eq!(standard::decode(standard::encode(w)), Some((w, 0)));
}
let w = standard::encode(0b10101010101);
assert_eq!(w, 0b10101010101_0101);
assert_eq!(standard::decode(w), Some((0b10101010101, 0)));
for i in 0..15 {
assert_eq!(standard::decode(w ^ 1 << i), Some((0b10101010101, 1)));
}
for (i, j) in (0..15).zip(0..15) {
if i != j {
let (_, n) = standard::decode(w ^ (1 << i) ^ (1 << j)).unwrap();
assert_eq!(n, 1);
}
}
}
#[test]
fn test_shortened() {
assert_eq!(shortened::encode(0), 0);
assert_eq!(shortened::encode(0b111111), 0b111111_0000);
for w in 0..1 << 6 {
assert_eq!(shortened::decode(shortened::encode(w)), Some((w, 0)));
}
let w = shortened::encode(0b101010);
assert_eq!(w, 0b101010_0110);
assert_eq!(shortened::decode(w), Some((0b101010, 0)));
for i in 0..10 {
assert_eq!(shortened::decode(w ^ 1 << i), Some((0b101010, 1)));
}
for (i, j) in (0..10).zip(0..10) {
if i != j {
let (_, n) = shortened::decode(w ^ (1 << i) ^ (1 << j)).unwrap();
assert_eq!(n, 1);
}
}
}
}