use crate::complex::*;
use crate::indices::*;
use crate::provider::*;
use crate::scaffold::*;
use icu_locale_core::LanguageIdentifier;
use icu_locale_core::subtags::{Language, language};
use icu_provider::prelude::*;
mod v1;
#[cfg(any(feature = "unstable", feature = "datagen"))]
#[cfg_attr(not(feature = "unstable"), allow(dead_code))]
mod v3;
#[non_exhaustive]
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
pub enum LineBreakStrictness {
Loose,
Normal,
#[default]
Strict,
Anywhere,
}
#[non_exhaustive]
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
pub enum LineBreakWordOption {
#[default]
Normal,
BreakAll,
KeepAll,
}
#[non_exhaustive]
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
pub struct LineBreakOptions<'a> {
pub strictness: Option<LineBreakStrictness>,
pub word_option: Option<LineBreakWordOption>,
pub content_locale: Option<&'a LanguageIdentifier>,
}
impl LineBreakOptions<'_> {
pub const fn default() -> Self {
Self {
strictness: None,
word_option: None,
content_locale: None,
}
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct ResolvedLineBreakOptions {
pub(crate) strictness: LineBreakStrictness,
pub(crate) word_option: LineBreakWordOption,
pub(crate) ja_zh: bool,
}
impl LineBreakOptions<'_> {
pub(crate) const fn resolve(self) -> ResolvedLineBreakOptions {
ResolvedLineBreakOptions {
strictness: match self.strictness {
Some(s) => s,
None => LineBreakStrictness::Strict,
},
word_option: match self.word_option {
Some(s) => s,
None => LineBreakWordOption::Normal,
},
ja_zh: if let Some(content_locale) = self.content_locale.as_ref() {
const JA: Language = language!("ja");
const ZH: Language = language!("zh");
matches!(content_locale.language, JA | ZH)
} else {
false
},
}
}
}
#[derive(Debug)]
pub struct LineSegmenter(LineSegmenterInner);
#[derive(Debug)]
enum LineSegmenterInner {
V1 {
options: ResolvedLineBreakOptions,
data: DataPayload<SegmenterBreakLineV1>,
complex: ComplexPayloads,
},
#[cfg(feature = "unstable")]
V2 {
data: DataPayload<SegmenterBreakLineV2>,
tailoring: Option<DataPayload<SegmenterBreakLineOverrideV2>>,
complex: ComplexPayloads,
},
#[cfg(feature = "unstable")]
V3 {
options: ResolvedLineBreakOptions,
data: DataPayload<SegmenterBreakLineV3>,
complex: ComplexPayloads,
},
}
#[derive(Clone, Debug, Copy)]
pub struct LineSegmenterBorrowed<'data>(LineSegmenterBorrowedInner<'data>);
#[derive(Debug, Clone, Copy)]
enum LineSegmenterBorrowedInner<'data> {
V1 {
options: ResolvedLineBreakOptions,
data: &'data RuleBreakData<'data>,
complex: ComplexPayloadsBorrowed<'data>,
},
#[cfg(feature = "unstable")]
V2 {
data: &'data SegmenterStateMachine<'data>,
tailoring: Option<&'data SegmenterStateMachineOverride<'data>>,
complex: ComplexPayloadsBorrowed<'data>,
},
#[cfg(feature = "unstable")]
V3 {
options: ResolvedLineBreakOptions,
data: &'data RuleBreakData<'data>,
complex: ComplexPayloadsBorrowed<'data>,
},
}
impl LineSegmenter {
#[cfg(feature = "auto")]
#[cfg(feature = "compiled_data")]
pub fn new_auto(options: LineBreakOptions) -> LineSegmenterBorrowed<'static> {
Self::new_lstm(options)
}
#[cfg(feature = "auto")]
icu_provider::gen_buffer_data_constructors!(
(options: LineBreakOptions) -> error: DataError,
functions: [
new_auto: skip,
try_new_auto_with_buffer_provider,
try_new_auto_unstable,
Self,
]
);
#[cfg(feature = "auto")]
#[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new_auto)]
pub fn try_new_auto_unstable<D>(
provider: &D,
options: LineBreakOptions,
) -> Result<Self, DataError>
where
D: DataProvider<SegmenterBreakLineV1>
+ DataProvider<SegmenterLstmAutoV1>
+ DataProvider<SegmenterBreakGraphemeClusterV1>
+ ?Sized,
{
Self::try_new_lstm_unstable(provider, options)
}
#[cfg(feature = "lstm")]
#[cfg(feature = "compiled_data")]
pub fn new_lstm(options: LineBreakOptions) -> LineSegmenterBorrowed<'static> {
let mut s = Self::new_for_non_complex_scripts(options);
s.load_lstm();
s
}
#[cfg(feature = "lstm")]
icu_provider::gen_buffer_data_constructors!(
(options: LineBreakOptions) -> error: DataError,
functions: [
try_new_lstm: skip,
try_new_lstm_with_buffer_provider,
try_new_lstm_unstable,
Self,
]
);
#[cfg(feature = "lstm")]
#[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new_lstm)]
pub fn try_new_lstm_unstable<D>(
provider: &D,
options: LineBreakOptions,
) -> Result<Self, DataError>
where
D: DataProvider<SegmenterBreakLineV1>
+ DataProvider<SegmenterLstmAutoV1>
+ DataProvider<SegmenterBreakGraphemeClusterV1>
+ ?Sized,
{
let mut s = Self::try_new_for_non_complex_scripts_unstable(provider, options)?;
s.load_lstm_unstable(provider)?;
Ok(s)
}
#[cfg(feature = "compiled_data")]
pub fn new_dictionary(options: LineBreakOptions) -> LineSegmenterBorrowed<'static> {
let mut s = Self::new_for_non_complex_scripts(options);
s.load_dictionary();
s
}
icu_provider::gen_buffer_data_constructors!(
(options: LineBreakOptions) -> error: DataError,
functions: [
new_dictionary: skip,
try_new_dictionary_with_buffer_provider,
try_new_dictionary_unstable,
Self,
]
);
#[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new_dictionary)]
pub fn try_new_dictionary_unstable<D>(
provider: &D,
options: LineBreakOptions,
) -> Result<Self, DataError>
where
D: DataProvider<SegmenterBreakLineV1>
+ DataProvider<SegmenterDictionaryExtendedV1>
+ DataProvider<SegmenterBreakGraphemeClusterV1>
+ ?Sized,
{
let mut s = Self::try_new_for_non_complex_scripts_unstable(provider, options)?;
s.load_dictionary_unstable(provider)?;
Ok(s)
}
#[cfg(feature = "compiled_data")]
pub const fn new_for_non_complex_scripts(
options: LineBreakOptions,
) -> LineSegmenterBorrowed<'static> {
LineSegmenterBorrowed(LineSegmenterBorrowedInner::V1 {
options: options.resolve(),
data: Baked::SINGLETON_SEGMENTER_BREAK_LINE_V1,
complex: ComplexPayloadsBorrowed::new(),
})
}
#[cfg(feature = "unstable")]
#[cfg(feature = "compiled_data")]
pub const fn new_17_for_non_complex_scripts(
options: LineBreakOptions,
) -> LineSegmenterBorrowed<'static> {
LineSegmenterBorrowed(LineSegmenterBorrowedInner::V3 {
options: options.resolve(),
data: Baked::SINGLETON_SEGMENTER_BREAK_LINE_V3,
complex: ComplexPayloadsBorrowed::new(),
})
}
icu_provider::gen_buffer_data_constructors!(
(options: LineBreakOptions) -> error: DataError,
functions: [
new_for_non_complex_scripts: skip,
try_new_for_non_complex_scripts_with_buffer_provider,
try_new_for_non_complex_scripts_unstable,
Self,
]
);
#[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new_for_non_complex_scripts)]
pub fn try_new_for_non_complex_scripts_unstable<D>(
provider: &D,
options: LineBreakOptions,
) -> Result<Self, DataError>
where
D: DataProvider<SegmenterBreakLineV1>
+ DataProvider<SegmenterBreakGraphemeClusterV1>
+ ?Sized,
{
Ok(Self(LineSegmenterInner::V1 {
data: provider.load(Default::default())?.payload,
options: options.resolve(),
complex: ComplexPayloads::try_new(provider)?,
}))
}
#[cfg(feature = "unstable")]
#[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new_17_for_non_complex_scripts)]
pub fn try_new_17_for_non_complex_script_unstable<D>(
provider: &D,
options: LineBreakOptions,
) -> Result<Self, DataError>
where
D: DataProvider<SegmenterBreakLineV3>
+ DataProvider<SegmenterBreakGraphemeClusterV1>
+ ?Sized,
{
Ok(Self(LineSegmenterInner::V3 {
data: provider.load(Default::default())?.payload,
options: options.resolve(),
complex: ComplexPayloads::try_new(provider)?,
}))
}
#[cfg(feature = "compiled_data")]
#[cfg(feature = "unstable")]
pub const fn new_neo_for_non_complex_scripts(
options: LineBreakOptions,
) -> LineSegmenterBorrowed<'static> {
const _: () = assert!(
Baked::SEGMENTER_BREAK_LINE_V2_CHECKSUM
== Baked::SEGMENTER_BREAK_LINE_OVERRIDE_V2_CHECKSUM
);
let options = options.resolve();
LineSegmenterBorrowed(LineSegmenterBorrowedInner::V2 {
data: Baked::SINGLETON_SEGMENTER_BREAK_LINE_V2,
tailoring: match (options.ja_zh, options.strictness, options.word_option) {
(_, _, LineBreakWordOption::BreakAll) => {
Some(Baked::SEGMENTER_BREAK_LINE_OVERRIDE_V2_UND_BREAKALL)
}
(_, _, LineBreakWordOption::KeepAll) => {
Some(Baked::SEGMENTER_BREAK_LINE_OVERRIDE_V2_UND_KEEPALL)
}
(true, LineBreakStrictness::Loose, LineBreakWordOption::Normal) => {
Some(Baked::SEGMENTER_BREAK_LINE_OVERRIDE_V2_UND_JA_LOOSE)
}
(false, LineBreakStrictness::Loose, LineBreakWordOption::Normal) => {
Some(Baked::SEGMENTER_BREAK_LINE_OVERRIDE_V2_UND_LOOSE)
}
(true, LineBreakStrictness::Normal, LineBreakWordOption::Normal) => {
Some(Baked::SEGMENTER_BREAK_LINE_OVERRIDE_V2_UND_JA_NORMAL)
}
(false, LineBreakStrictness::Normal, LineBreakWordOption::Normal) => {
Some(Baked::SEGMENTER_BREAK_LINE_OVERRIDE_V2_UND_NORMAL)
}
(true, LineBreakStrictness::Strict, LineBreakWordOption::Normal) => {
Some(Baked::SEGMENTER_BREAK_LINE_OVERRIDE_V2_UND_JA)
}
(false, LineBreakStrictness::Strict, LineBreakWordOption::Normal) => None,
(_, LineBreakStrictness::Anywhere, _) => {
return LineSegmenterBorrowed(LineSegmenterBorrowedInner::V2 {
data: Baked::SINGLETON_SEGMENTER_BREAK_GRAPHEME_CLUSTER_V2,
tailoring: None,
complex: ComplexPayloadsBorrowed::new_neo(),
});
}
},
complex: ComplexPayloadsBorrowed::new_neo(),
})
}
#[cfg(feature = "unstable")]
#[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new_neo_for_non_complex_scripts)]
pub fn try_new_neo_for_non_complex_scripts_unstable<D>(
provider: &D,
options: LineBreakOptions,
) -> Result<Self, DataError>
where
D: DataProvider<SegmenterBreakLineV2>
+ DataProvider<SegmenterBreakGraphemeClusterV2>
+ DataProvider<SegmenterBreakLineOverrideV2>
+ ?Sized,
{
let options = options.resolve();
let data = provider.load(Default::default())?;
let id = match (options.ja_zh, options.strictness, options.word_option) {
(_, _, LineBreakWordOption::BreakAll) => {
Some(const { DataMarkerAttributes::from_str_or_panic("breakall") })
}
(_, _, LineBreakWordOption::KeepAll) => {
Some(const { DataMarkerAttributes::from_str_or_panic("keepall") })
}
(true, LineBreakStrictness::Loose, LineBreakWordOption::Normal) => {
Some(const { DataMarkerAttributes::from_str_or_panic("ja-loose") })
}
(false, LineBreakStrictness::Loose, LineBreakWordOption::Normal) => {
Some(const { DataMarkerAttributes::from_str_or_panic("loose") })
}
(true, LineBreakStrictness::Normal, LineBreakWordOption::Normal) => {
Some(const { DataMarkerAttributes::from_str_or_panic("ja-normal") })
}
(false, LineBreakStrictness::Normal, LineBreakWordOption::Normal) => {
Some(const { DataMarkerAttributes::from_str_or_panic("normal") })
}
(true, LineBreakStrictness::Strict, LineBreakWordOption::Normal) => {
Some(const { DataMarkerAttributes::from_str_or_panic("ja") })
}
(false, LineBreakStrictness::Strict, LineBreakWordOption::Normal) => None,
(_, LineBreakStrictness::Anywhere, _) => {
return Ok(Self(LineSegmenterInner::V2 {
data: DataProvider::<SegmenterBreakGraphemeClusterV2>::load(
provider,
Default::default(),
)?
.payload
.cast(),
tailoring: None,
complex: ComplexPayloads::try_new_neo(provider)?,
}));
}
};
let tailoring = id
.map(|id| {
provider.load(DataRequest {
id: DataIdentifierBorrowed::for_marker_attributes(id),
metadata: Default::default(),
})
})
.transpose()?;
if let Some(ref tailoring) = tailoring
&& let Some(id) = id
&& data.metadata.checksum != tailoring.metadata.checksum
{
return Err(
DataErrorKind::InconsistentData(SegmenterBreakLineV2::INFO).with_req(
SegmenterBreakLineOverrideV2::INFO,
DataRequest {
id: DataIdentifierBorrowed::for_marker_attributes(id),
metadata: Default::default(),
},
),
);
}
Ok(Self(LineSegmenterInner::V2 {
data: data.payload,
complex: ComplexPayloads::try_new_neo(provider)?,
tailoring: tailoring.map(|d| d.payload),
}))
}
#[cfg(feature = "lstm")]
pub fn load_lstm_unstable<D>(&mut self, provider: &D) -> Result<(), DataError>
where
D: DataProvider<SegmenterLstmAutoV1> + ?Sized,
{
match self.0 {
LineSegmenterInner::V1 {
ref mut complex, ..
} => complex,
#[cfg(feature = "unstable")]
LineSegmenterInner::V2 {
ref mut complex, ..
} => complex,
#[cfg(feature = "unstable")]
LineSegmenterInner::V3 {
ref mut complex, ..
} => complex,
}
.with_southeast_asian_lstms(provider)
}
#[cfg(feature = "serde")]
#[cfg(feature = "lstm")]
pub fn load_lstm_with_buffer_provider(
&mut self,
provider: &(impl BufferProvider + ?Sized),
) -> Result<(), DataError> {
self.load_lstm_unstable(&provider.as_deserializing())
}
pub fn load_dictionary_unstable<D>(&mut self, provider: &D) -> Result<(), DataError>
where
D: DataProvider<SegmenterDictionaryExtendedV1> + ?Sized,
{
match self.0 {
LineSegmenterInner::V1 {
ref mut complex, ..
} => complex,
#[cfg(feature = "unstable")]
LineSegmenterInner::V2 {
ref mut complex, ..
} => complex,
#[cfg(feature = "unstable")]
LineSegmenterInner::V3 {
ref mut complex, ..
} => complex,
}
.with_southeast_asian_dictionaries(provider)
}
#[cfg(feature = "serde")]
pub fn load_dictionary_with_buffer_provider(
&mut self,
provider: &(impl BufferProvider + ?Sized),
) -> Result<(), DataError> {
self.load_dictionary_unstable(&provider.as_deserializing())
}
pub fn as_borrowed(&self) -> LineSegmenterBorrowed<'_> {
LineSegmenterBorrowed(match &self.0 {
LineSegmenterInner::V1 {
data,
options,
complex,
} => LineSegmenterBorrowedInner::V1 {
options: *options,
data: data.get(),
complex: complex.as_borrowed(),
},
#[cfg(feature = "unstable")]
LineSegmenterInner::V2 {
data,
tailoring,
complex,
} => LineSegmenterBorrowedInner::V2 {
data: data.get(),
tailoring: tailoring.as_ref().map(|t| t.get()),
complex: complex.as_borrowed(),
},
#[cfg(feature = "unstable")]
LineSegmenterInner::V3 {
data,
options,
complex,
} => LineSegmenterBorrowedInner::V3 {
options: *options,
data: data.get(),
complex: complex.as_borrowed(),
},
})
}
}
impl<'data> LineSegmenterBorrowed<'data> {
pub fn segment_str<'s>(self, input: &'s str) -> LineBreakIterator<'data, 's, Utf8> {
LineBreakIterator(match self.0 {
LineSegmenterBorrowedInner::V1 {
options,
data,
complex,
} => LineBreakIteratorInner::V1(v1::LineBreakIteratorV1::new(
input.char_indices(),
input.len(),
data,
options,
complex,
v1::line_handle_complex_utf8,
)),
#[cfg(feature = "unstable")]
LineSegmenterBorrowedInner::V2 {
data,
tailoring,
complex,
} => LineBreakIteratorInner::V2(crate::rule_segmenter_v2::RuleBreakIterator::new(
input.char_indices(),
data,
tailoring,
Some(complex),
)),
#[cfg(feature = "unstable")]
LineSegmenterBorrowedInner::V3 {
options,
data,
complex,
} => LineBreakIteratorInner::V3(v3::LineBreakIteratorV3::new(
input.char_indices(),
input.len(),
data,
options,
complex,
v3::line_handle_complex_utf8,
)),
})
}
pub fn segment_utf8<'s>(
self,
input: &'s [u8],
) -> LineBreakIterator<'data, 's, PotentiallyIllFormedUtf8> {
LineBreakIterator(match self.0 {
LineSegmenterBorrowedInner::V1 {
data,
options,
complex,
} => LineBreakIteratorInner::V1(v1::LineBreakIteratorV1::new(
Utf8CharIndices::new(input),
input.len(),
data,
options,
complex,
v1::line_handle_complex_utf8,
)),
#[cfg(feature = "unstable")]
LineSegmenterBorrowedInner::V2 {
data,
tailoring,
complex,
} => LineBreakIteratorInner::V2(crate::rule_segmenter_v2::RuleBreakIterator::new(
Utf8CharIndices::new(input),
data,
tailoring,
Some(complex),
)),
#[cfg(feature = "unstable")]
LineSegmenterBorrowedInner::V3 {
data,
options,
complex,
} => LineBreakIteratorInner::V3(v3::LineBreakIteratorV3::new(
Utf8CharIndices::new(input),
input.len(),
data,
options,
complex,
v3::line_handle_complex_utf8,
)),
})
}
pub fn segment_latin1<'s>(self, input: &'s [u8]) -> LineBreakIterator<'data, 's, Latin1> {
LineBreakIterator(match self.0 {
LineSegmenterBorrowedInner::V1 {
data,
options,
complex,
} => LineBreakIteratorInner::V1(v1::LineBreakIteratorV1::new(
Latin1Indices::new(input),
input.len(),
data,
options,
complex,
|_, _| None,
)),
#[cfg(feature = "unstable")]
LineSegmenterBorrowedInner::V2 {
data, tailoring, ..
} => LineBreakIteratorInner::V2(crate::rule_segmenter_v2::RuleBreakIterator::new(
Latin1Indices::new(input),
data,
tailoring,
None,
)),
#[cfg(feature = "unstable")]
LineSegmenterBorrowedInner::V3 {
data,
options,
complex,
} => LineBreakIteratorInner::V3(v3::LineBreakIteratorV3::new(
Latin1Indices::new(input),
input.len(),
data,
options,
complex,
|_, _| None,
)),
})
}
pub fn segment_utf16<'s>(self, input: &'s [u16]) -> LineBreakIterator<'data, 's, Utf16> {
LineBreakIterator(match self.0 {
LineSegmenterBorrowedInner::V1 {
data,
options,
complex,
} => LineBreakIteratorInner::V1(v1::LineBreakIteratorV1::new(
Utf16Indices::new(input),
input.len(),
data,
options,
complex,
v1::line_handle_complex_utf16,
)),
#[cfg(feature = "unstable")]
LineSegmenterBorrowedInner::V2 {
data,
tailoring,
complex,
} => LineBreakIteratorInner::V2(crate::rule_segmenter_v2::RuleBreakIterator::new(
Utf16Indices::new(input),
data,
tailoring,
Some(complex),
)),
#[cfg(feature = "unstable")]
LineSegmenterBorrowedInner::V3 {
data,
options,
complex,
} => LineBreakIteratorInner::V3(v3::LineBreakIteratorV3::new(
Utf16Indices::new(input),
input.len(),
data,
options,
complex,
v3::line_handle_complex_utf16,
)),
})
}
}
impl LineSegmenterBorrowed<'static> {
#[cfg(feature = "lstm")]
#[cfg(feature = "compiled_data")]
pub fn load_lstm(&mut self) {
match self.0 {
LineSegmenterBorrowedInner::V1 {
ref mut complex, ..
} => complex,
#[cfg(feature = "unstable")]
LineSegmenterBorrowedInner::V2 {
ref mut complex, ..
} => complex,
#[cfg(feature = "unstable")]
LineSegmenterBorrowedInner::V3 {
ref mut complex, ..
} => complex,
}
.with_southeast_asian_lstms()
}
#[cfg(feature = "compiled_data")]
pub fn load_dictionary(&mut self) {
match self.0 {
LineSegmenterBorrowedInner::V1 {
ref mut complex, ..
} => complex,
#[cfg(feature = "unstable")]
LineSegmenterBorrowedInner::V2 {
ref mut complex, ..
} => complex,
#[cfg(feature = "unstable")]
LineSegmenterBorrowedInner::V3 {
ref mut complex, ..
} => complex,
}
.with_southeast_asian_dictionaries()
}
pub fn static_to_owned(self) -> LineSegmenter {
LineSegmenter(match self.0 {
LineSegmenterBorrowedInner::V1 {
data,
options,
complex,
} => LineSegmenterInner::V1 {
data: DataPayload::from_static_ref(data),
complex: complex.static_to_owned(),
options,
},
#[cfg(feature = "unstable")]
LineSegmenterBorrowedInner::V2 {
data,
tailoring,
complex,
} => LineSegmenterInner::V2 {
data: DataPayload::from_static_ref(data),
complex: complex.static_to_owned(),
tailoring: tailoring.map(DataPayload::from_static_ref),
},
#[cfg(feature = "unstable")]
LineSegmenterBorrowedInner::V3 {
data,
options,
complex,
} => LineSegmenterInner::V3 {
data: DataPayload::from_static_ref(data),
complex: complex.static_to_owned(),
options,
},
})
}
}
#[derive(Debug)]
pub struct LineBreakIterator<'data, 's, Y: RuleBreakType>(LineBreakIteratorInner<'data, 's, Y>);
#[derive(Debug)]
enum LineBreakIteratorInner<'data, 's, Y: RuleBreakType> {
V1(v1::LineBreakIteratorV1<'data, 's, Y>),
#[cfg(feature = "unstable")]
V2(crate::rule_segmenter_v2::RuleBreakIterator<'data, 's, Y, ComplexLine<Y>>),
#[cfg(feature = "unstable")]
V3(v3::LineBreakIteratorV3<'data, 's, Y>),
}
impl<Y: RuleBreakType> Iterator for LineBreakIterator<'_, '_, Y> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
match self.0 {
LineBreakIteratorInner::V1(ref mut iter) => iter.next(),
#[cfg(feature = "unstable")]
LineBreakIteratorInner::V2(ref mut iter) => iter.next(),
#[cfg(feature = "unstable")]
LineBreakIteratorInner::V3(ref mut iter) => iter.next(),
}
}
}
#[cfg(feature = "unstable")]
impl<Y: RuleBreakType> LineBreakIterator<'_, '_, Y> {
pub fn is_mandatory(&self) -> bool {
match self.0 {
LineBreakIteratorInner::V1(_) => false,
#[cfg(feature = "unstable")]
LineBreakIteratorInner::V2(ref iter) => iter.last_accepting_status() == (true as u8),
#[cfg(feature = "unstable")]
LineBreakIteratorInner::V3(_) => false,
}
}
}
#[derive(Debug)]
#[cfg(feature = "unstable")]
struct ComplexLine<Y>(core::marker::PhantomData<Y>);
#[cfg(feature = "unstable")]
impl<Y: RuleBreakType> crate::rule_segmenter_v2::ComplexHandler<Y> for ComplexLine<Y> {
const BREAK_AT_BOUNDARIES: bool = false;
const BREAK_STATUS: u8 = false as u8;
type Cache = [usize; 16];
type ComplexPayloads<'s> = Y::ComplexPayloads<'s>;
type ComplexPayload<'s> = Y::ComplexPayload<'s>;
fn select<'data>(
complex_payloads: &Self::ComplexPayloads<'data>,
complex_script: ComplexScript,
) -> Option<Self::ComplexPayload<'data>> {
Y::select_complex(complex_payloads, complex_script)
}
fn handle<'data, 's>(
complex_payload: &Self::ComplexPayload<'data>,
iter: &Y::IterAttr<'s>,
past_complex: &Y::IterAttr<'s>,
) -> ComplexIterator<'data, 's, Y> {
Y::handle_complex(complex_payload, iter, past_complex)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::LineSegmenterBorrowed;
use crate::*;
include!("../tests/helpers.rs.raw");
#[test]
fn test_mandatory() {
let mut actual_breaks = LineSegmenter::new_neo_for_non_complex_scripts(Default::default())
.segment_str("this has a mandatory\nline break");
assert_eq!(actual_breaks.next(), Some(0));
assert_eq!(actual_breaks.is_mandatory(), false);
assert_eq!(actual_breaks.next(), Some(5));
assert_eq!(actual_breaks.is_mandatory(), false);
assert_eq!(actual_breaks.next(), Some(9));
assert_eq!(actual_breaks.is_mandatory(), false);
assert_eq!(actual_breaks.next(), Some(11));
assert_eq!(actual_breaks.is_mandatory(), false);
assert_eq!(actual_breaks.next(), Some(21));
assert_eq!(actual_breaks.is_mandatory(), true);
assert_eq!(actual_breaks.next(), Some(26));
assert_eq!(actual_breaks.is_mandatory(), false);
assert_eq!(actual_breaks.next(), Some(31));
assert_eq!(actual_breaks.is_mandatory(), true);
assert_eq!(actual_breaks.next(), None);
}
#[test]
fn linebreak() {
let segmenter = LineSegmenter::new_dictionary(Default::default());
check_line("hello world", &["hello ", "world"], segmenter);
check_line("$10 $10", &["$10 ", "$10"], segmenter);
check_line("[ abc def", &["[ abc ", "def"], segmenter);
check_line("abc\u{0022} (def", &["abc\u{0022} ", "(def"], segmenter);
check_line("« miaou »", &["« miaou »"], segmenter);
check_line(
"Die Katze hat »miau« gesagt.",
&["Die ", "Katze ", "hat ", "»miau« ", "gesagt."],
segmenter,
);
check_line("\u{0029}\u{203C}", &["\u{0029}\u{203C}"], segmenter);
check_line("\u{0029} \u{203C}", &["\u{0029} \u{203C}"], segmenter);
check_line("\u{2014}\u{2014}aa", &["\u{2014}\u{2014}", "aa"], segmenter);
check_line(
"\u{2014} \u{2014}aa",
&["\u{2014} \u{2014}", "aa"],
segmenter,
);
check_line(
"\u{2014}\u{2014} \u{2014}\u{2014}123 abc",
&["\u{2014}\u{2014} \u{2014}\u{2014}", "123 ", "abc"],
segmenter,
);
check_line("(0,1)+(2,3)", &["(0,1)+(2,3)"], segmenter);
check_line("—— ——123 abc", &["—— ——", "123 ", "abc"], segmenter);
check_line(
"\u{1F3FB} \u{1F3FB}",
&["\u{1F3FB} ", "\u{1F3FB}"],
segmenter,
);
}
#[test]
fn linebreak_17() {
let segmenter = LineSegmenter::new_17_for_non_complex_scripts(Default::default());
check_line("hello world", &["hello ", "world"], segmenter);
check_line("$10 $10", &["$10 ", "$10"], segmenter);
check_line("[ abc def", &["[ abc ", "def"], segmenter);
check_line("abc\u{0022} (def", &["abc\u{0022} ", "(def"], segmenter);
check_line("« miaou »", &["« miaou »"], segmenter);
check_line(
"Die Katze hat »miau« gesagt.",
&["Die ", "Katze ", "hat ", "»miau« ", "gesagt."],
segmenter,
);
check_line("\u{0029}\u{203C}", &["\u{0029}\u{203C}"], segmenter);
check_line("\u{0029} \u{203C}", &["\u{0029} \u{203C}"], segmenter);
check_line("\u{2014}\u{2014}aa", &["\u{2014}\u{2014}", "aa"], segmenter);
check_line(
"\u{2014} \u{2014}aa",
&["\u{2014} \u{2014}", "aa"],
segmenter,
);
check_line(
"\u{2014}\u{2014} \u{2014}\u{2014}123 abc",
&["\u{2014}\u{2014} \u{2014}\u{2014}", "123 ", "abc"],
segmenter,
);
check_line("(0,1)+(2,3)", &["(0,1)+(2,3)"], segmenter);
check_line("—— ——123 abc", &["—— ——", "123 ", "abc"], segmenter);
check_line(
"\u{1F3FB} \u{1F3FB}",
&["\u{1F3FB} ", "\u{1F3FB}"],
segmenter,
);
}
#[test]
fn linebreak_neo() {
let segmenter = LineSegmenter::new_neo_for_non_complex_scripts(Default::default());
check_line("hello world", &["hello ", "world"], segmenter);
check_line("$10 $10", &["$10 ", "$10"], segmenter);
check_line("[ abc def", &["[ abc ", "def"], segmenter);
check_line("abc\u{0022} (def", &["abc\u{0022} ", "(def"], segmenter);
check_line("« miaou »", &["« miaou »"], segmenter);
check_line(
"Die Katze hat »miau« gesagt.",
&["Die ", "Katze ", "hat ", "»miau« ", "gesagt."],
segmenter,
);
check_line("\u{0029}\u{203C}", &["\u{0029}\u{203C}"], segmenter);
check_line("\u{0029} \u{203C}", &["\u{0029} \u{203C}"], segmenter);
check_line("\u{2014}\u{2014}aa", &["\u{2014}\u{2014}", "aa"], segmenter);
check_line(
"\u{2014} \u{2014}aa",
&["\u{2014} \u{2014}", "aa"],
segmenter,
);
check_line(
"\u{2014}\u{2014} \u{2014}\u{2014}123 abc",
&["\u{2014}\u{2014} \u{2014}\u{2014}", "123 ", "abc"],
segmenter,
);
check_line("(0,1)+(2,3)", &["(0,1)+(2,3)"], segmenter);
check_line("—— ——123 abc", &["—— ——", "123 ", "abc"], segmenter);
check_line(
"\u{1F3FB} \u{1F3FB}",
&["\u{1F3FB} ", "\u{1F3FB}"],
segmenter,
);
}
#[test]
fn thai_line_break() {
check_line(
"ภาษาไทยภาษาไทย",
&["ภาษา", "ไทย", "ภาษา", "ไทย"],
LineSegmenter::new_lstm(Default::default()),
);
check_line(
"ภาษาไทยภาษาไทย",
&["ภาษา", "ไทย", "ภาษา", "ไทย"],
LineSegmenter::new_dictionary(Default::default()),
);
check_line(
"ภาษา",
&["ภาษา"],
LineSegmenter::new_lstm(Default::default()),
);
check_line(
"ภาษา",
&["ภาษา"],
LineSegmenter::new_dictionary(Default::default()),
);
}
#[test]
fn thai_line_break_17() {
check_line(
"ภาษาไทยภาษาไทย",
&["ภาษา", "ไทย", "ภาษา", "ไทย"],
{
let mut s = LineSegmenter::new_17_for_non_complex_scripts(Default::default());
s.load_lstm();
s
},
);
check_line(
"ภาษาไทยภาษาไทย",
&["ภาษา", "ไทย", "ภาษา", "ไทย"],
{
let mut s = LineSegmenter::new_17_for_non_complex_scripts(Default::default());
s.load_dictionary();
s
},
);
check_line("ภาษา", &["ภาษา"], {
let mut s = LineSegmenter::new_17_for_non_complex_scripts(Default::default());
s.load_lstm();
s
});
check_line("ภาษา", &["ภาษา"], {
let mut s = LineSegmenter::new_17_for_non_complex_scripts(Default::default());
s.load_dictionary();
s
});
}
#[test]
fn thai_line_break_neo() {
check_line(
"ภาษาไทยภาษาไทย",
&["ภาษา", "ไทย", "ภาษา", "ไทย"],
{
let mut s = LineSegmenter::new_neo_for_non_complex_scripts(Default::default());
s.load_lstm();
s
},
);
check_line(
"ภาษาไทยภาษาไทย",
&["ภาษา", "ไทย", "ภาษา", "ไทย"],
{
let mut s = LineSegmenter::new_neo_for_non_complex_scripts(Default::default());
s.load_dictionary();
s
},
);
check_line("ภาษา", &["ภาษา"], {
let mut s = LineSegmenter::new_neo_for_non_complex_scripts(Default::default());
s.load_lstm();
s
});
check_line("ภาษา", &["ภาษา"], {
let mut s = LineSegmenter::new_neo_for_non_complex_scripts(Default::default());
s.load_dictionary();
s
});
check_line(
"ก\u{2060}รุ\u{2060}ง",
&["ก\u{2060}รุ\u{2060}ง"],
{
let mut s = LineSegmenter::new_neo_for_non_complex_scripts(Default::default());
s.load_dictionary();
s
},
);
}
#[test]
fn burmese_line_break() {
check_line(
"မြန်မာဘာသာစကား",
&["မြန်", "မာ", "ဘာသာ", "စကား"],
LineSegmenter::new_lstm(Default::default()),
);
check_line(
"မြန်မာဘာသာစကား",
&["မြန်မာဘာသာ", "စကား"],
LineSegmenter::new_dictionary(Default::default()),
);
}
#[test]
fn burmese_line_break_17() {
check_line(
"မြန်မာဘာသာစကား",
&["မြန်", "မာ", "ဘာသာ", "စကား"],
{
let mut s = LineSegmenter::new_17_for_non_complex_scripts(Default::default());
s.load_lstm();
s
},
);
check_line(
"မြန်မာဘာသာစကား",
&["မြန်မာဘာသာ", "စကား"],
{
let mut s = LineSegmenter::new_17_for_non_complex_scripts(Default::default());
s.load_dictionary();
s
},
);
}
#[test]
fn burmese_line_break_neo() {
check_line(
"မြန်မာဘာသာစကား",
&["မြန်", "မာ", "ဘာသာ", "စကား"],
{
let mut s = LineSegmenter::new_neo_for_non_complex_scripts(Default::default());
s.load_lstm();
s
},
);
check_line(
"မြန်မာဘာသာစကား",
&["မြန်မာဘာသာ", "စကား"],
{
let mut s = LineSegmenter::new_neo_for_non_complex_scripts(Default::default());
s.load_dictionary();
s
},
);
}
#[test]
fn khmer_line_break() {
check_line(
"សេចក្ដីប្រកាសជាសកលស្ដីពីសិទ្ធិមនុស្ស",
&["សេចក្ដីប្រកាស", "ជាស", "កល", "ស្ដីពី", "សិទ្ធិមនុស្ស"],
LineSegmenter::new_lstm(Default::default()),
);
check_line(
"សេចក្ដីប្រកាសជាសកលស្ដីពីសិទ្ធិមនុស្ស",
&["សេចក្ដីប្រកាស", "ជាស", "កល", "ស្ដីពី", "សិទ្ធិមនុស្ស"],
LineSegmenter::new_dictionary(Default::default()),
);
}
#[test]
fn khmer_line_break_17() {
check_line(
"សេចក្ដីប្រកាសជាសកលស្ដីពីសិទ្ធិមនុស្ស",
&["សេចក្ដីប្រកាស", "ជាស", "កល", "ស្ដីពី", "សិទ្ធិមនុស្ស"],
{
let mut s = LineSegmenter::new_17_for_non_complex_scripts(Default::default());
s.load_lstm();
s
},
);
check_line(
"សេចក្ដីប្រកាសជាសកលស្ដីពីសិទ្ធិមនុស្ស",
&["សេចក្ដីប្រកាស", "ជាស", "កល", "ស្ដីពី", "សិទ្ធិមនុស្ស"],
{
let mut s = LineSegmenter::new_17_for_non_complex_scripts(Default::default());
s.load_dictionary();
s
},
);
}
#[test]
fn khmer_line_break_neo() {
check_line(
"សេចក្ដីប្រកាសជាសកលស្ដីពីសិទ្ធិមនុស្ស",
&["សេចក្ដីប្រកាស", "ជាស", "កល", "ស្ដីពី", "សិទ្ធិមនុស្ស"],
{
let mut s = LineSegmenter::new_neo_for_non_complex_scripts(Default::default());
s.load_lstm();
s
},
);
check_line(
"សេចក្ដីប្រកាសជាសកលស្ដីពីសិទ្ធិមនុស្ស",
&["សេចក្ដីប្រកាស", "ជាស", "កល", "ស្ដីពី", "សិទ្ធិមនុស្ស"],
{
let mut s = LineSegmenter::new_neo_for_non_complex_scripts(Default::default());
s.load_dictionary();
s
},
);
check_line(
"អស់ នឹង មាន",
&["អស់ ", "នឹង ", "មាន"],
{
let mut s = LineSegmenter::new_neo_for_non_complex_scripts(Default::default());
s.load_dictionary();
s
},
);
}
#[test]
fn lao_line_break() {
check_line(
"ກ່ຽວກັບສິດຂອງມະນຸດ",
&["ກ່ຽວ", "ກັບ", "ສິດ", "ຂອງ", "ມະນຸດ"],
LineSegmenter::new_lstm(Default::default()),
);
check_line(
"ກ່ຽວກັບສິດຂອງມະນຸດ",
&["ກ່ຽວກັບ", "ສິດ", "ຂອງ", "ມະນຸດ"],
LineSegmenter::new_dictionary(Default::default()),
);
}
#[test]
fn lao_line_break_17() {
check_line(
"ກ່ຽວກັບສິດຂອງມະນຸດ",
&["ກ່ຽວ", "ກັບ", "ສິດ", "ຂອງ", "ມະນຸດ"],
{
let mut s = LineSegmenter::new_17_for_non_complex_scripts(Default::default());
s.load_lstm();
s
},
);
check_line(
"ກ່ຽວກັບສິດຂອງມະນຸດ",
&["ກ່ຽວກັບ", "ສິດ", "ຂອງ", "ມະນຸດ"],
{
let mut s = LineSegmenter::new_17_for_non_complex_scripts(Default::default());
s.load_dictionary();
s
},
);
}
#[test]
fn lao_line_break_neo() {
check_line(
"ກ່ຽວກັບສິດຂອງມະນຸດ",
&["ກ່ຽວ", "ກັບ", "ສິດ", "ຂອງ", "ມະນຸດ"],
{
let mut s = LineSegmenter::new_neo_for_non_complex_scripts(Default::default());
s.load_lstm();
s
},
);
check_line(
"ກ່ຽວກັບສິດຂອງມະນຸດ",
&["ກ່ຽວກັບ", "ສິດ", "ຂອງ", "ມະນຸດ"],
{
let mut s = LineSegmenter::new_neo_for_non_complex_scripts(Default::default());
s.load_dictionary();
s
},
);
}
#[test]
fn empty_string() {
let segmenter = LineSegmenter::new_for_non_complex_scripts(Default::default());
let breaks: Vec<usize> = segmenter.segment_str("").collect();
assert_eq!(breaks, [0]);
}
#[test]
fn empty_string_17() {
let segmenter = LineSegmenter::new_17_for_non_complex_scripts(Default::default());
let breaks: Vec<usize> = segmenter.segment_str("").collect();
assert_eq!(breaks, [0]);
}
#[test]
fn empty_string_neo() {
let segmenter = LineSegmenter::new_neo_for_non_complex_scripts(Default::default());
let breaks: Vec<usize> = segmenter.segment_str("").collect();
assert_eq!(breaks, [0]);
}
}