use super::utf8_len_from_first_byte;
use std::{fmt::Display, mem::transmute};
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct Utf8Char {
bytes: [u8],
}
impl AsRef<[u8]> for Utf8Char {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl AsRef<str> for Utf8Char {
#[inline]
fn as_ref(&self) -> &str {
let bytes = self.as_ref();
debug_assert!(std::str::from_utf8(bytes).is_ok());
unsafe { std::str::from_utf8_unchecked(bytes) }
}
}
impl Utf8Char {
#[inline]
pub const unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
debug_assert!(std::str::from_utf8(bytes).is_ok());
debug_assert!(!bytes.is_empty());
debug_assert!(utf8_len_from_first_byte(bytes[0]) == bytes.len());
transmute(bytes)
}
#[inline]
pub const fn len_utf8(&self) -> usize {
self.bytes.len()
}
#[inline]
pub const fn as_bytes(&self) -> &[u8] {
&self.bytes
}
#[inline]
pub const fn as_str(&self) -> &str {
let bytes = self.as_bytes();
debug_assert!(std::str::from_utf8(bytes).is_ok());
unsafe { std::str::from_utf8_unchecked(bytes) }
}
#[inline]
pub fn from_first_char(s: &str) -> Option<&Self> {
let byte = s.as_bytes().first()?;
let l = unsafe { utf8_len_from_first_byte(*byte) };
let bytes: &Self = unsafe { transmute(s.as_bytes().get(0..l)?) };
Some(bytes)
}
}
impl PartialEq<char> for Utf8Char {
#[inline]
fn eq(&self, other: &char) -> bool {
let mut bytes = [0; 4];
let _ = other.encode_utf8(&mut bytes);
self.bytes == bytes[0..other.len_utf8()]
}
}
impl PartialEq<Utf8Char> for char {
#[inline]
fn eq(&self, other: &Utf8Char) -> bool {
<Utf8Char as PartialEq<char>>::eq(other, self)
}
}
impl PartialEq<char> for &Utf8Char {
#[inline]
fn eq(&self, other: &char) -> bool {
<Utf8Char as PartialEq<char>>::eq(self, other)
}
}
impl PartialEq<&Utf8Char> for char {
#[inline]
fn eq(&self, other: &&Utf8Char) -> bool {
<Utf8Char as PartialEq<char>>::eq(other, self)
}
}
impl From<&Utf8Char> for char {
#[inline]
fn from(f: &Utf8Char) -> Self {
unsafe { f.as_str().chars().next().unwrap_unchecked() }
}
}
impl Display for Utf8Char {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt(self.as_str(), f)
}
}