pub const HARD_ERASURE: u8 = 0xFF;
pub trait BranchMetric {
type Sample: Copy;
const MAX_SPREAD: u32;
fn branch_distance(expected: u32, received: &[Self::Sample]) -> u32;
fn erasure() -> Self::Sample;
}
pub struct HardHamming;
impl BranchMetric for HardHamming {
type Sample = u8;
const MAX_SPREAD: u32 = 256;
fn branch_distance(expected: u32, received: &[Self::Sample]) -> u32 {
let n = received.len();
let mut d: u32 = 0;
for (j, &s) in received.iter().enumerate() {
if s == HARD_ERASURE {
continue;
}
let shift = n - 1 - j;
let exp_bit = if shift < 32 {
((expected >> shift) & 1) as u8
} else {
0
};
if exp_bit != (s & 1) {
d = d.saturating_add(1); }
}
d
}
fn erasure() -> u8 {
HARD_ERASURE
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn hamming_counts_bit_mismatches() {
assert_eq!(HardHamming::branch_distance(0b10, &[1, 0]), 0);
assert_eq!(HardHamming::branch_distance(0b10, &[0, 0]), 1);
assert_eq!(HardHamming::branch_distance(0b10, &[0, 1]), 2);
}
#[test]
fn erasure_sample_is_free() {
assert_eq!(HardHamming::erasure(), 0xFF);
assert_eq!(HardHamming::branch_distance(0b11, &[0xFF, 0xFF]), 0);
assert_eq!(HardHamming::branch_distance(0b11, &[0xFF, 0]), 1); }
}