use read_fonts::ps::agl;
#[must_use]
pub fn unicode_from_adobe_name(name: &[u8]) -> u16 {
let Ok(name) = std::str::from_utf8(name) else {
return 0;
};
agl::name_to_char(name).map_or(0, |c| c as u16)
}
#[must_use]
pub fn adobe_name_from_unicode(unicode: u16) -> Option<String> {
if unicode == 0 {
return None;
}
let mut buf = [0u8; agl::MAX_NAME_LEN];
agl::char_to_name(u32::from(unicode), &mut buf).map(ToOwned::to_owned)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unicode_from_adobe_name_matches_the_oracle() {
for (name, expected) in [
(&b"nonesuch"[..], 0x0000),
(b"", 0x0000),
(b"paragraph", 0x00B6),
(b"Oacute", 0x00D3),
(b"thorn", 0x00FE),
(b"tonos", 0x0384),
(b"bullet", 0x2022),
] {
assert_eq!(
unicode_from_adobe_name(name),
expected,
"{:?}",
std::str::from_utf8(name)
);
}
}
#[test]
fn adobe_name_from_unicode_matches_the_oracle() {
for (unicode, expected) in [
(0x0000u16, None),
(0x00F7, Some("divide")),
(0x0141, Some("Lslash")),
(0x0384, Some("tonos")),
(0x0691, Some("afii57513")),
(0x0E5A, Some("angkhankhuthai")),
(0x20AC, Some("Euro")),
] {
assert_eq!(
adobe_name_from_unicode(unicode).as_deref(),
expected,
"U+{unicode:04X}"
);
}
}
#[test]
fn synthetic_spellings_resolve() {
assert_eq!(unicode_from_adobe_name(b"uni0041"), 0x0041);
assert_eq!(unicode_from_adobe_name(b"uni20AC"), 0x20AC);
assert_eq!(unicode_from_adobe_name(b"u0041"), 0x0041);
assert_eq!(unicode_from_adobe_name(b"u00041"), 0x0041);
}
#[test]
fn the_variant_suffix_is_stripped() {
assert_eq!(unicode_from_adobe_name(b"A.swash"), 0x0041);
assert_eq!(unicode_from_adobe_name(b"A.alt"), 0x0041);
assert_eq!(unicode_from_adobe_name(b"A"), 0x0041);
}
#[test]
fn non_utf8_names_map_to_nothing_rather_than_panicking() {
assert_eq!(unicode_from_adobe_name(&[0xff, 0xfe, 0x00]), 0);
}
#[test]
fn the_two_directions_agree_on_the_names_that_have_one() {
for u in [0x41u16, 0xF7, 0x141, 0x384, 0x20AC, 0x2022] {
let name = adobe_name_from_unicode(u).expect("has a name");
assert_eq!(unicode_from_adobe_name(name.as_bytes()), u);
}
}
}