use core::mem::MaybeUninit;
use crate::error::InvalidInput;
use crate::util::lut16;
#[allow(unsafe_code, reason = "XXX")]
pub(crate) const unsafe fn encode_generic_unchecked<const UPPER: bool>(
mut src: &[u8],
mut dst: &mut [[MaybeUninit<u8>; 2]],
) {
debug_assert!(
src.len() <= dst.len(),
"implementation bug: `src` should not be longer than `dst`"
);
let digits = lut16::<UPPER>();
while !src.is_empty() {
let cur_src;
(cur_src, src) = src.split_first().unwrap_unchecked();
let cur_dst;
(cur_dst, dst) = dst.split_first_mut().unwrap_unchecked();
cur_dst[0].write(digits[(*cur_src >> 4) as usize]);
cur_dst[1].write(digits[(*cur_src & 0x0F) as usize]);
}
}
#[allow(unsafe_code, reason = "XXX")]
pub(crate) const unsafe fn decode_generic_unchecked<const VALIDATED: bool>(
mut src: &[[u8; 2]],
mut dst: &mut [MaybeUninit<u8>],
) -> Result<(), InvalidInput> {
const NIL: u8 = u8::MAX;
const LUT: [u8; u8::MAX as usize + 1] = {
let mut lut = [NIL; _];
let mut i = 0;
while i <= u8::MAX as usize {
#[allow(clippy::cast_possible_truncation, reason = "XXX")]
match i as u8 {
b'0'..=b'9' => {
lut[i] = i as u8 - b'0';
}
b'a'..=b'f' => {
lut[i] = i as u8 - b'a' + 10;
}
b'A'..=b'F' => {
lut[i] = i as u8 - b'A' + 10;
}
_ => {}
};
i += 1;
}
lut
};
debug_assert!(
src.len() <= dst.len(),
"implementation bug: `src` should not be longer than `dst`"
);
while !src.is_empty() {
let cur_src;
(cur_src, src) = src.split_first().unwrap_unchecked();
let cur_dst;
(cur_dst, dst) = dst.split_first_mut().unwrap_unchecked();
let &[hi, lo] = cur_src;
let hi = LUT[hi as usize];
let lo = LUT[lo as usize];
if !VALIDATED && (hi == NIL || lo == NIL) {
return Err(InvalidInput);
}
cur_dst.write(hi << 4 | lo);
}
Ok(())
}