use alloc::vec::Vec;
use icu_provider::prelude::*;
use crate::indices::{Latin1Indices, Utf16Indices};
use crate::iterator_helpers::derive_usize_iterator_with_type;
use crate::provider::*;
use crate::rule_segmenter::*;
use utf8_iter::Utf8CharIndices;
#[derive(Debug)]
pub struct GraphemeClusterBreakIterator<'l, 's, Y: RuleBreakType<'l, 's> + ?Sized>(
RuleBreakIterator<'l, 's, Y>,
);
derive_usize_iterator_with_type!(GraphemeClusterBreakIterator);
pub type GraphemeClusterBreakIteratorUtf8<'l, 's> =
GraphemeClusterBreakIterator<'l, 's, RuleBreakTypeUtf8>;
pub type GraphemeClusterBreakIteratorPotentiallyIllFormedUtf8<'l, 's> =
GraphemeClusterBreakIterator<'l, 's, RuleBreakTypePotentiallyIllFormedUtf8>;
pub type GraphemeClusterBreakIteratorLatin1<'l, 's> =
GraphemeClusterBreakIterator<'l, 's, RuleBreakTypeLatin1>;
pub type GraphemeClusterBreakIteratorUtf16<'l, 's> =
GraphemeClusterBreakIterator<'l, 's, RuleBreakTypeUtf16>;
#[derive(Debug)]
pub struct GraphemeClusterSegmenter {
payload: DataPayload<GraphemeClusterBreakDataV2>,
}
impl GraphemeClusterSegmenter {
#[cfg(feature = "compiled_data")]
#[allow(clippy::new_without_default)] pub fn new() -> Self {
Self {
payload: DataPayload::from_static_ref(
crate::provider::Baked::SINGLETON_GRAPHEME_CLUSTER_BREAK_DATA_V2,
),
}
}
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<GraphemeClusterBreakDataV2> + ?Sized,
{
let payload = provider.load(Default::default())?.payload;
Ok(Self { payload })
}
pub fn segment_str<'l, 's>(
&'l self,
input: &'s str,
) -> GraphemeClusterBreakIteratorUtf8<'l, 's> {
GraphemeClusterSegmenter::new_and_segment_str(input, self.payload.get())
}
pub(crate) fn new_and_segment_str<'l, 's>(
input: &'s str,
payload: &'l RuleBreakData<'l>,
) -> GraphemeClusterBreakIteratorUtf8<'l, 's> {
GraphemeClusterBreakIterator(RuleBreakIterator {
iter: input.char_indices(),
len: input.len(),
current_pos_data: None,
result_cache: Vec::new(),
data: payload,
complex: None,
boundary_property: 0,
locale_override: None,
})
}
pub fn segment_utf8<'l, 's>(
&'l self,
input: &'s [u8],
) -> GraphemeClusterBreakIteratorPotentiallyIllFormedUtf8<'l, 's> {
GraphemeClusterBreakIterator(RuleBreakIterator {
iter: Utf8CharIndices::new(input),
len: input.len(),
current_pos_data: None,
result_cache: Vec::new(),
data: self.payload.get(),
complex: None,
boundary_property: 0,
locale_override: None,
})
}
pub fn segment_latin1<'l, 's>(
&'l self,
input: &'s [u8],
) -> GraphemeClusterBreakIteratorLatin1<'l, 's> {
GraphemeClusterBreakIterator(RuleBreakIterator {
iter: Latin1Indices::new(input),
len: input.len(),
current_pos_data: None,
result_cache: Vec::new(),
data: self.payload.get(),
complex: None,
boundary_property: 0,
locale_override: None,
})
}
pub fn segment_utf16<'l, 's>(
&'l self,
input: &'s [u16],
) -> GraphemeClusterBreakIteratorUtf16<'l, 's> {
GraphemeClusterSegmenter::new_and_segment_utf16(input, self.payload.get())
}
pub(crate) fn new_and_segment_utf16<'l, 's>(
input: &'s [u16],
payload: &'l RuleBreakData<'l>,
) -> GraphemeClusterBreakIteratorUtf16<'l, 's> {
GraphemeClusterBreakIterator(RuleBreakIterator {
iter: Utf16Indices::new(input),
len: input.len(),
current_pos_data: None,
result_cache: Vec::new(),
data: payload,
complex: None,
boundary_property: 0,
locale_override: None,
})
}
}
#[test]
fn empty_string() {
let segmenter = GraphemeClusterSegmenter::new();
let breaks: Vec<usize> = segmenter.segment_str("").collect();
assert_eq!(breaks, [0]);
}
#[test]
fn emoji_flags() {
let segmenter = GraphemeClusterSegmenter::new();
let breaks: Vec<usize> = segmenter.segment_str("🇺🇸🏴").collect();
assert_eq!(breaks, [0, 8, 36]);
}