use core::mem::MaybeUninit;
use core::slice;
use crate::error::InvalidInput;
use crate::util::digits16;
#[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` and `dst` should have the same length"
);
let digits = digits16::<UPPER>();
while !src.is_empty() {
{
let src = src[0];
let dst = unsafe { &mut *dst.as_mut_ptr() };
dst[0].write(digits[(src >> 4) as usize]);
dst[1].write(digits[(src & 0x0F) as usize]);
}
unsafe {
src = slice::from_raw_parts(src.as_ptr().add(1), src.len().unchecked_sub(1));
dst = slice::from_raw_parts_mut(dst.as_mut_ptr().add(1), dst.len().unchecked_sub(1));
};
}
}
#[allow(unused, reason = "XXX")]
#[inline]
pub(crate) fn validate_generic(src: &[[u8; 2]]) -> Result<(), InvalidInput> {
src.as_flattened()
.iter()
.all(u8::is_ascii_hexdigit)
.then_some(())
.ok_or(InvalidInput)
}
#[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
};
const LUT_FOR_VALIDATED: [u8; u8::MAX as usize + 1] = {
let mut lut = [0; _];
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` and `dst` should have the same length"
);
while !src.is_empty() {
{
let [hi, lo] = src[0];
let dst = unsafe { &mut *dst.as_mut_ptr() };
if VALIDATED {
let hi = LUT_FOR_VALIDATED[hi as usize];
let lo = LUT_FOR_VALIDATED[lo as usize];
dst.write(hi << 4 | lo);
} else {
let hi = LUT[hi as usize];
let lo = LUT[lo as usize];
if hi == NIL || lo == NIL {
return Err(InvalidInput);
}
dst.write(hi << 4 | lo);
}
}
unsafe {
src = slice::from_raw_parts(src.as_ptr().add(1), src.len().unchecked_sub(1));
dst = slice::from_raw_parts_mut(dst.as_mut_ptr().add(1), dst.len().unchecked_sub(1));
};
}
Ok(())
}