use alloc::string::String;
use icu_casemap::CaseMapperBorrowed;
use icu_locale_core::LanguageIdentifier;
use icu_normalizer::ComposingNormalizerBorrowed;
use icu_properties::{
CodePointMapData, CodePointSetData,
props::{Alphabetic, DefaultIgnorableCodePoint, GeneralCategory, Ideographic, Script},
};
use icu_segmenter::{
WordSegmenter, WordSegmenterBorrowed, iterators::WordBreakIterator,
options::WordBreakInvariantOptions, scaffold::Utf8,
};
use writeable::Writeable;
#[derive(Debug)]
pub(super) struct UnicodeBackend {
normalizer: ComposingNormalizerBorrowed<'static>,
case_mapper: CaseMapperBorrowed<'static>,
word_segmenter: WordSegmenterBorrowed<'static>,
root_locale: LanguageIdentifier,
}
impl UnicodeBackend {
pub(super) fn new() -> Self {
Self {
normalizer: ComposingNormalizerBorrowed::new_nfkc(),
case_mapper: CaseMapperBorrowed::new(),
word_segmenter: WordSegmenter::new_auto(WordBreakInvariantOptions::default()),
root_locale: LanguageIdentifier::UNKNOWN,
}
}
#[inline]
pub(super) fn normalize_into(&self, text: &str, output: &mut String) {
output.clear();
let _ = self.normalizer.normalize_to(text, output);
}
#[inline]
pub(super) fn lowercase_into(&self, text: &str, output: &mut String) {
output.clear();
let _ = self
.case_mapper
.lowercase(text, &self.root_locale)
.write_to(output);
}
#[inline]
pub(super) fn word_boundaries<'text>(
&self,
text: &'text str,
) -> WordBreakIterator<'static, 'text, Utf8> {
self.word_segmenter.segment_str(text)
}
#[inline]
pub(super) fn is_default_ignorable(c: char) -> bool {
CodePointSetData::new::<DefaultIgnorableCodePoint>().contains(c)
}
#[inline]
pub(super) fn is_alphabetic(c: char) -> bool {
CodePointSetData::new::<Alphabetic>().contains(c)
}
#[inline]
pub(super) fn is_mark(c: char) -> bool {
matches!(
CodePointMapData::<GeneralCategory>::new().get(c),
GeneralCategory::NonspacingMark
| GeneralCategory::SpacingMark
| GeneralCategory::EnclosingMark
)
}
#[inline]
pub(super) fn is_cjk_unigram(c: char) -> bool {
CodePointSetData::new::<Ideographic>().contains(c)
|| CodePointMapData::<Script>::new().get(c) == Script::Hiragana
}
}
impl Default for UnicodeBackend {
fn default() -> Self {
Self::new()
}
}
impl Clone for UnicodeBackend {
fn clone(&self) -> Self {
Self::new()
}
}