#![deny(unsafe_code)]
#![forbid(missing_docs)]
mod tables;
mod hangul;
pub use tables::UNICODE_VERSION;
pub use tables::{canonical_decomposition, compatibility_decomposition, canonical_composition, canonical_combining_class};
pub use tables::is_combining_mark;
use std::cmp::Ordering::{Equal, Less, Greater};
use std::ops::FnMut;
pub fn decompose_canonical<F>(c: char, mut i: F)
where F: FnMut(char)
{
d(c, &mut i, false);
}
pub fn decompose_compatible<F>(c: char, mut i: F)
where F: FnMut(char)
{
d(c, &mut i, true);
}
fn d<F>(c: char, i: &mut F, k: bool)
where F: FnMut(char)
{
if c <= '\x7f' {
(*i)(c);
return;
}
if (c as u32) >= hangul::S_BASE && (c as u32) < (hangul::S_BASE + hangul::S_COUNT) {
hangul::decompose(c, i);
return;
}
match canonical_decomposition(c) {
Some(canon) => {
for x in canon {
d(*x, i, k);
}
return;
}
None => (),
}
if !k {
(*i)(c);
return;
}
match compatibility_decomposition(c) {
Some(compat) => {
for x in compat {
d(*x, i, k);
}
return;
}
None => (),
}
(*i)(c);
}
pub fn compose(a: char, b: char) -> Option<char> {
hangul::compose(a, b).or_else(
|| match canonical_composition(a) {
None => None,
Some(candidates) => {
match candidates.binary_search_by(
|&(val, _)| if b == val {
Equal
} else if val < b {
Less
} else {
Greater
}
) {
Ok(idx) => {
let (_, result) = candidates[idx];
Some(result)
}
Err(_) => None,
}
}
}
)
}
#[cfg(test)]
mod tests {
use std::char;
use super::*;
#[test]
fn test_is_combining_mark_ascii() {
for cp in 0..0x7f {
assert!(!is_combining_mark(char::from_u32(cp).unwrap()));
}
}
#[test]
fn test_is_combining_mark_misc() {
assert!(is_combining_mark('\u{11C3A}'));
assert!(is_combining_mark('\u{11C3F}'));
}
}