use alloc::vec::Vec;
use icu_provider::prelude::*;
use crate::indices::*;
use crate::provider::*;
use crate::scaffold::*;
#[derive(Debug)]
pub struct GraphemeClusterBreakIterator<'data, 's, Y: RuleBreakType>(
pub(crate) GraphemeClusterBreakIteratorInner<'data, 's, Y>,
);
#[derive(Debug)]
pub(crate) enum GraphemeClusterBreakIteratorInner<'data, 's, Y: RuleBreakType> {
V1(crate::rule_segmenter_v1::RuleBreakIterator<'data, 's, Y>),
#[cfg(feature = "unstable")]
V2(crate::rule_segmenter_v2::RuleBreakIterator<'data, 's, Y>),
}
impl<'data, 's, Y: RuleBreakType> GraphemeClusterBreakIterator<'data, 's, Y> {
pub(crate) fn clone_internal(&self) -> Self {
let inner = match &self.0 {
GraphemeClusterBreakIteratorInner::V1(iter) => {
GraphemeClusterBreakIteratorInner::V1(crate::rule_segmenter_v1::RuleBreakIterator {
iter: iter.iter.clone(),
len: iter.len,
current_pos_data: iter.current_pos_data,
result_cache: iter.result_cache.clone(),
data: iter.data,
complex: iter.complex,
boundary_property: iter.boundary_property,
locale_override: iter.locale_override,
handle_complex: iter.handle_complex,
})
}
#[cfg(feature = "unstable")]
GraphemeClusterBreakIteratorInner::V2(iter) => {
GraphemeClusterBreakIteratorInner::V2(crate::rule_segmenter_v2::RuleBreakIterator {
data: iter.data,
pseudo_symbol_map: iter.pseudo_symbol_map,
cache: iter.cache.clone(),
lookahead_positions: iter.lookahead_positions.clone(),
remaining_input: iter.remaining_input.clone(),
last_accepting_status: iter.last_accepting_status,
complex: iter.complex,
})
}
};
Self(inner)
}
}
impl<Y: RuleBreakType> Iterator for GraphemeClusterBreakIterator<'_, '_, Y> {
type Item = usize;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
match &mut self.0 {
GraphemeClusterBreakIteratorInner::V1(iter) => iter.next(),
#[cfg(feature = "unstable")]
GraphemeClusterBreakIteratorInner::V2(iter) => iter.next(),
}
}
}
#[derive(Debug)]
pub struct GraphemeClusterSegmenter(GraphemeClusterSegmenterInner);
#[derive(Debug)]
enum GraphemeClusterSegmenterInner {
V1(DataPayload<SegmenterBreakGraphemeClusterV1>),
#[cfg(feature = "unstable")]
V2(DataPayload<SegmenterBreakGraphemeClusterV2>),
}
#[derive(Clone, Debug, Copy)]
pub struct GraphemeClusterSegmenterBorrowed<'data>(
pub(crate) GraphemeClusterSegmenterBorrowedInner<'data>,
);
#[derive(Clone, Debug, Copy)]
pub(crate) enum GraphemeClusterSegmenterBorrowedInner<'data> {
V1(&'data RuleBreakData<'data>),
#[cfg(feature = "unstable")]
V2(&'data SegmenterStateMachine<'data>),
}
impl GraphemeClusterSegmenter {
#[cfg(feature = "compiled_data")]
#[expect(clippy::new_ret_no_self)] pub const fn new() -> GraphemeClusterSegmenterBorrowed<'static> {
GraphemeClusterSegmenterBorrowed(GraphemeClusterSegmenterBorrowedInner::V1(
Baked::SINGLETON_SEGMENTER_BREAK_GRAPHEME_CLUSTER_V1,
))
}
icu_provider::gen_buffer_data_constructors!(() -> error: DataError,
functions: [
new: skip,
try_new_with_buffer_provider,
try_new_unstable,
Self,
]);
#[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new)]
pub fn try_new_unstable<D>(provider: &D) -> Result<Self, DataError>
where
D: DataProvider<SegmenterBreakGraphemeClusterV1> + ?Sized,
{
let payload = provider.load(Default::default())?.payload;
Ok(Self(GraphemeClusterSegmenterInner::V1(payload)))
}
#[cfg(feature = "compiled_data")]
#[cfg(feature = "unstable")]
pub const fn new_neo() -> GraphemeClusterSegmenterBorrowed<'static> {
GraphemeClusterSegmenterBorrowed(GraphemeClusterSegmenterBorrowedInner::V2(
Baked::SINGLETON_SEGMENTER_BREAK_GRAPHEME_CLUSTER_V2,
))
}
#[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new_neo)]
#[cfg(feature = "unstable")]
pub fn try_new_neo_unstable<D>(provider: &D) -> Result<Self, DataError>
where
D: DataProvider<SegmenterBreakGraphemeClusterV2> + ?Sized,
{
let payload = provider.load(Default::default())?.payload;
Ok(Self(GraphemeClusterSegmenterInner::V2(payload)))
}
pub fn as_borrowed(&self) -> GraphemeClusterSegmenterBorrowed<'_> {
GraphemeClusterSegmenterBorrowed(match &self.0 {
GraphemeClusterSegmenterInner::V1(payload) => {
GraphemeClusterSegmenterBorrowedInner::V1(payload.get())
}
#[cfg(feature = "unstable")]
GraphemeClusterSegmenterInner::V2(payload) => {
GraphemeClusterSegmenterBorrowedInner::V2(payload.get())
}
})
}
}
impl<'data> GraphemeClusterSegmenterBorrowed<'data> {
pub(crate) fn segment<'s, Y: RuleBreakType>(
self,
iter: Y::IterAttr<'s>,
len: usize,
) -> GraphemeClusterBreakIterator<'data, 's, Y> {
GraphemeClusterBreakIterator(match self.0 {
GraphemeClusterSegmenterBorrowedInner::V1(data) => {
GraphemeClusterBreakIteratorInner::V1(crate::rule_segmenter_v1::RuleBreakIterator {
iter,
len,
current_pos_data: None,
result_cache: Vec::new(),
data,
complex: None,
boundary_property: 0,
locale_override: None,
handle_complex: crate::rule_segmenter_v1::empty_handle_complex,
})
}
#[cfg(feature = "unstable")]
GraphemeClusterSegmenterBorrowedInner::V2(data) => {
GraphemeClusterBreakIteratorInner::V2(
crate::rule_segmenter_v2::RuleBreakIterator::new(iter, data, None, None),
)
}
})
}
pub fn segment_str<'s>(self, input: &'s str) -> GraphemeClusterBreakIterator<'data, 's, Utf8> {
self.segment(input.char_indices(), input.len())
}
pub fn segment_utf8<'s>(
self,
input: &'s [u8],
) -> GraphemeClusterBreakIterator<'data, 's, PotentiallyIllFormedUtf8> {
self.segment(Utf8CharIndices::new(input), input.len())
}
pub fn segment_latin1<'s>(
self,
input: &'s [u8],
) -> GraphemeClusterBreakIterator<'data, 's, Latin1> {
self.segment(Latin1Indices::new(input), input.len())
}
pub fn segment_utf16<'s>(
self,
input: &'s [u16],
) -> GraphemeClusterBreakIterator<'data, 's, Utf16> {
self.segment(Utf16Indices::new(input), input.len())
}
}
impl GraphemeClusterSegmenterBorrowed<'static> {
pub const fn static_to_owned(self) -> GraphemeClusterSegmenter {
GraphemeClusterSegmenter(match self.0 {
GraphemeClusterSegmenterBorrowedInner::V1(data) => {
GraphemeClusterSegmenterInner::V1(DataPayload::from_static_ref(data))
}
#[cfg(feature = "unstable")]
GraphemeClusterSegmenterBorrowedInner::V2(data) => {
GraphemeClusterSegmenterInner::V2(DataPayload::from_static_ref(data))
}
})
}
}
#[cfg(test)]
mod test {
use crate::*;
include!("../tests/helpers.rs.raw");
#[test]
fn empty_string() {
let segmenter = GraphemeClusterSegmenter::new();
let breaks: Vec<usize> = segmenter.segment_str("").collect();
assert_eq!(breaks, [0]);
}
#[test]
fn emoji_flags() {
check_grapheme("🇺🇸🏴", &["🇺🇸", "🏴"], GraphemeClusterSegmenter::new());
}
#[test]
fn empty_string_neo() {
let segmenter = GraphemeClusterSegmenter::new_neo();
let breaks: Vec<usize> = segmenter.segment_str("").collect();
assert_eq!(breaks, [0]);
}
#[test]
fn emoji_flags_neo() {
check_grapheme("🇺🇸🏴", &["🇺🇸", "🏴"], GraphemeClusterSegmenter::new_neo());
}
}