#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DefaultStyleEntry {
pub name: &'static str,
pub eng_name: &'static str,
pub style_type: &'static str,
pub char_pr_group: u8,
pub para_pr_group: u8,
}
impl DefaultStyleEntry {
pub fn is_char_style(&self) -> bool {
self.style_type == "CHAR"
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
#[non_exhaustive]
pub enum HancomStyleSet {
Classic,
#[default]
Modern,
Latest,
}
impl HancomStyleSet {
pub fn default_styles(&self) -> &'static [DefaultStyleEntry] {
match self {
Self::Classic => &CLASSIC_STYLES,
Self::Modern => &MODERN_STYLES,
Self::Latest => &LATEST_STYLES,
}
}
pub fn count(&self) -> usize {
self.default_styles().len()
}
pub fn style_id_for_name(&self, name: &str) -> Option<usize> {
self.default_styles().iter().position(|entry| entry.name == name || entry.eng_name == name)
}
}
macro_rules! entry {
($name:expr, $eng:expr, $ty:expr, $cp:expr, $pp:expr) => {
DefaultStyleEntry {
name: $name,
eng_name: $eng,
style_type: $ty,
char_pr_group: $cp,
para_pr_group: $pp,
}
};
}
const CLASSIC_STYLES: [DefaultStyleEntry; 18] = [
entry!("바탕글", "Normal", "PARA", 0, 0), entry!("본문", "Body", "PARA", 0, 1), entry!("개요 1", "Outline 1", "PARA", 0, 2), entry!("개요 2", "Outline 2", "PARA", 0, 3), entry!("개요 3", "Outline 3", "PARA", 0, 4), entry!("개요 4", "Outline 4", "PARA", 0, 5), entry!("개요 5", "Outline 5", "PARA", 0, 6), entry!("개요 6", "Outline 6", "PARA", 0, 7), entry!("개요 7", "Outline 7", "PARA", 0, 8), entry!("쪽 번호", "Page Number", "CHAR", 1, 0), entry!("머리말", "Header", "PARA", 2, 9), entry!("각주", "Footnote", "PARA", 3, 10), entry!("미주", "Endnote", "PARA", 3, 10), entry!("메모", "Memo", "PARA", 4, 11), entry!("차례 제목", "TOC Heading", "PARA", 5, 12), entry!("차례 1", "TOC 1", "PARA", 6, 13), entry!("차례 2", "TOC 2", "PARA", 6, 14), entry!("차례 3", "TOC 3", "PARA", 6, 15), ];
const MODERN_STYLES: [DefaultStyleEntry; 22] = [
entry!("바탕글", "Normal", "PARA", 0, 0), entry!("본문", "Body", "PARA", 0, 1), entry!("개요 1", "Outline 1", "PARA", 0, 2), entry!("개요 2", "Outline 2", "PARA", 0, 3), entry!("개요 3", "Outline 3", "PARA", 0, 4), entry!("개요 4", "Outline 4", "PARA", 0, 5), entry!("개요 5", "Outline 5", "PARA", 0, 6), entry!("개요 6", "Outline 6", "PARA", 0, 7), entry!("개요 7", "Outline 7", "PARA", 0, 8), entry!("개요 8", "Outline 8", "PARA", 0, 18), entry!("개요 9", "Outline 9", "PARA", 0, 16), entry!("개요 10", "Outline 10", "PARA", 0, 17), entry!("쪽 번호", "Page Number", "CHAR", 1, 0), entry!("머리말", "Header", "PARA", 2, 9), entry!("각주", "Footnote", "PARA", 3, 10), entry!("미주", "Endnote", "PARA", 3, 10), entry!("메모", "Memo", "PARA", 4, 11), entry!("차례 제목", "TOC Heading", "PARA", 5, 12), entry!("차례 1", "TOC 1", "PARA", 6, 13), entry!("차례 2", "TOC 2", "PARA", 6, 14), entry!("차례 3", "TOC 3", "PARA", 6, 15), entry!("캡션", "Caption", "PARA", 0, 19), ];
const LATEST_STYLES: [DefaultStyleEntry; 23] = [
entry!("바탕글", "Normal", "PARA", 0, 0), entry!("본문", "Body", "PARA", 0, 1), entry!("개요 1", "Outline 1", "PARA", 0, 2), entry!("개요 2", "Outline 2", "PARA", 0, 3), entry!("개요 3", "Outline 3", "PARA", 0, 4), entry!("개요 4", "Outline 4", "PARA", 0, 5), entry!("개요 5", "Outline 5", "PARA", 0, 6), entry!("개요 6", "Outline 6", "PARA", 0, 7), entry!("개요 7", "Outline 7", "PARA", 0, 8), entry!("개요 8", "Outline 8", "PARA", 0, 18), entry!("개요 9", "Outline 9", "PARA", 0, 16), entry!("개요 10", "Outline 10", "PARA", 0, 17), entry!("쪽 번호", "Page Number", "CHAR", 1, 0), entry!("머리말", "Header", "PARA", 2, 9), entry!("각주", "Footnote", "PARA", 3, 10), entry!("미주", "Endnote", "PARA", 3, 10), entry!("메모", "Memo", "PARA", 4, 11), entry!("차례 제목", "TOC Heading", "PARA", 5, 12), entry!("차례 1", "TOC 1", "PARA", 6, 13), entry!("차례 2", "TOC 2", "PARA", 6, 14), entry!("차례 3", "TOC 3", "PARA", 6, 15), entry!("캡션", "Caption", "PARA", 0, 19), entry!("줄 번호", "Line Number", "CHAR", 1, 0), ];
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn classic_has_18_styles() {
assert_eq!(HancomStyleSet::Classic.count(), 18);
assert_eq!(HancomStyleSet::Classic.default_styles().len(), 18);
}
#[test]
fn modern_has_22_styles() {
assert_eq!(HancomStyleSet::Modern.count(), 22);
assert_eq!(HancomStyleSet::Modern.default_styles().len(), 22);
}
#[test]
fn latest_has_23_styles() {
assert_eq!(HancomStyleSet::Latest.count(), 23);
assert_eq!(HancomStyleSet::Latest.default_styles().len(), 23);
}
#[test]
fn modern_is_default() {
assert_eq!(HancomStyleSet::default(), HancomStyleSet::Modern);
}
#[test]
fn all_styles_start_with_batanggeul() {
for set in [HancomStyleSet::Classic, HancomStyleSet::Modern, HancomStyleSet::Latest] {
let styles = set.default_styles();
assert_eq!(styles[0].name, "바탕글");
assert_eq!(styles[0].eng_name, "Normal");
assert_eq!(styles[0].style_type, "PARA");
}
}
#[test]
fn modern_outline_8_at_index_9() {
let styles = HancomStyleSet::Modern.default_styles();
assert_eq!(styles[9].name, "개요 8");
assert_eq!(styles[9].style_type, "PARA");
}
#[test]
fn classic_page_number_at_index_9() {
let styles = HancomStyleSet::Classic.default_styles();
assert_eq!(styles[9].name, "쪽 번호");
assert_eq!(styles[9].style_type, "CHAR");
}
#[test]
fn modern_page_number_at_index_12() {
let styles = HancomStyleSet::Modern.default_styles();
assert_eq!(styles[12].name, "쪽 번호");
assert_eq!(styles[12].style_type, "CHAR");
}
#[test]
fn latest_extends_modern_with_line_number() {
let modern = HancomStyleSet::Modern.default_styles();
let latest = HancomStyleSet::Latest.default_styles();
assert_eq!(&latest[..22], modern);
assert_eq!(latest[22].name, "줄 번호");
assert_eq!(latest[22].style_type, "CHAR");
}
#[test]
fn style_id_for_name_korean_outline1() {
assert_eq!(HancomStyleSet::Modern.style_id_for_name("개요 1"), Some(2));
}
#[test]
fn style_id_for_name_english_outline1() {
assert_eq!(HancomStyleSet::Modern.style_id_for_name("Outline 1"), Some(2));
}
#[test]
fn style_id_for_name_batanggeul_is_0() {
assert_eq!(HancomStyleSet::Modern.style_id_for_name("바탕글"), Some(0));
assert_eq!(HancomStyleSet::Modern.style_id_for_name("Normal"), Some(0));
}
#[test]
fn style_id_for_name_unknown_returns_none() {
assert_eq!(HancomStyleSet::Modern.style_id_for_name("unknown"), None);
assert_eq!(HancomStyleSet::Modern.style_id_for_name(""), None);
}
#[test]
fn style_id_for_name_classic_vs_modern_differ() {
assert_eq!(HancomStyleSet::Classic.style_id_for_name("쪽 번호"), Some(9));
assert_eq!(HancomStyleSet::Modern.style_id_for_name("쪽 번호"), Some(12));
}
#[test]
fn modern_char_pr_groups_in_range() {
for entry in HancomStyleSet::Modern.default_styles() {
assert!(
entry.char_pr_group < 7,
"charPr group {} out of range for {}",
entry.char_pr_group,
entry.name
);
}
}
#[test]
fn modern_para_pr_groups_in_range() {
for entry in HancomStyleSet::Modern.default_styles() {
assert!(
entry.para_pr_group < 20,
"paraPr group {} out of range for {}",
entry.para_pr_group,
entry.name
);
}
}
#[test]
fn modern_batanggeul_uses_group_0() {
let styles = HancomStyleSet::Modern.default_styles();
assert_eq!(styles[0].char_pr_group, 0); assert_eq!(styles[0].para_pr_group, 0); }
#[test]
fn modern_outline8_uses_nonconsecutive_para_pr() {
let styles = HancomStyleSet::Modern.default_styles();
assert_eq!(styles[9].name, "개요 8");
assert_eq!(styles[9].para_pr_group, 18);
assert_eq!(styles[10].name, "개요 9");
assert_eq!(styles[10].para_pr_group, 16);
assert_eq!(styles[11].name, "개요 10");
assert_eq!(styles[11].para_pr_group, 17);
}
#[test]
fn modern_footnote_endnote_share_para_pr() {
let styles = HancomStyleSet::Modern.default_styles();
let footnote = styles.iter().find(|e| e.name == "각주").unwrap();
let endnote = styles.iter().find(|e| e.name == "미주").unwrap();
assert_eq!(footnote.para_pr_group, endnote.para_pr_group);
assert_eq!(footnote.char_pr_group, endnote.char_pr_group);
}
#[test]
fn modern_toc_entries_share_char_pr() {
let styles = HancomStyleSet::Modern.default_styles();
let toc1 = styles.iter().find(|e| e.name == "차례 1").unwrap();
let toc2 = styles.iter().find(|e| e.name == "차례 2").unwrap();
let toc3 = styles.iter().find(|e| e.name == "차례 3").unwrap();
assert_eq!(toc1.char_pr_group, 6);
assert_eq!(toc2.char_pr_group, 6);
assert_eq!(toc3.char_pr_group, 6);
}
}