pub struct NibRef {
inner: [u8],
}
impl NibRef {
fn is_high(&self) -> bool {
self.inner.len() == 1
}
pub fn from_high(v: &u8) -> &Self {
unsafe { mem::transmute(slice::from_raw_parts(v as *const _, 1)) }
}
pub fn from_low(v: &u8) -> &Self {
unsafe { mem::transmute(slice::from_raw_parts(v as *const _, 0)) }
}
}
impl fmt::Debug for NibRef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", u8::from(self))
}
}
impl From<&NibRef> for u8 {
fn from(nr: &NibRef) -> Self {
let v = unsafe { slice::from_raw_parts(nr.inner.as_ptr(), 1) }[0];
if nr.is_high() {
v >> 4
} else {
v & 0x0f
}
}
}
impl<'a> ops::Index<usize> for NibSlice<'a> {
type Output = NibRef;
fn index(&self, index: usize) -> &Self::Output {
assert!(index < self.len());
let index = index + if self.exclude.is_first_excluded() { 1 } else { 0 };
let b_idx = index >> 1;
let is_high = index & 1 == 0;
let b = &self.inner[b_idx];
if is_high {
NibRef::from_high(b)
} else {
NibRef::from_low(b)
}
}
}
#[cfg(test)]
mod test_nibref {
use super::*;
#[test]
fn low_works() {
let v = 0xab;
let a = NibRef::from_low(&v);
assert_eq!(u8::from(a), 0x0b);
}
#[test]
fn high_works() {
let v = 0xab;
let a = NibRef::from_high(&v);
assert_eq!(u8::from(a), 0x0a);
}
}
#[cfg(test)]
mod test_nibslice {
use super::*;
#[test]
fn build_ok() {
let ns = NibSlice::from_bytes_exclude(&[0xab, 0xcd], Exclude::Last);
assert_eq!(ns.len(), 3);
}
#[test]
fn index_single() {
let ns = NibSlice::from_bytes_exclude(&[0x12, 0x34], Exclude::First);
assert_eq!(ns.len(), 3);
let n = &ns[1];
assert_eq!(u8::from(n), 0x3);
}
#[test]
#[should_panic]
fn index_oob() {
let ns = NibSlice::from_bytes_exclude(&[0x12, 0x34], Exclude::Both);
assert_eq!(ns.len(), 2);
let n = &ns[2];
assert_eq!(u8::from(n), 0x4);
}
}