use crate::char_struct::CharType;
use crate::rules::RuleMeta;
use crate::rules::context::RuleContext;
use crate::rules::traits::{BrailleRule, Phase, RuleResult};
pub static META: RuleMeta = RuleMeta {
section: "44",
subsection: Some("b1"),
name: "number_korean_spacing",
standard_ref: "2024 Korean Braille Standard, Ch.5 Sec.11 Art.44 [다만]",
description: "Insert space between number and confusable Korean choseong",
};
const CONFUSABLE_CHOSEONG: [char; 7] = ['ㄴ', 'ㄷ', 'ㅁ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'];
pub struct Rule44;
impl BrailleRule for Rule44 {
fn meta(&self) -> &'static RuleMeta {
&META
}
fn phase(&self) -> Phase {
Phase::CoreEncoding
}
fn priority(&self) -> u16 {
50 }
fn matches(&self, ctx: &RuleContext) -> bool {
if !ctx.state.is_number {
return false;
}
let CharType::Korean(korean) = ctx.char_type else {
return false;
};
CONFUSABLE_CHOSEONG.contains(&korean.cho) || ctx.current_char() == '운'
}
fn apply(&self, ctx: &mut RuleContext) -> Result<RuleResult, String> {
let has_middle_dot_before = ctx.word_chars[..ctx.index].contains(&'·');
if has_middle_dot_before {
ctx.emit(8); } else {
ctx.emit(0); }
Ok(RuleResult::Continue) }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn identifies_confusable_choseong() {
for &cho in &CONFUSABLE_CHOSEONG {
assert!(
CONFUSABLE_CHOSEONG.contains(&cho),
"Missing confusable: {}",
cho
);
}
}
#[test]
fn golden_test_alignment() {
let result = crate::encode_to_unicode("5운6기").unwrap();
assert_eq!(result, "⠼⠑⠀⠛⠼⠋⠈⠕");
}
#[test]
fn meta_is_correct() {
assert_eq!(META.section, "44");
assert_eq!(META.name, "number_korean_spacing");
}
}