use core::iter::FusedIterator;
use utf_types::utf8::Ascii;
use utf_types::utf8::FourByteSequence;
use utf_types::utf8::PreparedThreeBytes;
use utf_types::utf8::PreparedTwoBytes;
use utf_types::utf8::ThreeByteSequence;
use utf_types::utf8::TwoByteSequence;
const SEQUENCE_FOR_REPLACEMENT_CHARACTER: ThreeByteSequence = const {
if let Ok(sequence) = ThreeByteSequence::try_new(0xEF, 0xBF, 0xBD) {
sequence
} else {
panic!()
}
};
pub trait Utf8Handler {
type Output;
fn single_byte(&self, ascii: Ascii) -> Self::Output;
fn two_byte(&self, sequence: TwoByteSequence) -> Self::Output;
fn three_byte(&self, sequence: ThreeByteSequence) -> Self::Output;
fn four_byte(&self, sequence: FourByteSequence) -> Self::Output;
#[inline(always)]
fn error(&self) -> Self::Output {
self.three_byte(SEQUENCE_FOR_REPLACEMENT_CHARACTER)
}
}
#[derive(Debug)]
pub struct Utf8CharsWithHandler<'a, H>
where
H: Utf8Handler,
{
remaining: &'a [u8],
handler: H,
}
impl<'a, H> Utf8CharsWithHandler<'a, H>
where
H: Utf8Handler,
{
#[inline(always)]
pub fn new(bytes: &'a [u8], handler: H) -> Self {
Utf8CharsWithHandler::<'a, H> {
remaining: bytes,
handler,
}
}
#[inline(always)]
pub fn as_slice(&self) -> &'a [u8] {
self.remaining
}
#[inline(always)]
pub fn handler(&self) -> &H {
&self.handler
}
#[cold]
fn error(&self) -> H::Output {
self.handler.error()
}
#[cold]
#[inline(never)]
fn next_fallback(&mut self) -> Option<H::Output> {
let (&first, after_one) = self.remaining.split_first()?;
if let Ok(ascii) = Ascii::try_new(first) {
self.remaining = after_one;
return Some(self.handler.single_byte(ascii));
}
if let Some((&second, after_two)) = after_one.split_first() {
if let Ok(two_byte) = TwoByteSequence::try_new(first, second) {
self.remaining = after_two;
return Some(self.handler.two_byte(two_byte));
}
let prepared_two = PreparedTwoBytes::new(first, second);
if let Some((&third, after_three)) = after_two.split_first() {
let prepared_three = PreparedThreeBytes::new_with_prepared(prepared_two, third);
if let Ok(three_byte) = ThreeByteSequence::try_new_with_prepared(prepared_three) {
self.remaining = after_three;
return Some(self.handler.three_byte(three_byte));
}
if prepared_three.prefix_of_four_byte() {
self.remaining = after_three;
return Some(self.error());
}
}
if prepared_two.sequence_prefix() {
self.remaining = after_two;
return Some(self.error());
}
}
self.remaining = after_one;
Some(self.error())
}
#[cold]
#[inline(never)]
fn next_back_fallback(&mut self) -> Option<H::Output> {
let (&last, before_one) = self.remaining.split_last()?;
if let Ok(ascii) = Ascii::try_new(last) {
self.remaining = before_one;
return Some(self.handler.single_byte(ascii));
}
if let Some((&second_last, before_two)) = before_one.split_last() {
if let Ok(two_byte) = TwoByteSequence::try_new(second_last, last) {
self.remaining = before_two;
return Some(self.handler.two_byte(two_byte));
}
let prepared_two = PreparedTwoBytes::new(second_last, last);
if let Some((&third_last, before_three)) = before_two.split_last() {
let prepared_three = PreparedThreeBytes::new(third_last, second_last, last);
if let Ok(three_byte) = ThreeByteSequence::try_new_with_prepared(prepared_three) {
self.remaining = before_three;
return Some(self.handler.three_byte(three_byte));
}
if prepared_three.prefix_of_four_byte() {
self.remaining = before_three;
return Some(self.error());
}
}
if prepared_two.sequence_prefix() {
self.remaining = before_two;
return Some(self.error());
}
}
self.remaining = before_one;
Some(self.error())
}
}
impl<'a, H> Iterator for Utf8CharsWithHandler<'a, H>
where
H: Utf8Handler,
{
type Item = H::Output;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
if self.remaining.len() >= 4 {
let (&first, after_one) = self.remaining.split_first().unwrap();
if let Ok(ascii) = Ascii::try_new(first) {
self.remaining = after_one;
return Some(self.handler.single_byte(ascii));
}
let (&second, after_two) = after_one.split_first().unwrap();
if let Ok(two_byte) = TwoByteSequence::try_new(first, second) {
self.remaining = after_two;
return Some(self.handler.two_byte(two_byte));
}
let (&third, after_three) = after_two.split_first().unwrap();
let prepared_three = PreparedThreeBytes::new(first, second, third);
if let Ok(three_byte) = ThreeByteSequence::try_new_with_prepared(prepared_three) {
self.remaining = after_three;
return Some(self.handler.three_byte(three_byte));
}
let (&fourth, after_four) = after_three.split_first().unwrap();
if let Ok(four_byte) = FourByteSequence::try_new_with_prepared(prepared_three, fourth) {
self.remaining = after_four;
return Some(self.handler.four_byte(four_byte));
}
}
self.next_fallback()
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.remaining.len();
(len.div_ceil(4), Some(len))
}
#[inline(always)]
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
}
impl<'a, H> DoubleEndedIterator for Utf8CharsWithHandler<'a, H>
where
H: Utf8Handler,
{
#[inline(always)]
fn next_back(&mut self) -> Option<H::Output> {
if self.remaining.len() >= 4 {
let (&last, before_one) = self.remaining.split_last().unwrap();
if let Ok(ascii) = Ascii::try_new(last) {
self.remaining = before_one;
return Some(self.handler.single_byte(ascii));
}
let (&second_last, before_two) = before_one.split_last().unwrap();
if let Ok(two_byte) = TwoByteSequence::try_new(second_last, last) {
self.remaining = before_two;
return Some(self.handler.two_byte(two_byte));
}
let (&third_last, before_three) = before_two.split_last().unwrap();
if let Ok(three_byte) = ThreeByteSequence::try_new(third_last, second_last, last) {
self.remaining = before_three;
return Some(self.handler.three_byte(three_byte));
}
let (&fourth_last, before_four) = before_three.split_last().unwrap();
if let Ok(four_byte) =
FourByteSequence::try_new(fourth_last, third_last, second_last, last)
{
self.remaining = before_four;
return Some(self.handler.four_byte(four_byte));
}
}
self.next_back_fallback()
}
}
impl<H> FusedIterator for Utf8CharsWithHandler<'_, H> where H: Utf8Handler {}
impl<'a, H> Clone for Utf8CharsWithHandler<'a, H>
where
H: Utf8Handler + Clone,
{
fn clone(&self) -> Self {
Self {
remaining: self.remaining,
handler: self.handler.clone(),
}
}
}