basenc 1.0.0-alpha.1

High-performance SIMD-accelerated Base64, Base32, and hex encoding and decoding with no_std support.
Documentation
use core::arch::aarch64::*;

use super::*;

#[inline]
#[target_feature(enable = "neon")]
unsafe fn encode_block(src: *const u8, base: &Base64) -> uint8x16_t {
	let input = vld1q_u8(src);
	let reorder = vld1q_u8([2, 1, 0, 16, 5, 4, 3, 16, 8, 7, 6, 16, 11, 10, 9, 16].as_ptr());
	let words = vreinterpretq_u32_u8(vqtbl1q_u8(input, reorder));
	let mask = vdupq_n_u32(0x3f);
	let i0 = vshrq_n_u32::<18>(words);
	let i1 = vshlq_n_u32::<8>(vandq_u32(vshrq_n_u32::<12>(words), mask));
	let i2 = vshlq_n_u32::<16>(vandq_u32(vshrq_n_u32::<6>(words), mask));
	let i3 = vshlq_n_u32::<24>(vandq_u32(words, mask));
	lookup(vreinterpretq_u8_u32(vorrq_u32(vorrq_u32(i0, i1), vorrq_u32(i2, i3))), base)
}

#[inline]
#[target_feature(enable = "neon")]
unsafe fn lookup(indices: uint8x16_t, base: &Base64) -> uint8x16_t {
	let upper = vaddq_u8(indices, vdupq_n_u8(b'A'));
	let lower = vaddq_u8(indices, vdupq_n_u8(b'a' - 26));
	let digits = vaddq_u8(indices, vdupq_n_u8(b'0'.wrapping_sub(52)));
	let lower_mask = vcgeq_u8(indices, vdupq_n_u8(26));
	let digit_mask = vcgeq_u8(indices, vdupq_n_u8(52));
	let char62_mask = vceqq_u8(indices, vdupq_n_u8(62));
	let char63_mask = vceqq_u8(indices, vdupq_n_u8(63));
	let ascii = vbslq_u8(lower_mask, lower, upper);
	let ascii = vbslq_u8(digit_mask, digits, ascii);
	let ascii = vbslq_u8(char62_mask, vdupq_n_u8(base.charset[62]), ascii);
	vbslq_u8(char63_mask, vdupq_n_u8(base.charset[63]), ascii)
}

#[target_feature(enable = "neon")]
pub unsafe fn encode(mut bytes: &[u8], base: &Base64, pad: Padding, mut dest: *mut u8) -> *mut u8 {
	while bytes.len() >= 16 {
		vst1q_u8(dest, encode_block(bytes.as_ptr(), base));
		bytes = bytes.get_unchecked(12..);
		dest = dest.add(16);
	}
	scalar::encode(bytes, base, pad, dest)
}