Skip to main content

unicode_normalize_aligned/
char.rs

1//! Per-character queries backed by the same tables as the iterators.
2
3use crate::props::{self, hangul, Props};
4
5/// Canonical combining class (ccc) of the character. 0 for starters.
6#[inline]
7pub fn canonical_combining_class(c: char) -> u8 {
8    Props::of(c).ccc()
9}
10
11/// Whether the character's General_Category is Mn, Mc or Me.
12#[inline]
13pub fn is_combining_mark(c: char) -> bool {
14    Props::of(c).is_combining_mark()
15}
16
17/// Canonical composition of a pair. Returns the primary composite, or the
18/// Hangul syllable the pair forms. Excluded composites and singleton
19/// decompositions never compose, so they return `None`.
20#[inline]
21pub fn compose(a: char, b: char) -> Option<char> {
22    hangul::compose(a, b).or_else(|| props::compose_pair(a, b))
23}
24
25/// Emits the full canonical decomposition of the character, one `char` at a
26/// time. A character with no canonical mapping is emitted unchanged.
27pub fn decompose_canonical<F: FnMut(char)>(c: char, mut emit: F) {
28    if (c as u32) < 0x80 || !Props::of(c).nfd_no() {
29        emit(c);
30        return;
31    }
32    if let Some((l, v, t)) = hangul::decompose(c) {
33        emit(l);
34        emit(v);
35        if let Some(t) = t {
36            emit(t);
37        }
38        return;
39    }
40    match props::canonical(c) {
41        Some(seq) => seq.iter().copied().for_each(emit),
42        None => emit(c),
43    }
44}
45
46/// Emits the full compatibility decomposition of the character, one `char` at
47/// a time. A character with no mapping is emitted unchanged.
48pub fn decompose_compatible<F: FnMut(char)>(c: char, mut emit: F) {
49    let p = Props::of(c);
50    if (c as u32) < 0x80 || !p.nfkd_no() {
51        emit(c);
52        return;
53    }
54    if let Some((l, v, t)) = hangul::decompose(c) {
55        emit(l);
56        emit(v);
57        if let Some(t) = t {
58            emit(t);
59        }
60        return;
61    }
62    let seq = if p.has_compat() {
63        props::compat_distinct(c)
64    } else {
65        props::canonical(c)
66    };
67    match seq {
68        Some(seq) => seq.iter().copied().for_each(emit),
69        None => emit(c),
70    }
71}