use crate::errors::{FromStrError, EmptyStrError, NonAsciiError, Utf8Error};
use crate::utf8_iterators::Utf8Iterator;
use crate::traits::{CharExt, U8UtfExt};
use crate::utf16_char::Utf16Char;
extern crate core;
use core::{hash, fmt, str, ptr};
use core::cmp::Ordering;
use core::borrow::Borrow;
use core::ops::Deref;
#[cfg(feature="std")]
use core::iter::FromIterator;
#[cfg(feature="ascii")]
extern crate ascii;
#[cfg(feature="ascii")]
use ascii::{AsciiChar,ToAsciiChar,ToAsciiCharError};
#[derive(Default)]
#[derive(PartialEq,Eq, PartialOrd,Ord)]
#[derive(Clone,Copy)]
pub struct Utf8Char {
bytes: [u8; 4],
}
impl str::FromStr for Utf8Char {
type Err = FromStrError;
fn from_str(s: &str) -> Result<Self, FromStrError> {
if s.is_empty() {
Err(FromStrError::Empty)
} else if s.len() != 1+s.as_bytes()[0].extra_utf8_bytes_unchecked() {
Err(FromStrError::MultipleCodepoints)
} else {
let mut bytes = [0; 4];
bytes[..s.len()].copy_from_slice(s.as_bytes());
Ok(Utf8Char{bytes})
}
}
}
impl From<Utf16Char> for Utf8Char {
fn from(utf16: Utf16Char) -> Utf8Char {
match utf16.to_tuple() {
(ascii @ 0..=0x00_7f, _) => {
Utf8Char{ bytes: [ascii as u8, 0, 0, 0] }
},
(unit @ 0..=0x07_ff, _) => {
let byte2 = 0x80 | (unit & 0x00_3f) as u8;
let byte1 = 0xc0 | ((unit & 0x07_c0) >> 6) as u8;
Utf8Char{ bytes: [byte1, byte2, 0, 0] }
},
(unit, None) => {
let byte3 = 0x80 | (unit & 0x00_3f) as u8;
let byte2 = 0x80 | ((unit & 0x0f_c0) >> 6) as u8;
let byte1 = 0xe0 | ((unit & 0xf0_00) >> 12) as u8;
Utf8Char{ bytes: [byte1, byte2, byte3, 0] }
},
(first, Some(second)) => {
let first = first + (0x01_00_00u32 >> 10) as u16;
let byte4 = 0x80 | (second & 0x00_3f) as u8;
let byte3 = 0x80 | ((second & 0x03_c0) >> 6) as u8
| (( first & 0x00_03) << 4) as u8;
let byte2 = 0x80 | (( first & 0x00_fc) >> 2) as u8;
let byte1 = 0xf0 | (( first & 0x07_00) >> 8) as u8;
Utf8Char{ bytes: [byte1, byte2, byte3, byte4] }
}
}
}
}
impl From<char> for Utf8Char {
fn from(c: char) -> Self {
Utf8Char::new(c)
}
}
impl From<Utf8Char> for char {
fn from(uc: Utf8Char) -> char {
uc.to_char()
}
}
impl IntoIterator for Utf8Char {
type Item=u8;
type IntoIter=Utf8Iterator;
fn into_iter(self) -> Utf8Iterator {
Utf8Iterator::from(self)
}
}
#[cfg(feature="std")]
impl Extend<Utf8Char> for Vec<u8> {
fn extend<I:IntoIterator<Item=Utf8Char>>(&mut self, iter: I) {
let iter = iter.into_iter();
self.reserve(iter.size_hint().0);
for u8c in iter {
self.push(u8c.bytes[0]);
for &extra in &u8c.bytes[1..] {
if extra != 0 {
self.push(extra);
}
}
}
}
}
#[cfg(feature="std")]
impl<'a> Extend<&'a Utf8Char> for Vec<u8> {
fn extend<I:IntoIterator<Item=&'a Utf8Char>>(&mut self, iter: I) {
self.extend(iter.into_iter().cloned())
}
}
#[cfg(feature="std")]
impl Extend<Utf8Char> for String {
fn extend<I:IntoIterator<Item=Utf8Char>>(&mut self, iter: I) {
unsafe { self.as_mut_vec().extend(iter) }
}
}
#[cfg(feature="std")]
impl<'a> Extend<&'a Utf8Char> for String {
fn extend<I:IntoIterator<Item=&'a Utf8Char>>(&mut self, iter: I) {
self.extend(iter.into_iter().cloned())
}
}
#[cfg(feature="std")]
impl FromIterator<Utf8Char> for String {
fn from_iter<I:IntoIterator<Item=Utf8Char>>(iter: I) -> String {
let mut string = String::new();
string.extend(iter);
return string;
}
}
#[cfg(feature="std")]
impl<'a> FromIterator<&'a Utf8Char> for String {
fn from_iter<I:IntoIterator<Item=&'a Utf8Char>>(iter: I) -> String {
iter.into_iter().cloned().collect()
}
}
#[cfg(feature="std")]
impl FromIterator<Utf8Char> for Vec<u8> {
fn from_iter<I:IntoIterator<Item=Utf8Char>>(iter: I) -> Self {
iter.into_iter().collect::<String>().into_bytes()
}
}
#[cfg(feature="std")]
impl<'a> FromIterator<&'a Utf8Char> for Vec<u8> {
fn from_iter<I:IntoIterator<Item=&'a Utf8Char>>(iter: I) -> Self {
iter.into_iter().cloned().collect::<String>().into_bytes()
}
}
impl AsRef<[u8]> for Utf8Char {
fn as_ref(&self) -> &[u8] {
&self.bytes[..self.len()]
}
}
impl AsRef<str> for Utf8Char {
fn as_ref(&self) -> &str {
unsafe{ str::from_utf8_unchecked( self.as_ref() ) }
}
}
impl Borrow<[u8]> for Utf8Char {
fn borrow(&self) -> &[u8] {
self.as_ref()
}
}
impl Borrow<str> for Utf8Char {
fn borrow(&self) -> &str {
self.as_ref()
}
}
impl Deref for Utf8Char {
type Target = str;
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}
#[cfg(feature="ascii")]
impl From<AsciiChar> for Utf8Char {
fn from(ac: AsciiChar) -> Self {
Utf8Char{ bytes: [ac.as_byte(),0,0,0] }
}
}
#[cfg(feature="ascii")]
impl ToAsciiChar for Utf8Char {
fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError> {
self.bytes[0].to_ascii_char()
}
unsafe fn to_ascii_char_unchecked(self) -> AsciiChar {
unsafe { self.bytes[0].to_ascii_char_unchecked() }
}
}
impl hash::Hash for Utf8Char {
fn hash<H : hash::Hasher>(&self, state: &mut H) {
self.to_char().hash(state);
}
}
impl fmt::Debug for Utf8Char {
fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.to_char(), fmtr)
}
}
impl fmt::Display for Utf8Char {
fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
fmtr.write_str(self.as_str())
}
}
impl PartialEq<char> for Utf8Char {
fn eq(&self, u32c: &char) -> bool {
*self == Utf8Char::from(*u32c)
}
}
impl PartialEq<Utf8Char> for char {
fn eq(&self, u8c: &Utf8Char) -> bool {
Utf8Char::from(*self) == *u8c
}
}
impl PartialOrd<char> for Utf8Char {
fn partial_cmp(&self, u32c: &char) -> Option<Ordering> {
self.partial_cmp(&Self::from(*u32c))
}
}
impl PartialOrd<Utf8Char> for char {
fn partial_cmp(&self, u8c: &Utf8Char) -> Option<Ordering> {
Utf8Char::from(*self).partial_cmp(u8c)
}
}
impl PartialEq<Utf16Char> for Utf8Char {
fn eq(&self, u16c: &Utf16Char) -> bool {
*self == Self::from(*u16c)
}
}
impl PartialOrd<Utf16Char> for Utf8Char {
fn partial_cmp(&self, u16c: &Utf16Char) -> Option<Ordering> {
self.partial_cmp(&Self::from(*u16c))
}
}
impl PartialEq<u8> for Utf8Char {
fn eq(&self, byte: &u8) -> bool {
self.bytes[0] == *byte && self.bytes[1] == 0
}
}
#[cfg(feature = "ascii")]
impl PartialEq<AsciiChar> for Utf8Char {
#[inline]
fn eq(&self, ascii: &AsciiChar) -> bool {
self.bytes[0] == *ascii as u8
}
}
#[cfg(feature = "ascii")]
impl PartialEq<Utf8Char> for AsciiChar {
#[inline]
fn eq(&self, u8c: &Utf8Char) -> bool {
u8c == self
}
}
#[cfg(feature = "ascii")]
impl PartialOrd<AsciiChar> for Utf8Char {
#[inline]
fn partial_cmp(&self, ascii: &AsciiChar) -> Option<Ordering> {
self.bytes[0].partial_cmp(ascii)
}
}
#[cfg(feature = "ascii")]
impl PartialOrd<Utf8Char> for AsciiChar {
#[inline]
fn partial_cmp(&self, u8c: &Utf8Char) -> Option<Ordering> {
self.partial_cmp(&u8c.bytes[0])
}
}
impl Utf8Char {
pub const fn new(c: char) -> Self {
if c.is_ascii() {
Utf8Char{bytes: [c as u8, 0, 0, 0]}
} else {
const EXTRA_BYTES: u64 = 0b11_11_11_11_11__10_10_10_10_10__01_01_01_01__00_00_00_00_00_00_00__00;
let bits_used = 32 - (c as u32).leading_zeros();
let len = 1 + ((EXTRA_BYTES >> (bits_used*2)) & 0b11);
let mut c = c as u32;
let mut parts = 0; parts |= c & 0x3f; c>>=6;
parts<<=8; parts |= c & 0x3f; c>>=6;
parts<<=8; parts |= c & 0x3f; c>>=6;
parts<<=8; parts |= c & 0x3f;
parts |= 0x80_80_80_80; parts >>= 8*(4-len);
parts |= (0xff_00u32 >> len) & 0xff; parts &= !(1u32 << (7-len));
Utf8Char {bytes: parts.to_le_bytes()}
}
}
pub fn from_str_start(src: &str) -> Result<(Self,usize),EmptyStrError> {
unsafe {
if src.is_empty() {
Err(EmptyStrError)
} else {
Ok(Utf8Char::from_slice_start_unchecked(src.as_bytes()))
}
}
}
pub fn from_slice_start(src: &[u8]) -> Result<(Self,usize),Utf8Error> {
char::from_utf8_slice_start(src).map(|(_,len)| {
let mut bytes = [0; 4];
bytes[..len].copy_from_slice(&src[..len]);
(Utf8Char{bytes}, len)
})
}
pub unsafe fn from_slice_start_unchecked(src: &[u8]) -> (Self,usize) {
unsafe {
let len = 1+src.get_unchecked(0).extra_utf8_bytes_unchecked();
let mut bytes = [0; 4];
ptr::copy_nonoverlapping(src.as_ptr(), bytes.as_mut_ptr() as *mut u8, len);
(Utf8Char{bytes}, len)
}
}
pub fn from_array(utf8: [u8;4]) -> Result<Self,Utf8Error> {
char::from_utf8_array(utf8)?;
let extra = utf8[0].extra_utf8_bytes_unchecked() as u32;
let mask = u32::from_le(0xff_ff_ff_ff >> (8*(3-extra)));
let unused_zeroed = mask & u32::from_ne_bytes(utf8); Ok(Utf8Char{ bytes: unused_zeroed.to_ne_bytes() })
}
#[inline]
pub const unsafe fn from_array_unchecked(utf8: [u8;4]) -> Self {
Utf8Char{ bytes: utf8 }
}
pub const fn from_ascii(ascii: u8) -> Result<Self,NonAsciiError> {
[Ok(Utf8Char{ bytes: [ascii, 0, 0, 0] }), Err(NonAsciiError)][(ascii >> 7) as usize]
}
#[inline]
pub const unsafe fn from_ascii_unchecked(ascii: u8) -> Self {
Utf8Char{ bytes: [ascii, 0, 0, 0] }
}
#[inline]
pub const fn len(self) -> usize {
(4 - (u32::from_le_bytes(self.bytes)|1).leading_zeros()/8) as usize
}
pub const fn is_ascii(self) -> bool {
self.bytes[0].is_ascii()
}
pub const fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
if self.is_ascii() {
self.bytes[0].eq_ignore_ascii_case(&other.bytes[0])
} else {
u32::from_le_bytes(self.bytes) == u32::from_le_bytes(other.bytes)
}
}
pub const fn to_ascii_uppercase(mut self) -> Self {
self.bytes[0] = self.bytes[0].to_ascii_uppercase();
self
}
pub const fn to_ascii_lowercase(mut self) -> Self {
self.bytes[0] = self.bytes[0].to_ascii_lowercase();
self
}
#[inline]
pub fn make_ascii_uppercase(&mut self) {
self.bytes[0].make_ascii_uppercase()
}
#[inline]
pub fn make_ascii_lowercase(&mut self) {
self.bytes[0].make_ascii_lowercase();
}
pub fn to_char(self) -> char {
unsafe { char::from_utf8_exact_slice_unchecked(&self.bytes[..self.len()]) }
}
pub fn to_slice(self, dst: &mut[u8]) -> usize {
if self.len() > dst.len() {
panic!("The provided buffer is too small.");
}
dst[..self.len()].copy_from_slice(&self.bytes[..self.len()]);
self.len()
}
pub const fn to_array(self) -> ([u8;4],usize) {
(self.bytes, self.len())
}
pub fn as_str(&self) -> &str {
self.deref()
}
}