unic_ucd_hangul/
hangul.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
12//! Conjoining Jamo composition to/decomposition from Hangul syllables.
13//!
14//! Reference: Section 3.12 Conjoining Jamo Behavior, Unicode 9.0.0
15//! <https://www.unicode.org/versions/Unicode9.0.0/ch03.pdf>
16
17use core::char;
18
19pub const S_BASE: u32 = 0xAC00;
20pub const L_BASE: u32 = 0x1100;
21pub const V_BASE: u32 = 0x1161;
22pub const T_BASE: u32 = 0x11A7;
23pub const L_COUNT: u32 = 19;
24pub const V_COUNT: u32 = 21;
25pub const T_COUNT: u32 = 28;
26pub const N_COUNT: u32 = (V_COUNT * T_COUNT);
27pub const S_COUNT: u32 = (L_COUNT * N_COUNT);
28
29/// Whether the character is a (precomposed) Hangul Syllable
30pub fn is_syllable(ch: char) -> bool {
31    let cp = ch as u32;
32    cp >= S_BASE && cp < (S_BASE + S_COUNT)
33}
34
35/// Decompose a precomposed Hangul syllable
36// FIXME: This is a workaround, we should use `F` instead of `&mut F`
37#[allow(unsafe_code)]
38#[inline]
39pub fn decompose_syllable<F>(syllable: char, f: &mut F)
40where
41    F: FnMut(char),
42{
43    let si = syllable as u32 - S_BASE;
44
45    let li = si / N_COUNT;
46    unsafe {
47        (*f)(char::from_u32_unchecked(L_BASE + li));
48
49        let vi = (si % N_COUNT) / T_COUNT;
50        (*f)(char::from_u32_unchecked(V_BASE + vi));
51
52        let ti = si % T_COUNT;
53        if ti > 0 {
54            (*f)(char::from_u32_unchecked(T_BASE + ti));
55        }
56    }
57}
58
59/// Compose a pair of Hangul Jamo
60#[allow(unsafe_code)]
61#[inline]
62pub fn compose_syllable(jamo1: char, jamo2: char) -> Option<char> {
63    let l = jamo1 as u32;
64    let v = jamo2 as u32;
65    // Compose an LPart and a VPart
66    if L_BASE <= l && l < (L_BASE + L_COUNT) // l should be an L choseong jamo
67        && V_BASE <= v && v < (V_BASE + V_COUNT)
68    {
69        // v should be a V jungseong jamo
70        let r = S_BASE + (l - L_BASE) * N_COUNT + (v - V_BASE) * T_COUNT;
71        return unsafe { Some(char::from_u32_unchecked(r)) };
72    }
73    // Compose an LVPart and a TPart
74    if S_BASE <= l && l <= (S_BASE+S_COUNT-T_COUNT) // l should be a syllable block
75        && T_BASE <= v && v < (T_BASE+T_COUNT) // v should be a T jongseong jamo
76        && (l - S_BASE) % T_COUNT == 0
77    {
78        // l should be an LV syllable block (not LVT)
79        let r = l + (v - T_BASE);
80        return unsafe { Some(char::from_u32_unchecked(r)) };
81    }
82    None
83}