lowercase-hex 0.1.1

Fast byte array to lowercase hex string conversion
Documentation
#![allow(unsafe_op_in_unsafe_fn)]

use super::generic;
use crate::HEX_CHARS_LOWER;
use core::simd::prelude::*;

type Simd = u8x16;

pub(crate) const USE_CHECK_FN: bool = true;

pub(crate) unsafe fn encode(input: &[u8], output: *mut u8) {
    // Load table.
    let hex_table = Simd::from_array(*HEX_CHARS_LOWER);

    generic::encode_unaligned_chunks::<_>(input, output, |chunk: Simd| {
        // Load input bytes and mask to nibbles.
        let mut lo = chunk & Simd::splat(15);
        let mut hi = chunk >> Simd::splat(4);

        // Lookup the corresponding ASCII hex digit for each nibble.
        lo = hex_table.swizzle_dyn(lo);
        hi = hex_table.swizzle_dyn(hi);

        // Interleave the nibbles ([hi[0], lo[0], hi[1], lo[1], ...]).
        Simd::interleave(hi, lo)
    });
}

pub(crate) fn check(input: &[u8]) -> bool {
    generic::check_unaligned_chunks(input, |chunk: Simd| {
        let valid_digit = chunk.simd_ge(Simd::splat(b'0')) & chunk.simd_le(Simd::splat(b'9'));
        let valid_lower = chunk.simd_ge(Simd::splat(b'a')) & chunk.simd_le(Simd::splat(b'f'));
        let valid = valid_digit | valid_lower;
        valid.all()
    })
}

pub(crate) use generic::decode_checked;
pub(crate) use generic::decode_unchecked;