1use crate::char_from_u16;
15use crate::char_from_u32;
16use crate::in_inclusive_range;
17use crate::provider::CanonicalCompositions;
18use crate::provider::DecompositionData;
19use crate::provider::DecompositionTables;
20use crate::provider::NonRecursiveDecompositionSupplement;
21use crate::provider::NormalizerNfcV1;
22use crate::provider::NormalizerNfdDataV1;
23use crate::provider::NormalizerNfdSupplementV1;
24use crate::provider::NormalizerNfdTablesV1;
25use crate::trie_value_has_ccc;
26use crate::CanonicalCombiningClass;
27use crate::BACKWARD_COMBINING_MARKER;
28use crate::FDFA_MARKER;
29use crate::HANGUL_L_BASE;
30use crate::HANGUL_N_COUNT;
31use crate::HANGUL_S_BASE;
32use crate::HANGUL_S_COUNT;
33use crate::HANGUL_T_BASE;
34use crate::HANGUL_T_COUNT;
35use crate::HANGUL_V_BASE;
36use crate::HIGH_ZEROS_MASK;
37use crate::LOW_ZEROS_MASK;
38use crate::NON_ROUND_TRIP_MARKER;
39use icu_provider::prelude::*;
40
41)]
48pub struct CanonicalCompositionBorrowed<'a> {
49 canonical_compositions: &'a CanonicalCompositions<'a>,
50}
51
52#[cfg(feature = "compiled_data")]
53impl Default for CanonicalCompositionBorrowed<'static> {
54 fn default() -> Self {
55 Self::new()
56 }
57}
58
59impl CanonicalCompositionBorrowed<'static> {
60 pub const fn static_to_owned(self) -> CanonicalComposition {
65 CanonicalComposition {
66 canonical_compositions: DataPayload::from_static_ref(self.canonical_compositions),
67 }
68 }
69
70 #[cfg(feature = "compiled_data")]
76 pub const fn new() -> Self {
77 Self {
78 canonical_compositions: crate::provider::Baked::SINGLETON_NORMALIZER_NFC_V1,
79 }
80 }
81}
82
83impl CanonicalCompositionBorrowed<'_> {
84 #[inline(always)]
102 pub fn compose(self, starter: char, second: char) -> Option<char> {
103 crate::compose(
104 self.canonical_compositions.canonical_compositions.iter(),
105 starter,
106 second,
107 )
108 }
109}
110
111)]
118pub struct CanonicalComposition {
119 canonical_compositions: DataPayload<NormalizerNfcV1>,
120}
121
122#[cfg(feature = "compiled_data")]
123impl Default for CanonicalComposition {
124 fn default() -> Self {
125 Self::new().static_to_owned()
126 }
127}
128
129impl CanonicalComposition {
130 pub fn as_borrowed(&self) -> CanonicalCompositionBorrowed<'_> {
132 CanonicalCompositionBorrowed {
133 canonical_compositions: self.canonical_compositions.get(),
134 }
135 }
136
137 #[cfg(feature = "compiled_data")]
143 #[allow(clippy::new_ret_no_self)]
144 pub const fn new() -> CanonicalCompositionBorrowed<'static> {
145 CanonicalCompositionBorrowed::new()
146 }
147
148 icu_provider::gen_buffer_data_constructors!(() -> error: DataError,
149 functions: [
150 new: skip,
151 try_new_with_buffer_provider,
152 try_new_unstable,
153 Self,
154 ]
155 );
156
157 #[doc = "A version of [`Self::new`] that uses custom data provided by a [`DataProvider`](icu_provider::DataProvider).\n\n[\u{1f4da} Help choosing a constructor](icu_provider::constructors)\n\n<div class=\"stab unstable\">\u{26a0}\u{fe0f} The bounds on <tt>provider</tt> may change over time, including in SemVer minor releases.</div>"icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new)]
158 pub fn try_new_unstable<D>(provider: &D) -> Result<Self, DataError>
159 where
160 D: DataProvider<NormalizerNfcV1> + ?Sized,
161 {
162 let canonical_compositions: DataPayload<NormalizerNfcV1> =
163 provider.load(Default::default())?.payload;
164 Ok(CanonicalComposition {
165 canonical_compositions,
166 })
167 }
168}
169
170#[allow(clippy::exhaustive_enums)]
172#[derive(#[automatically_derived]
#[allow(clippy::exhaustive_enums)]
impl ::core::fmt::Debug for Decomposed {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Decomposed::Default =>
::core::fmt::Formatter::write_str(f, "Default"),
Decomposed::Singleton(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"Singleton", &__self_0),
Decomposed::Expansion(__self_0, __self_1) =>
::core::fmt::Formatter::debug_tuple_field2_finish(f,
"Expansion", __self_0, &__self_1),
}
}
}Debug, #[automatically_derived]
#[allow(clippy::exhaustive_enums)]
impl ::core::cmp::PartialEq for Decomposed {
#[inline]
fn eq(&self, other: &Decomposed) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(Decomposed::Singleton(__self_0),
Decomposed::Singleton(__arg1_0)) => __self_0 == __arg1_0,
(Decomposed::Expansion(__self_0, __self_1),
Decomposed::Expansion(__arg1_0, __arg1_1)) =>
__self_0 == __arg1_0 && __self_1 == __arg1_1,
_ => true,
}
}
}PartialEq, #[automatically_derived]
#[allow(clippy::exhaustive_enums)]
impl ::core::cmp::Eq for Decomposed {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) -> () {
let _: ::core::cmp::AssertParamIsEq<char>;
}
}Eq)]
173pub enum Decomposed {
174 Default,
176 Singleton(char),
178 Expansion(char, char),
180}
181
182)]
189pub struct CanonicalDecompositionBorrowed<'a> {
190 decompositions: &'a DecompositionData<'a>,
191 tables: &'a DecompositionTables<'a>,
192 non_recursive: &'a NonRecursiveDecompositionSupplement<'a>,
193}
194
195#[cfg(feature = "compiled_data")]
196impl Default for CanonicalDecompositionBorrowed<'static> {
197 fn default() -> Self {
198 Self::new()
199 }
200}
201
202impl CanonicalDecompositionBorrowed<'static> {
203 pub const fn static_to_owned(self) -> CanonicalDecomposition {
208 CanonicalDecomposition {
209 decompositions: DataPayload::from_static_ref(self.decompositions),
210 tables: DataPayload::from_static_ref(self.tables),
211 non_recursive: DataPayload::from_static_ref(self.non_recursive),
212 }
213 }
214
215 #[cfg(feature = "compiled_data")]
221 pub const fn new() -> Self {
222 const _: () = if !(crate::provider::Baked::SINGLETON_NORMALIZER_NFD_TABLES_V1.scalars16.const_len()
+
crate::provider::Baked::SINGLETON_NORMALIZER_NFD_TABLES_V1.scalars24.const_len()
<= 0xFFF) {
{ ::core::panicking::panic_fmt(format_args!("future extension")); }
}assert!(
223 crate::provider::Baked::SINGLETON_NORMALIZER_NFD_TABLES_V1
224 .scalars16
225 .const_len()
226 + crate::provider::Baked::SINGLETON_NORMALIZER_NFD_TABLES_V1
227 .scalars24
228 .const_len()
229 <= 0xFFF,
230 "future extension"
231 );
232
233 Self {
234 decompositions: crate::provider::Baked::SINGLETON_NORMALIZER_NFD_DATA_V1,
235 tables: crate::provider::Baked::SINGLETON_NORMALIZER_NFD_TABLES_V1,
236 non_recursive: crate::provider::Baked::SINGLETON_NORMALIZER_NFD_SUPPLEMENT_V1,
237 }
238 }
239}
240
241impl CanonicalDecompositionBorrowed<'_> {
242 #[inline]
259 pub fn decompose(&self, c: char) -> Decomposed {
260 let lvt = u32::from(c).wrapping_sub(HANGUL_S_BASE);
261 if lvt >= HANGUL_S_COUNT {
262 return self.decompose_non_hangul(c);
263 }
264 let t = lvt % HANGUL_T_COUNT;
266 if t == 0 {
268 let l = lvt / HANGUL_N_COUNT;
269 let v = (lvt % HANGUL_N_COUNT) / HANGUL_T_COUNT;
271 return Decomposed::Expansion(
273 unsafe { char::from_u32_unchecked(HANGUL_L_BASE + l) },
276 unsafe { char::from_u32_unchecked(HANGUL_V_BASE + v) },
277 );
278 }
279 let lv = lvt - t;
280 Decomposed::Expansion(
283 unsafe { char::from_u32_unchecked(HANGUL_S_BASE + lv) },
286 unsafe { char::from_u32_unchecked(HANGUL_T_BASE + t) },
287 )
288 }
289
290 #[inline(always)]
293 fn decompose_non_hangul(&self, c: char) -> Decomposed {
294 let decomposition = self.decompositions.trie.get(c);
295 if (decomposition & !(BACKWARD_COMBINING_MARKER | NON_ROUND_TRIP_MARKER)) == 0 {
298 return Decomposed::Default;
299 }
300 #[allow(clippy::never_loop)]
302 loop {
303 let high_zeros = (decomposition & HIGH_ZEROS_MASK) == 0;
304 let low_zeros = (decomposition & LOW_ZEROS_MASK) == 0;
305 if !high_zeros && !low_zeros {
306 if in_inclusive_range(c, '\u{1F71}', '\u{1FFB}') {
308 break;
311 }
312 let starter = char_from_u32(decomposition & 0x7FFF);
313 let combining = char_from_u32((decomposition >> 15) & 0x7FFF);
314 return Decomposed::Expansion(starter, combining);
315 }
316 if high_zeros {
317 if trie_value_has_ccc(decomposition) {
319 if !in_inclusive_range(c, '\u{0340}', '\u{0F81}') {
321 return Decomposed::Default;
322 }
323 return match c {
324 '\u{0340}' => {
325 Decomposed::Singleton('\u{0300}')
327 }
328 '\u{0341}' => {
329 Decomposed::Singleton('\u{0301}')
331 }
332 '\u{0343}' => {
333 Decomposed::Singleton('\u{0313}')
335 }
336 '\u{0344}' => {
337 Decomposed::Expansion('\u{0308}', '\u{0301}')
339 }
340 '\u{0F73}' => {
341 Decomposed::Expansion('\u{0F71}', '\u{0F72}')
343 }
344 '\u{0F75}' => {
345 Decomposed::Expansion('\u{0F71}', '\u{0F74}')
347 }
348 '\u{0F81}' => {
349 Decomposed::Expansion('\u{0F71}', '\u{0F80}')
351 }
352 _ => Decomposed::Default,
353 };
354 }
355 let singleton = decomposition as u16;
356 if true {
match (&(singleton), &(FDFA_MARKER)) {
(left_val, right_val) => {
if *left_val == *right_val {
let kind = ::core::panicking::AssertKind::Ne;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val,
::core::option::Option::Some(format_args!("How come we got the U+FDFA NFKD marker here?")));
}
}
};
};debug_assert_ne!(
357 singleton, FDFA_MARKER,
358 "How come we got the U+FDFA NFKD marker here?"
359 );
360 return Decomposed::Singleton(char_from_u16(singleton));
361 }
362 if c == '\u{212B}' {
363 return Decomposed::Singleton('\u{00C5}');
365 }
366 let offset = (((decomposition & !(0b11 << 30)) >> 16) as usize) - 1;
368 let len_bits = decomposition & 0b1111;
370 let tables = self.tables;
371 if offset < tables.scalars16.len() {
372 if len_bits != 0 {
373 break;
375 }
376 if let Some(first) = tables.scalars16.get(offset) {
377 if let Some(second) = tables.scalars16.get(offset + 1) {
378 return Decomposed::Expansion(char_from_u16(first), char_from_u16(second));
380 }
381 }
382 if true {
if !false { ::core::panicking::panic("assertion failed: false") };
};debug_assert!(false);
384 return Decomposed::Default;
385 }
386 let len = len_bits + 1;
387 if len > 2 {
388 break;
389 }
390 let offset24 = offset - tables.scalars16.len();
391 if let Some(first_c) = tables.scalars24.get(offset24) {
392 if len == 1 {
393 return Decomposed::Singleton(first_c);
394 }
395 if let Some(second_c) = tables.scalars24.get(offset24 + 1) {
396 return Decomposed::Expansion(first_c, second_c);
397 }
398 }
399 if true {
if !false { ::core::panicking::panic("assertion failed: false") };
};debug_assert!(false);
401 return Decomposed::Default;
402 }
403 let non_recursive = self.non_recursive;
404 let non_recursive_decomposition = non_recursive.trie.get(c);
405 if non_recursive_decomposition == 0 {
406 if true {
if !false { ::core::panicking::panic("assertion failed: false") };
};debug_assert!(false);
408 return Decomposed::Default;
409 }
410 let trail_or_complex = (non_recursive_decomposition >> 16) as u16;
411 let lead = non_recursive_decomposition as u16;
412 if lead != 0 && trail_or_complex != 0 {
413 return Decomposed::Expansion(char_from_u16(lead), char_from_u16(trail_or_complex));
415 }
416 if lead != 0 {
417 return Decomposed::Singleton(char_from_u16(lead));
419 }
420 let offset = usize::from(trail_or_complex - 1);
423 if let Some(first) = non_recursive.scalars24.get(offset) {
424 if let Some(second) = non_recursive.scalars24.get(offset + 1) {
425 return Decomposed::Expansion(first, second);
426 }
427 }
428 if true {
if !false { ::core::panicking::panic("assertion failed: false") };
};debug_assert!(false);
430 Decomposed::Default
431 }
432}
433
434)]
441pub struct CanonicalDecomposition {
442 decompositions: DataPayload<NormalizerNfdDataV1>,
443 tables: DataPayload<NormalizerNfdTablesV1>,
444 non_recursive: DataPayload<NormalizerNfdSupplementV1>,
445}
446
447#[cfg(feature = "compiled_data")]
448impl Default for CanonicalDecomposition {
449 fn default() -> Self {
450 Self::new().static_to_owned()
451 }
452}
453
454impl CanonicalDecomposition {
455 pub fn as_borrowed(&self) -> CanonicalDecompositionBorrowed<'_> {
457 CanonicalDecompositionBorrowed {
458 decompositions: self.decompositions.get(),
459 tables: self.tables.get(),
460 non_recursive: self.non_recursive.get(),
461 }
462 }
463
464 #[cfg(feature = "compiled_data")]
470 #[allow(clippy::new_ret_no_self)]
471 pub const fn new() -> CanonicalDecompositionBorrowed<'static> {
472 CanonicalDecompositionBorrowed::new()
473 }
474
475 icu_provider::gen_buffer_data_constructors!(() -> error: DataError,
476 functions: [
477 new: skip,
478 try_new_with_buffer_provider,
479 try_new_unstable,
480 Self,
481 ]
482 );
483
484 #[doc = "A version of [`Self::new`] that uses custom data provided by a [`DataProvider`](icu_provider::DataProvider).\n\n[\u{1f4da} Help choosing a constructor](icu_provider::constructors)\n\n<div class=\"stab unstable\">\u{26a0}\u{fe0f} The bounds on <tt>provider</tt> may change over time, including in SemVer minor releases.</div>"icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new)]
485 pub fn try_new_unstable<D>(provider: &D) -> Result<Self, DataError>
486 where
487 D: DataProvider<NormalizerNfdDataV1>
488 + DataProvider<NormalizerNfdTablesV1>
489 + DataProvider<NormalizerNfdSupplementV1>
490 + ?Sized,
491 {
492 let decompositions: DataPayload<NormalizerNfdDataV1> =
493 provider.load(Default::default())?.payload;
494 let tables: DataPayload<NormalizerNfdTablesV1> = provider.load(Default::default())?.payload;
495
496 if tables.get().scalars16.len() + tables.get().scalars24.len() > 0xFFF {
497 return Err(DataError::custom("future extension"));
504 }
505
506 let non_recursive: DataPayload<NormalizerNfdSupplementV1> =
507 provider.load(Default::default())?.payload;
508
509 Ok(CanonicalDecomposition {
510 decompositions,
511 tables,
512 non_recursive,
513 })
514 }
515}
516
517)]
530pub struct CanonicalCombiningClassMapBorrowed<'a> {
531 decompositions: &'a DecompositionData<'a>,
533}
534
535#[cfg(feature = "compiled_data")]
536impl Default for CanonicalCombiningClassMapBorrowed<'static> {
537 fn default() -> Self {
538 Self::new()
539 }
540}
541
542impl CanonicalCombiningClassMapBorrowed<'static> {
543 pub const fn static_to_owned(self) -> CanonicalCombiningClassMap {
548 CanonicalCombiningClassMap {
549 decompositions: DataPayload::from_static_ref(self.decompositions),
550 }
551 }
552
553 #[cfg(feature = "compiled_data")]
559 pub const fn new() -> Self {
560 CanonicalCombiningClassMapBorrowed {
561 decompositions: crate::provider::Baked::SINGLETON_NORMALIZER_NFD_DATA_V1,
562 }
563 }
564}
565
566impl CanonicalCombiningClassMapBorrowed<'_> {
567 #[inline(always)]
573 pub fn get_u8(&self, c: char) -> u8 {
574 self.get32_u8(u32::from(c))
575 }
576
577 pub fn get32_u8(&self, c: u32) -> u8 {
585 let trie_value = self.decompositions.trie.get32(c);
586 if trie_value_has_ccc(trie_value) {
587 trie_value as u8
588 } else {
589 const { CanonicalCombiningClass::from_icu4c_value(0) }ccc!(NotReordered, 0).to_icu4c_value()
590 }
591 }
592
593 #[inline(always)]
597 #[cfg(feature = "icu_properties")]
598 pub fn get(&self, c: char) -> CanonicalCombiningClass {
599 CanonicalCombiningClass::from_icu4c_value(self.get_u8(c))
600 }
601
602 #[cfg(feature = "icu_properties")]
608 pub fn get32(&self, c: u32) -> CanonicalCombiningClass {
609 CanonicalCombiningClass::from_icu4c_value(self.get32_u8(c))
610 }
611}
612
613)]
615pub struct CanonicalCombiningClassMap {
616 decompositions: DataPayload<NormalizerNfdDataV1>,
618}
619
620#[cfg(feature = "compiled_data")]
621impl Default for CanonicalCombiningClassMap {
622 fn default() -> Self {
623 Self::new().static_to_owned()
624 }
625}
626
627impl CanonicalCombiningClassMap {
628 pub fn as_borrowed(&self) -> CanonicalCombiningClassMapBorrowed<'_> {
630 CanonicalCombiningClassMapBorrowed {
631 decompositions: self.decompositions.get(),
632 }
633 }
634
635 #[cfg(feature = "compiled_data")]
641 #[allow(clippy::new_ret_no_self)]
642 pub const fn new() -> CanonicalCombiningClassMapBorrowed<'static> {
643 CanonicalCombiningClassMapBorrowed::new()
644 }
645
646 icu_provider::gen_buffer_data_constructors!(() -> error: DataError,
647 functions: [
648 new: skip,
649 try_new_with_buffer_provider,
650 try_new_unstable,
651 Self,
652 ]);
653
654 #[doc = "A version of [`Self::new`] that uses custom data provided by a [`DataProvider`](icu_provider::DataProvider).\n\n[\u{1f4da} Help choosing a constructor](icu_provider::constructors)\n\n<div class=\"stab unstable\">\u{26a0}\u{fe0f} The bounds on <tt>provider</tt> may change over time, including in SemVer minor releases.</div>"icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new)]
655 pub fn try_new_unstable<D>(provider: &D) -> Result<Self, DataError>
656 where
657 D: DataProvider<NormalizerNfdDataV1> + ?Sized,
658 {
659 let decompositions: DataPayload<NormalizerNfdDataV1> =
660 provider.load(Default::default())?.payload;
661 Ok(CanonicalCombiningClassMap { decompositions })
662 }
663}