use core::cmp;
#[inline]
pub fn nybble_index(n: usize, slice: &[u8]) -> u8 {
let byte_idx = n / 2;
if byte_idx < slice.len() {
let byte = slice[byte_idx];
if n & 1 == 0 {
1 + (byte & 0x0F)
} else {
1 + (byte >> 4)
}
} else {
0
}
}
#[inline]
pub fn nybble_mismatch(left: &[u8], right: &[u8]) -> Option<usize> {
let mut difference;
for (i, (l, r)) in left.iter().cloned().zip(right.iter().cloned()).enumerate() {
difference = l ^ r;
if difference != 0 {
if difference & 0x0F == 0 {
return Some(1 + i * 2);
} else {
return Some(i * 2);
}
}
}
if left.len() == right.len() {
None
} else {
Some(cmp::min(left.len(), right.len()) * 2)
}
}
#[inline]
pub fn nybble_get_mismatch(left: &[u8], right: &[u8]) -> Option<(u8, usize)> {
let mut difference;
for (i, (l, r)) in left.iter().cloned().zip(right.iter().cloned()).enumerate() {
difference = l ^ r;
if difference != 0 {
if difference & 0x0F == 0 {
return Some((1 + (l >> 4), 1 + i * 2));
} else {
return Some((1 + (l & 0x0F), i * 2));
}
}
}
if left.len() == right.len() {
None
} else {
let idx = cmp::min(left.len(), right.len()) * 2;
Some((nybble_index(idx, left), idx))
}
}
#[cfg(test)]
mod test {
use alloc::vec::Vec;
use quickcheck::TestResult;
use super::*;
quickcheck! {
fn nybble(nybs: Vec<u8>) -> TestResult {
for &nyb in &nybs {
if nyb > 15 {
return TestResult::discard();
}
}
let mut bytes = Vec::new();
for chunk in nybs.chunks(2) {
if chunk.len() == 2 {
bytes.push(chunk[0] | (chunk[1] << 4));
} else {
bytes.push(chunk[0]);
}
}
for (i, nyb) in nybs.into_iter().enumerate() {
assert_eq!(nyb + 1, nybble_index(i, &bytes));
}
TestResult::passed()
}
}
}