use std::fmt;
use std::error;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn decomposition() {
let han = '한';
let ha = '하';
assert_eq!(get_choseong(han).unwrap(), 'ㅎ');
assert_eq!(get_jungseong(han).unwrap(), 'ㅏ');
assert_eq!(get_jongseong(han).unwrap(), 'ㄴ');
assert_eq!(has_jongseong(han).unwrap(), true);
assert_eq!(has_jongseong(ha).unwrap(), false);
get_jongseong(ha).unwrap_err();
}
#[test]
fn check_jamo() {
assert_eq!(is_jamo('ㄱ'), true);
assert_eq!(is_jamo('ㅣ'), true);
assert_eq!(is_jamo('a'), false);
assert_eq!(is_jaeum('ㄱ'), true);
assert_eq!(is_jaeum('ㅎ'), true);
assert_eq!(is_jaeum('ㅏ'), false);
assert_eq!(is_choseong('ㄱ'), true);
assert_eq!(is_choseong('ㅎ'), true);
assert_eq!(is_choseong('ㄸ'), true);
assert_eq!(is_choseong('ㄳ'), false);
assert_eq!(is_jongseong('ㄱ'), true);
assert_eq!(is_jongseong('ㅎ'), true);
assert_eq!(is_jongseong('ㄸ'), false);
assert_eq!(is_jongseong('ㄳ'), true);
}
}
#[derive(Debug)]
pub enum HangeulError {
NotSyllable,
NoJongSeong,
}
impl fmt::Display for HangeulError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
HangeulError::NotSyllable => write!(f, "HangeulError: Not correct Hangeul syllable"),
HangeulError::NoJongSeong => write!(f, "HangeulError: The syllable has no jongseong")
}
}
}
impl error::Error for HangeulError {
fn description(&self) -> &str {
match *self {
HangeulError::NotSyllable => "HangeulError: Not correct Hangeul syllable",
HangeulError::NoJongSeong => "HangeulError: The syllable has no jongseong",
}
}
fn cause(&self) -> Option<&error::Error> {
match *self {
_ => None
}
}
}
const CHOSEONG_TABLE: [u32; 19] = [
0x01, 0x02, 0x04, 0x07, 0x08, 0x09, 0x11, 0x12, 0x13, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, ];
const JONGSEONG_TABLE: [u32; 27] = [
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x14, 0x15, 0x16, 0x17, 0x18, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, ];
fn _is_syllable(code:u32) -> bool {
(code >= 0xAC00 && code <= 0xD7AF)
}
pub fn is_syllable(c:char) -> bool {
let code = c as u32;
_is_syllable(code)
}
fn syllable_to_u32(c:char) -> Result<u32, HangeulError> {
let code = c as u32;
if _is_syllable(code) {
Ok(code)
} else {
Err(HangeulError::NotSyllable)
}
}
pub fn get_choseong(c:char) -> Result<char, HangeulError> {
let code = try!(syllable_to_u32(c));
let x = (code - 0xAC00) / 21 / 28;
Ok(std::char::from_u32(CHOSEONG_TABLE[x as usize] + 0x3130).unwrap())
}
pub fn get_jungseong(c:char) -> Result<char, HangeulError> {
let code = try!(syllable_to_u32(c));
Ok(std::char::from_u32(((code - 0xAc00) % (21 * 28)) / 28 + 0x314F).unwrap())
}
pub fn get_jongseong(c:char) -> Result<char, HangeulError> {
let code = try!(syllable_to_u32(c));
let x:i32 = (code - 0xAC00) as i32 % 28 - 1;
if x >= 0 {
Ok(std::char::from_u32(JONGSEONG_TABLE[x as usize] + 0x3130).unwrap())
} else {
Err(HangeulError::NoJongSeong)
}
}
pub fn has_jongseong(c:char) -> Result<bool, HangeulError> {
let code = try!(syllable_to_u32(c));
Ok((code - 0xAC00) % 28 != 0)
}
pub fn ends_with_jongseong(s:&str) -> Result<bool, HangeulError> {
let c = match s.chars().last() {
Some(x) => x,
None => return Err(HangeulError::NotSyllable),
};
has_jongseong(c)
}
pub fn is_jamo(c:char) -> bool {
let code = c as u32;
(code >= 0x3131 && code <= 0x3163)
}
pub fn is_jaeum(c:char) -> bool {
let code = c as u32;
(code >= 0x3131 && code <= 0x314E)
}
pub fn is_choseong(c:char) -> bool {
let code_jamo = c as u32 - 0x3130;
CHOSEONG_TABLE.into_iter().any(|&x| x == code_jamo)
}
pub fn is_jongseong(c:char) -> bool {
let code_jamo = c as u32 - 0x3130;
JONGSEONG_TABLE.into_iter().any(|&x| x == code_jamo)
}