use std::fmt::Display; use convert_case::{Case, Casing}; use deunicode::deunicode; pub mod chapter; pub mod replacement; pub mod section; #[derive(PartialEq, Eq, PartialOrd, Ord)] pub struct MangledName(String); impl MangledName { pub fn new(name: &str) -> Self { let safe_name = name // TeX fails to include/input stuff with a colon in it. .replace(':', "_") // This obviously creates weird extra directories .replace('/', "_"); let ascii_name = deunicode(&safe_name.to_case(Case::Snake)).to_case(Case::Snake); Self(ascii_name) } pub fn from_str_unsafe(name: &str) -> Self { Self(name.to_owned()) } pub fn check_mangled(name: &str) -> bool { let mangled = Self::new(name); let normal = Self::from_str_unsafe(name); mangled == normal } pub fn as_str(&self) -> &str { &self.0 } pub fn try_unmangle(self) -> String { self.0.to_case(Case::Title) } } impl Display for MangledName { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str(&self.0) } } #[cfg(test)] mod test { use crate::new::MangledName; #[test] fn test_names() { let name = MangledName::new("Æneid"); assert_eq!(name.to_string().as_str(), "aeneid"); let name = MangledName::new("étude"); assert_eq!(name.to_string().as_str(), "etude"); let name = MangledName::new("Ästhetik"); assert_eq!(name.to_string().as_str(), "asthetik"); let name = MangledName::new("北亰"); assert_eq!(name.to_string().as_str(), "bei_jing"); let name = MangledName::new("ᔕᓇᓇ"); assert_eq!(name.to_string().as_str(), "shanana"); let name = MangledName::new("げんまい茶"); assert_eq!(name.to_string().as_str(), "genmai_cha"); let name = MangledName::new("🦄☣"); assert_eq!(name.to_string().as_str(), "unicorn_biohazard"); } }