#[must_use]
pub const fn has_odd_parity(byte: u8) -> bool {
byte.count_ones() & 1 == 1
}
#[must_use]
pub const fn set_odd_parity(data7: u8) -> u8 {
let d = data7 & 0x7F;
if d.count_ones() & 1 == 0 { d | 0x80 } else { d }
}
#[must_use]
pub const fn strip_parity(byte: u8) -> Option<u8> {
if has_odd_parity(byte) {
Some(byte & 0x7F)
} else {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_data_value_round_trips_with_odd_parity() {
for d in 0u8..=0x7F {
let b = set_odd_parity(d);
assert!(has_odd_parity(b), "{d:#04x} -> {b:#04x}");
assert_eq!(b & 0x7F, d, "data bits untouched");
assert_eq!(strip_parity(b), Some(d));
}
}
#[test]
fn the_parity_bit_is_set_only_when_needed() {
assert_eq!(set_odd_parity(0x00), 0x80); assert_eq!(set_odd_parity(0x01), 0x01); assert_eq!(set_odd_parity(0x03), 0x83); assert_eq!(set_odd_parity(0x7F), 0x7F); }
#[test]
fn only_the_low_seven_bits_of_the_input_are_used() {
assert_eq!(set_odd_parity(0xFF), set_odd_parity(0x7F));
assert_eq!(set_odd_parity(0x80), set_odd_parity(0x00));
}
#[test]
fn a_single_flipped_bit_is_detected_never_corrected() {
for d in 0u8..=0x7F {
let good = set_odd_parity(d);
for bit in 0..8 {
assert_eq!(strip_parity(good ^ (1 << bit)), None, "{d:#04x} bit {bit}");
}
}
}
#[test]
fn matches_the_spec_corner_values() {
assert_eq!(set_odd_parity(0x14), 0x94);
assert_eq!(set_odd_parity(b'H'), 0xC8);
assert_eq!(strip_parity(0xC8), Some(b'H'));
}
}