use std::collections::BTreeSet;
use std::hash::{Hash, Hasher};
use std::ops::Add;
use rustc_hash::FxHashMap;
#[derive(Debug, Clone)]
pub struct Remapper<C, T> {
counter: C,
forward: FxHashMap<T, T>,
backward: Vec<T>,
}
impl<C, T: Hash> Hash for Remapper<C, T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.backward.hash(state);
}
}
impl<C, T: PartialEq + Hash> PartialEq for Remapper<C, T> {
fn eq(&self, other: &Self) -> bool {
self.backward == other.backward
}
}
impl<C, T: PartialEq + Hash> Eq for Remapper<C, T> {}
pub trait CheckedAdd: Sized + Add<Self, Output = Self> {
fn checked_add(&self, v: &Self) -> Option<Self>;
}
impl CheckedAdd for u8 {
fn checked_add(&self, v: &Self) -> Option<Self> {
u8::checked_add(*self, *v)
}
}
impl CheckedAdd for u16 {
fn checked_add(&self, v: &Self) -> Option<Self> {
u16::checked_add(*self, *v)
}
}
impl CheckedAdd for u32 {
fn checked_add(&self, v: &Self) -> Option<Self> {
u32::checked_add(*self, *v)
}
}
impl<C, T> Remapper<C, T>
where
C: CheckedAdd + Copy + From<u8>,
T: From<C> + Copy + From<u8> + Eq + Hash,
{
pub fn new() -> Self
where
C: Default,
{
Self {
counter: C::default(),
forward: FxHashMap::default(),
backward: Vec::new(),
}
}
pub fn get(&self, old: T) -> Option<T> {
self.forward.get(&old).copied()
}
pub fn remap(&mut self, old: T) -> T {
*self.forward.entry(old).or_insert_with(|| {
let value = self.counter;
self.backward.push(old);
self.counter = self
.counter
.checked_add(&C::from(1))
.expect("remapper was overflowed");
value.into()
})
}
pub fn len(&self) -> C {
self.counter
}
pub fn sorted_iter(&self) -> impl Iterator<Item = T> + '_ {
self.backward.iter().copied()
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct GlyphRemapper(Remapper<u16, u16>);
impl Default for GlyphRemapper {
fn default() -> Self {
let mut remapper = Remapper::new();
remapper.remap(0);
Self(remapper)
}
}
impl GlyphRemapper {
pub fn new() -> Self {
Self::default()
}
pub fn new_from_glyphs(glyphs: &[u16]) -> Self {
let mut map = Self::new();
for glyph in glyphs {
map.remap(*glyph);
}
map
}
pub fn new_from_glyphs_sorted(glyphs: &[u16]) -> Self {
let mut sorted =
BTreeSet::from_iter(glyphs).iter().map(|g| **g).collect::<Vec<_>>();
sorted.sort();
GlyphRemapper::new_from_glyphs(&sorted)
}
pub fn num_gids(&self) -> u16 {
self.0.len()
}
#[inline]
pub fn remap(&mut self, old: u16) -> u16 {
self.0.remap(old)
}
#[inline]
pub fn get(&self, old: u16) -> Option<u16> {
self.0.get(old)
}
pub fn remapped_gids(&self) -> impl Iterator<Item = u16> + '_ {
self.0.backward.iter().copied()
}
}