use core::simd::{Select, Simd, SimdCast, SimdElement, cmp::SimdPartialOrd, num::SimdUint};
mod sealed {
pub trait Sealed {}
impl Sealed for u8 {}
impl Sealed for u16 {}
impl Sealed for u32 {}
}
pub trait Unit: sealed::Sealed + Copy + Eq + Default + SimdCast + SimdElement + 'static {
type Native: crate::encoding::Encoding<Unit = Self>;
fn from_u32(v: u32) -> Self;
fn to_u32(self) -> u32;
fn swap_bytes(self) -> Self;
fn cast<V: Unit, const N: usize>(v: Simd<Self, N>) -> Simd<V, N>;
fn widen<const N: usize>(v: Simd<Self, N>) -> Simd<u32, N>;
fn narrow<const N: usize>(v: Simd<u32, N>) -> Simd<Self, N>;
fn non_ascii_index<const N: usize>(v: Simd<Self, N>) -> Option<usize>;
fn non_plain_index<const N: usize>(v: Simd<Self, N>) -> Option<usize>;
fn fold_case<const N: usize>(v: Simd<Self, N>, base: u32) -> Simd<Self, N>;
}
macro_rules! impl_unit {
($t:ty, $native:ty) => {
impl Unit for $t {
type Native = $native;
#[inline(always)]
fn from_u32(v: u32) -> Self {
v as $t
}
#[inline(always)]
fn to_u32(self) -> u32 {
self as u32
}
#[inline(always)]
fn swap_bytes(self) -> Self {
<$t>::swap_bytes(self)
}
#[inline(always)]
fn cast<V: Unit, const N: usize>(v: Simd<Self, N>) -> Simd<V, N> {
v.cast::<V>()
}
#[inline(always)]
fn widen<const N: usize>(v: Simd<Self, N>) -> Simd<u32, N> {
v.cast::<u32>()
}
#[inline(always)]
fn narrow<const N: usize>(v: Simd<u32, N>) -> Simd<Self, N> {
v.cast::<$t>()
}
#[inline(always)]
fn non_ascii_index<const N: usize>(v: Simd<Self, N>) -> Option<usize> {
v.simd_gt(Simd::splat(0x7f)).first_set()
}
#[inline(always)]
fn non_plain_index<const N: usize>(v: Simd<Self, N>) -> Option<usize> {
(v - Simd::splat(0x20))
.simd_gt(Simd::splat(0x5e))
.first_set()
}
#[inline(always)]
fn fold_case<const N: usize>(v: Simd<Self, N>, base: u32) -> Simd<Self, N> {
let alpha = (v - Simd::splat(base as $t)).simd_le(Simd::splat(25));
alpha.select(v ^ Simd::splat(0x20), v)
}
}
};
}
impl_unit!(u8, crate::utf8::Utf8);
impl_unit!(u16, crate::utf16::Utf16<false>);
impl_unit!(u32, crate::utf32::Utf32<false>);
#[inline(always)]
pub const fn fold_case_scalar(v: u32, base: u32) -> u32 {
if v.wrapping_sub(base) <= 25 {
v ^ 0x20
} else {
v
}
}