use skrifa::{FontRef, MetadataProvider as _};
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum Standing {
Canonical,
Compatibility,
Private,
}
fn standing(code: u32) -> Standing {
match code {
0xE000..=0xF8FF | 0xF_0000..=0x10_FFFF => Standing::Private,
0x2E80..=0x2FDF
| 0xF900..=0xFAFF
| 0x2_F800..=0x2_FA1F
| 0xFB00..=0xFDFF
| 0xFE30..=0xFE4F
| 0xFE70..=0xFEFF
| 0xFF00..=0xFFEF => Standing::Compatibility,
_ => Standing::Canonical,
}
}
pub(crate) fn reverse(font: &FontRef<'_>) -> HashMap<u32, char> {
let mut best: HashMap<u32, char> = HashMap::new();
for (code, glyph) in font.charmap().mappings() {
let Some(found) = char::from_u32(code) else {
continue;
};
best.entry(glyph.to_u32())
.and_modify(|held| {
if rank(found) < rank(*held) {
*held = found;
}
})
.or_insert(found);
}
best
}
fn rank(c: char) -> (Standing, u32) {
(standing(u32::from(c)), u32::from(c))
}
#[cfg(test)]
mod tests {
use super::{Standing, rank, standing};
const CASES: &[(char, Standing)] = &[
('a', Standing::Canonical),
('一', Standing::Canonical),
('⼀', Standing::Compatibility),
('⺀', Standing::Compatibility),
('\u{F900}', Standing::Compatibility),
('fi', Standing::Compatibility),
('A', Standing::Compatibility),
('\u{E000}', Standing::Private),
];
#[test]
fn code_points_stand_where_the_table_says() {
for &(c, want) in CASES {
assert_eq!(standing(u32::from(c)), want, "{c:?}");
}
}
#[test]
fn the_ideograph_beats_the_radical_it_shares_a_glyph_with() {
assert!(rank('一') < rank('⼀'));
assert!(rank(' ') < rank('\u{A0}'));
}
}