mod enums;
use core::{mem, ptr};
#[expect(clippy::cast_possible_truncation, reason = "leading_ones is weird, the max value is 8, no truncation")]
pub(crate) const fn codepoint_len_bmi(byte: u8) -> u8 {
(byte.leading_ones().saturating_sub(1) + 1) as u8
}
pub(crate) const fn codepoint_len_lut(byte: u8) -> u8 {
const LUT_SIZE: usize = 16;
const LUT: [u8; LUT_SIZE] = {
let mut i = 0;
let mut arr = [0; LUT_SIZE];
while i < LUT_SIZE {
#[expect(
clippy::cast_possible_truncation,
reason = "wont truncate, const contexts cant use try_from"
)]
{
arr[i] = codepoint_len_bmi((i as u8) << 4);
}
i += 1;
}
arr
};
LUT[(byte >> 4) as usize]
}
#[test]
fn identical_codepoint_len() {
use crate::tests;
use rayon::iter::ParallelIterator;
tests::all_chars().for_each(|c| {
let u8c = crate::Utf8Char::from_char(c);
let first = u8c.0.first_byte().0;
let control = c.len_utf8() as u8;
assert_eq!(codepoint_len_bmi(first as u8), control);
assert_eq!(codepoint_len_lut(first as u8), control);
assert_eq!(u8c.len_utf8(), control);
});
}
#[derive(Copy, Clone, Debug)]
#[repr(u8)]
#[expect(
dead_code,
reason = "we transmute into/outof these values, rust cant see it"
)]
#[expect(
clippy::missing_docs_in_private_items,
reason = "its 1..=4, each variant is unspecial"
)]
pub(crate) enum EncodedLength {
One = 1,
Two,
Three,
Four,
}
#[expect(
clippy::needless_lifetimes,
reason = "This is an unsafe code wrapper, the explicitness is its purpose"
)]
const unsafe fn trans_mut<'a, T, U>(v: &'a mut T) -> &'a mut U {
unsafe { core::mem::transmute(v) }
}
#[repr(transparent)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub(crate) struct Utf8FirstByte(pub(crate) enums::Utf8FirstByte);
impl Utf8FirstByte {
pub(crate) const unsafe fn new(b: u8) -> Self {
Self(unsafe { mem::transmute::<u8, enums::Utf8FirstByte>(b) })
}
pub(crate) const fn codepoint_len(self) -> EncodedLength {
let len: u8 = codepoint_len_lut(self.0 as u8);
unsafe { mem::transmute::<u8, EncodedLength>(len) }
}
}
#[repr(C)]
#[derive(Copy, Clone, Eq, PartialEq)]
pub(crate) struct Utf8CharInner(Utf8FirstByte, [enums::Utf8ContByte; 3]);
impl Utf8CharInner {
pub(crate) const fn len_utf8(self) -> EncodedLength {
self.0.codepoint_len()
}
pub(crate) const unsafe fn from_utf8char_array(arr: [u8; 4]) -> Self {
unsafe { mem::transmute(arr) }
}
pub(crate) const fn as_array(&self) -> &[u8; 4] {
unsafe { &*ptr::from_ref(self).cast::<[u8; 4]>() }
}
pub(crate) const fn first_byte(self) -> Utf8FirstByte {
self.0
}
pub(crate) const fn const_eq(self, other: Self) -> bool {
let this = u32::from_ne_bytes(*self.as_array());
let other = u32::from_ne_bytes(*other.as_array());
this == other
}
pub(crate) const unsafe fn first_byte_mut(&mut self) -> &mut u8 {
unsafe { trans_mut::<enums::Utf8FirstByte, u8>(&mut self.0 .0) }
}
pub(crate) const unsafe fn total_repr_mut(&mut self) -> &mut [u8; 4] {
unsafe { &mut *ptr::from_mut(self).cast::<[u8; 4]>() }
}
}
impl Ord for Utf8CharInner {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.as_array().cmp(other.as_array())
}
}
impl PartialOrd for Utf8CharInner {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}