unic_ucd_normal/
decomposition.rs

1// Copyright 2012-2015 The Rust Project Developers.
2// Copyright 2017 The UNIC Project Developers.
3//
4// See the COPYRIGHT file at the top-level directory of this distribution.
5//
6// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
7// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
8// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
9// option. This file may not be copied, modified, or distributed
10// except according to those terms.
11
12use core::ops::FnMut;
13
14use crate::composition::{canonical_decomposition, compatibility_decomposition};
15
16use unic_ucd_hangul::{decompose_syllable, is_syllable};
17
18/// Compute canonical Unicode decomposition for character.
19///
20/// See [Unicode Standard Annex #15](https://www.unicode.org/reports/tr15/) for more information.
21pub fn decompose_canonical<F>(ch: char, mut callback: F)
22where
23    F: FnMut(char),
24{
25    d(ch, &mut callback, false);
26}
27
28/// Compute canonical or compatible Unicode decomposition for character.
29///
30/// See [Unicode Standard Annex #15](https://www.unicode.org/reports/tr15/) for more information.
31pub fn decompose_compatible<F>(ch: char, mut callback: F)
32where
33    F: FnMut(char),
34{
35    d(ch, &mut callback, true);
36}
37
38// FIXME: This is a workaround, we should use `F` instead of `&mut F`
39fn d<F>(ch: char, callback: &mut F, k: bool)
40where
41    F: FnMut(char),
42{
43    // 7-bit ASCII never decomposes
44    if ch <= '\x7f' {
45        (*callback)(ch);
46        return;
47    }
48
49    // Perform decomposition for Hangul
50    if is_syllable(ch) {
51        decompose_syllable(ch, callback);
52        return;
53    }
54
55    // First check the canonical decompositions
56    if let Some(canon) = canonical_decomposition(ch) {
57        for x in canon {
58            d(*x, callback, k);
59        }
60        return;
61    }
62
63    // Bottom out if we're not doing compat.
64    if !k {
65        (*callback)(ch);
66        return;
67    }
68
69    // Then check the compatibility decompositions
70    if let Some(compat) = compatibility_decomposition(ch) {
71        for x in compat {
72            d(*x, callback, k);
73        }
74        return;
75    }
76
77    // Finally bottom out.
78    (*callback)(ch);
79}