mkwebfont_fontops 0.4.0

Internal crate for mkwebfont.
Documentation
use bincode::{config::standard, Decode, Encode};
use mkwebfont_common::{
    character_set::{CharacterSet, CompressedCharacterSet},
    compression::zstd_decompress,
};
use std::{
    collections::HashMap,
    sync::{Arc, LazyLock},
};

#[derive(Clone, Debug)]
pub struct WebfontData {
    pub by_name: HashMap<Arc<str>, Arc<WebfontSubset>>,
    pub subsets: Vec<Arc<WebfontSubset>>,
    pub groups: Vec<Arc<WebfontSubsetGroup>>,
}
impl WebfontData {
    pub fn load<'a>() -> &'a WebfontData {
        static CACHE: LazyLock<WebfontData> = LazyLock::new(|| {
            let data = include_bytes!("gfonts_subsets.bin.zst");
            let decompressed = zstd_decompress(data).unwrap();
            let out: RawSubsets = bincode::decode_from_slice(&decompressed, standard())
                .unwrap()
                .0;
            out.build()
        });
        &*CACHE
    }
}

#[derive(Clone, Debug)]
pub struct WebfontSubsetGroup {
    pub name: Arc<str>,
    pub subsets: Vec<Arc<WebfontSubset>>,
}

#[derive(Clone, Debug)]
pub struct WebfontSubset {
    pub name: Arc<str>,
    pub map: CharacterSet,
}

#[derive(Clone, Debug, Encode, Decode)]
pub struct RawSubset {
    pub name: String,
    pub group: Option<String>,
    pub chars: CompressedCharacterSet,
}

#[derive(Clone, Debug, Encode, Decode)]
pub struct RawSubsets {
    pub subsets: Vec<RawSubset>,
}

fn convert_subset(name: &str, chars: &CompressedCharacterSet) -> Arc<WebfontSubset> {
    Arc::new(WebfontSubset { name: name.into(), map: CharacterSet::decompress(chars) })
}
fn build_by_name(subsets: &[Arc<WebfontSubset>]) -> HashMap<Arc<str>, Arc<WebfontSubset>> {
    let mut by_name = HashMap::new();
    for subset in subsets {
        by_name.insert(subset.name.clone(), subset.clone());
    }
    by_name
}
fn split_groups(
    group_names: &HashMap<String, String>,
    subsets: Vec<Arc<WebfontSubset>>,
) -> (Vec<Arc<WebfontSubset>>, Vec<Arc<WebfontSubsetGroup>>) {
    let (has_group, no_group) = subsets
        .into_iter()
        .partition::<Vec<_>, _>(|x| group_names.contains_key(x.name.as_ref()));
    let mut groups: HashMap<_, Vec<_>> = HashMap::new();
    for group in has_group {
        groups
            .entry(group_names.get(group.name.as_ref()).unwrap().clone())
            .or_default()
            .push(group);
    }
    let groups: Vec<_> = groups
        .into_iter()
        .map(|(k, v)| Arc::new(WebfontSubsetGroup { name: k.into(), subsets: v }))
        .collect();
    (no_group, groups)
}

impl RawSubsets {
    fn build(&self) -> WebfontData {
        let groups: HashMap<_, _> = self
            .subsets
            .iter()
            .flat_map(|v| v.group.as_ref().map(|g| (v.name.clone(), g.clone())))
            .collect();
        let subsets: Vec<_> = self
            .subsets
            .iter()
            .map(|v| convert_subset(&v.name, &v.chars))
            .collect();
        let by_name = build_by_name(&subsets);
        let (subsets, groups) = split_groups(&groups, subsets);
        WebfontData { by_name, subsets, groups }
    }
}