pub(super) fn is_letter_unit(unit: u16) -> bool {
char::from_u32(unit as u32).is_some_and(|c| c.is_alphabetic())
}
pub(super) fn is_upper_unit(unit: u16) -> bool {
char::from_u32(unit as u32).is_some_and(|c| c.is_uppercase())
}
pub(super) fn is_lower_unit(unit: u16) -> bool {
char::from_u32(unit as u32).is_some_and(|c| c.is_lowercase())
}
pub(super) fn to_upper_invariant_unit(unit: u16) -> u16 {
let Some(ch) = char::from_u32(unit as u32) else {
return unit;
};
let mut upper = ch.to_uppercase();
match (upper.next(), upper.next()) {
(Some(c), None) if c.len_utf16() == 1 => c as u16,
_ => unit,
}
}
pub(super) fn utf16_slice(units: &[u16], start: usize, len: usize) -> String {
String::from_utf16_lossy(&units[start..start + len])
}