use std::collections::HashMap;
use std::sync::OnceLock;
const AGL_GLYPHLIST: &str = include_str!("agl-glyphlist.txt");
fn table() -> &'static HashMap<&'static str, Vec<u32>> {
static TABLE: OnceLock<HashMap<&'static str, Vec<u32>>> = OnceLock::new();
TABLE.get_or_init(|| {
let mut map = HashMap::new();
for line in AGL_GLYPHLIST.lines() {
let line = line.trim();
if line.is_empty() || line.starts_with('#') {
continue;
}
let Some((name, values)) = line.split_once(';') else {
continue;
};
let mut cps = Vec::new();
let mut ok = true;
for hex in values.split(' ') {
if hex.is_empty() {
continue;
}
match u32::from_str_radix(hex, 16) {
Ok(v) => cps.push(v),
Err(_) => {
ok = false;
break;
}
}
}
if ok && !cps.is_empty() {
map.insert(name, cps);
}
}
map
})
}
pub fn glyph_name_to_codepoints(name: &str) -> Option<&'static [u32]> {
table().get(name).map(|v| v.as_slice())
}
pub fn glyph_name_to_char(name: &str) -> Option<char> {
match glyph_name_to_codepoints(name)? {
[cp] => char::from_u32(*cp),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn resolves_basic_latin() {
assert_eq!(glyph_name_to_char("A"), Some('A'));
assert_eq!(glyph_name_to_char("space"), Some(' '));
assert_eq!(glyph_name_to_char("zero"), Some('0'));
assert_eq!(glyph_name_to_char("exclam"), Some('!'));
}
#[test]
fn resolves_accented() {
assert_eq!(glyph_name_to_char("AEacute"), Some('\u{01FC}'));
assert_eq!(glyph_name_to_char("AE"), Some('\u{00C6}'));
}
#[test]
fn unknown_name_is_none() {
assert!(glyph_name_to_codepoints("definitely_not_a_glyph_name").is_none());
assert!(glyph_name_to_char("definitely_not_a_glyph_name").is_none());
}
#[test]
fn multi_codepoint_sequence() {
let seq = glyph_name_to_codepoints("dalethatafpatah").expect("present in AGL");
assert_eq!(seq, &[0x05D3, 0x05B2]);
assert_eq!(glyph_name_to_char("dalethatafpatah"), None);
}
#[test]
fn ligature_maps_to_presentation_form() {
let seq = glyph_name_to_codepoints("fi").expect("present in AGL");
assert_eq!(seq, &[0xFB01]);
assert_eq!(glyph_name_to_char("fi"), Some('\u{FB01}'));
assert_eq!(glyph_name_to_char("ffi"), Some('\u{FB03}'));
}
#[test]
fn table_is_nonempty_and_stable() {
assert!(table().len() > 4000, "AGL table unexpectedly small");
let a = table() as *const _;
let b = table() as *const _;
assert_eq!(a, b);
}
#[test]
fn comment_and_blank_lines_skipped() {
assert!(glyph_name_to_codepoints("Copyright").is_none());
assert!(glyph_name_to_codepoints("").is_none());
}
}