#[inline]
pub fn grapheme_breaks(text: &str) -> GraphemeBreaks<'_> {
GraphemeBreakIter::from_char_indexes(text.char_indices())
}
pub type GraphemeBreaks<'a> = GraphemeBreakIter<std::str::CharIndices<'a>>;
#[derive(Clone, Debug)]
pub struct GraphemeBreakIter<I> {
src: std::iter::Fuse<I>,
last_value: Option<(usize, char)>,
state: GraphemeBreakState,
}
impl<I: Iterator<Item = (usize, char)>> GraphemeBreakIter<I> {
#[inline]
pub fn from_char_indexes(iter: I) -> Self {
GraphemeBreakIter {
src: iter.fuse(),
last_value: None,
state: GraphemeBreakState::new(),
}
}
}
impl<I: Iterator<Item = (usize, char)>> Iterator for GraphemeBreakIter<I> {
type Item = usize;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
loop {
if self.last_value.is_none() {
self.last_value = self.src.next();
}
let (_last_index, last_codepoint) = self.last_value?;
let next_value = self.src.next();
self.last_value = next_value;
let (next_index, next_codepoint) = next_value?;
if grapheme_break_stateful(last_codepoint, next_codepoint, &mut self.state) {
return Some(next_index);
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, self.src.size_hint().1)
}
}
impl<I: Iterator<Item = (usize, char)>> std::iter::FusedIterator for GraphemeBreakIter<I> {}
#[derive(Clone, Debug)]
pub struct GraphemeBreakState(pub(crate) Option<i32>);
impl Default for GraphemeBreakState {
fn default() -> Self {
Self::new()
}
}
impl GraphemeBreakState {
#[inline]
pub const fn new() -> Self {
GraphemeBreakState(Some(0))
}
#[inline]
pub const fn missing() -> Self {
GraphemeBreakState(None)
}
}
#[inline]
pub fn grapheme_break_stateful(codepoint1: char, codepoint2: char, state: &mut GraphemeBreakState) -> bool {
unsafe {
utf8proc_sys::utf8proc_grapheme_break_stateful(
codepoint1 as i32,
codepoint2 as i32,
match state.0 {
Some(ref mut state) => std::ptr::from_mut::<i32>(state),
None => std::ptr::null_mut(),
},
)
}
}