#![forbid(unsafe_code)]
use fgf::bits;
const LENGTH: usize = 7;
const CHECKS: [[u8; 1]; 3] = [[0b0101_0101], [0b0110_0110], [0b0111_1000]];
fn main() {
let generator = [[0b0000_0111], [0b0001_1001], [0b0010_1010], [0b0100_1011]];
let sources: [&[u8]; 4] = generator.each_ref().map(|row| row.as_slice());
let message = 0b1101u64;
let mut codeword = [0u8; bits::bytes_for(LENGTH)];
bits::xor_gather(&mut codeword, LENGTH, message, &sources);
assert_eq!(syndrome(&codeword), 0);
assert_eq!((codeword[0] >> 2) & 1, 1);
assert_eq!((codeword[0] >> 4) & 1, 0);
assert_eq!((codeword[0] >> 5) & 1, 1);
assert_eq!((codeword[0] >> 6) & 1, 1);
println!("Message {message:04b} -> codeword {:07b}", codeword[0]);
let mut received = codeword;
received[0] ^= 1 << 4;
let error_position = syndrome(&received);
assert_eq!(error_position, 5);
let mut difference = received;
bits::xor_assign(&mut difference, &codeword);
assert_eq!(bits::weight(&difference, LENGTH), 1);
received[0] ^= 1 << (error_position - 1);
assert_eq!(received, codeword);
println!(
"Syndrome {error_position:03b} locates position {error_position}; correction matches the codeword."
);
let mut with_padding = codeword;
with_padding[0] |= 0x80;
assert_eq!(syndrome(&with_padding), 0);
assert_eq!(
bits::weight(&with_padding, LENGTH),
bits::weight(&codeword, LENGTH)
);
let live_bits = bits::XorRange::new(LENGTH, 0, LENGTH);
bits::xor_range_with(&mut with_padding, &codeword, &live_bits);
assert_eq!(with_padding, [0x80]);
println!("Logical-length queries ignore padding; range XOR preserves it.");
}
fn syndrome(word: &[u8]) -> u8 {
CHECKS.iter().enumerate().fold(0, |value, (bit, check)| {
value | (u8::from(bits::dot_product(word, check, LENGTH).is_one()) << bit)
})
}