#![allow(unsafe_code)]
use crate::Utf8Handler;
use utf_types::utf8::Ascii;
use utf_types::utf8::FourByteSequence;
use utf_types::utf8::LeadForFourByte;
use utf_types::utf8::LeadForMultiByte;
use utf_types::utf8::LeadForThreeByte;
use utf_types::utf8::ThreeByteSequence;
use utf_types::utf8::TwoByteSequence;
use utf_types::utf8::UnconstrainedContinuation;
#[derive(Debug)]
pub struct CharsWithHandler<'a, H>
where
H: Utf8Handler,
{
inner: core::slice::Iter<'a, u8>,
handler: H,
}
impl<'a, H> CharsWithHandler<'a, H>
where
H: Utf8Handler,
{
#[inline(always)]
pub fn new(s: &'a str, handler: H) -> Self {
CharsWithHandler::<'a, H> {
inner: s.as_bytes().iter(),
handler,
}
}
#[inline(always)]
pub fn as_str(&self) -> &'a str {
unsafe { core::str::from_utf8_unchecked(self.inner.as_slice()) }
}
#[inline(always)]
pub fn handler(&self) -> &H {
&self.handler
}
#[inline(always)]
pub fn next_with_minimum_lead(
&mut self,
multi_byte_lead: LeadForMultiByte,
) -> Option<H::Output> {
let bound = multi_byte_lead.to_u8();
loop {
let byte = *self.inner.next()?;
if byte < bound {
continue;
}
return Some(unsafe { self.consume_continuations(byte) });
}
}
#[inline(always)]
unsafe fn consume_continuations(&mut self, first: u8) -> H::Output {
debug_assert!(LeadForMultiByte::is(first));
let second = *unsafe { self.inner.next().unwrap_unchecked() };
if first < LeadForThreeByte::MIN as u8 {
return self.handler.two_byte(
unsafe { TwoByteSequence::new_unchecked(first, second) },
);
}
let third = *unsafe { self.inner.next().unwrap_unchecked() };
if first < LeadForFourByte::MIN as u8 {
return self.handler.three_byte(unsafe {
ThreeByteSequence::new_unchecked(first, second, third)
});
}
let fourth = *unsafe { self.inner.next().unwrap_unchecked() };
self.handler.four_byte(
unsafe { FourByteSequence::new_unchecked(first, second, third, fourth) },
)
}
}
impl<'a, H> Clone for CharsWithHandler<'a, H>
where
H: Utf8Handler + Clone,
{
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
handler: self.handler.clone(),
}
}
}
impl<'a, H> Iterator for CharsWithHandler<'a, H>
where
H: Utf8Handler,
{
type Item = H::Output;
#[inline(always)]
fn next(&mut self) -> Option<H::Output> {
let first = *self.inner.next()?;
if let Ok(ascii) = Ascii::try_new(first) {
return Some(self.handler.single_byte(ascii));
}
Some(unsafe { self.consume_continuations(first) })
}
#[inline(always)]
fn count(self) -> usize {
self.as_str().chars().count()
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.as_str().len();
(len.div_ceil(4), Some(len))
}
#[inline(always)]
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
}
impl<'a, H> DoubleEndedIterator for CharsWithHandler<'a, H>
where
H: Utf8Handler,
{
#[inline(always)]
fn next_back(&mut self) -> Option<H::Output> {
let last = *self.inner.next_back()?;
if let Ok(ascii) = Ascii::try_new(last) {
return Some(self.handler.single_byte(ascii));
}
debug_assert!(UnconstrainedContinuation::is(last));
let second_last = *unsafe { self.inner.next_back().unwrap_unchecked() };
if !UnconstrainedContinuation::is(second_last) {
return Some(self.handler.two_byte(
unsafe { TwoByteSequence::new_unchecked(second_last, last) },
));
}
let third_last = *unsafe { self.inner.next_back().unwrap_unchecked() };
if !UnconstrainedContinuation::is(third_last) {
return Some(self.handler.three_byte(
unsafe { ThreeByteSequence::new_unchecked(third_last, second_last, last) },
));
}
let fourth_last = *unsafe { self.inner.next_back().unwrap_unchecked() };
Some(self.handler.four_byte(
unsafe { FourByteSequence::new_unchecked(fourth_last, third_last, second_last, last) },
))
}
}
impl<H> core::iter::FusedIterator for CharsWithHandler<'_, H> where H: Utf8Handler {}