use crate::{GraphemeProps, GraphemeScanner, Mem, charu, impl_trait};
mod state;
use state::GraphemeMachineState;
#[cfg(test)]
mod tests;
#[doc = crate::_tags!(text)]
#[doc = concat!["Streaming ", crate::_ABBR_EGC!(), " boundary detector."]]
#[doc = crate::_doc_location!("text/grapheme")]
#[doc = crate::_doc!(vendor: "grapheme_machine")]
#[derive(Clone, Copy, Debug, Default, Eq)]
pub struct GraphemeMachine {
state: GraphemeMachineState,
prev: Option<GraphemeProps>,
}
impl_trait! { PartialEq for GraphemeMachine |self, other| Self::eq(*self, *other) }
impl_trait! { Hash for GraphemeMachine |self, state| {
self.state.hash(state); self.prev.hash(state);
} }
impl GraphemeMachine {
pub const fn new() -> Self {
GraphemeMachine { state: GraphemeMachineState::Base, prev: None }
}
pub const fn next_char_properties(&mut self, next: GraphemeProps) -> GraphemeBoundary {
let (boundary, next_state) = self.state.transition(self.prev, next);
self.state = next_state;
self.prev = Some(next);
if boundary { GraphemeBoundary::Split } else { GraphemeBoundary::Continue }
}
pub const fn next_charu(&mut self, c: charu) -> GraphemeBoundary {
let props = GraphemeProps::for_charu(c);
self.next_char_properties(props)
}
pub const fn next_char(&mut self, c: char) -> GraphemeBoundary {
let props = GraphemeProps::for_char(c);
self.next_char_properties(props)
}
pub const fn next_charu_from_str<'a>(&'a mut self, s: &'a str) -> GraphemeScanner<'a, charu> {
GraphemeScanner::<charu>::new(self, s)
}
pub const fn next_char_from_str<'a>(&'a mut self, s: &'a str) -> GraphemeScanner<'a, char> {
GraphemeScanner::<char>::new(self, s)
}
pub const fn end_of_input(&mut self) -> GraphemeBoundary {
self.state = GraphemeMachineState::Base;
self.prev = None;
GraphemeBoundary::Split
}
pub const fn eq(self, other: Self) -> bool {
self.state.eq(other.state)
&& match (self.prev, other.prev) {
(Some(prev), Some(other_prev)) => prev.eq(other_prev),
(None, None) => true,
_ => false,
}
}
}
#[doc = crate::_tags!(text)]
#[doc = crate::_doc_location!("text/grapheme")]
#[doc = crate::_doc!(vendor: "grapheme_machine")]
#[derive(Debug, Clone, Copy, Eq)]
pub enum GraphemeBoundary {
Continue,
Split,
}
impl_trait! { PartialEq for GraphemeBoundary |self, other| Self::eq(*self, *other) }
impl_trait! { Hash for GraphemeBoundary |self, state| { Mem::discriminant(self).hash(state); } }
impl GraphemeBoundary {
pub const fn eq(self, other: Self) -> bool {
matches!((self, other), (Self::Continue, Self::Continue) | (Self::Split, Self::Split))
}
}