sugarloaf 0.2.36

Sugarloaf is Rio rendering engine, designed to be multiplatform. It is based on WebGPU, Rust library for Desktops and WebAssembly for Web (JavaScript). This project is created and maintained for Rio terminal purposes but feel free to use it.
Documentation
// font_introspector was retired from https://github.com/dfrg/swash
// which is licensed under MIT license

use super::at::FeatureStore;
use super::engine::EngineMetadata;
use super::internal::var::Fvar;
use crate::font_introspector::{charmap::CharmapProxy, metrics::MetricsProxy, FontRef};
use tracing::debug;

pub type Epoch = u64;

pub struct FontEntry {
    pub metrics: MetricsProxy,
    pub charmap: CharmapProxy,
    pub coord_count: u16,
    pub metadata: EngineMetadata,
}

impl FontEntry {
    pub fn new(font: &FontRef) -> Self {
        Self {
            metrics: MetricsProxy::from_font(font),
            charmap: CharmapProxy::from_font(font),
            coord_count: Fvar::from_font(font)
                .map(|fvar| fvar.axis_count())
                .unwrap_or(0),
            metadata: EngineMetadata::from_font(font),
        }
    }
}

pub struct FeatureEntry {
    pub epoch: Epoch,
    pub id: [u64; 2],
    pub coords: Vec<i16>,
    pub tags: [u32; 4],
    pub store: FeatureStore,
}

pub struct FeatureCache {
    entries: Vec<FeatureEntry>,
    epoch: Epoch,
    max_entries: usize,
}

pub enum FeatureCacheEntry<'a> {
    New(&'a mut FeatureStore),
    Present(&'a mut FeatureStore),
}

impl FeatureCache {
    pub fn new(max_entries: usize) -> Self {
        Self {
            entries: Default::default(),
            epoch: 0,
            max_entries,
        }
    }

    pub fn entry<'a>(
        &'a mut self,
        id: [u64; 2],
        coords: &[i16],
        has_feature_vars: bool,
        tags: &[u32; 4],
    ) -> FeatureCacheEntry<'a> {
        match self.find_entry(id, coords, has_feature_vars, tags) {
            (true, index) => {
                let entry = &mut self.entries[index];
                entry.epoch = self.epoch;
                FeatureCacheEntry::Present(&mut entry.store)
            }
            (false, index) => {
                // Log cache miss for debugging
                debug!("FeatureCache miss for font_id={:?} tags={:?}", id, tags);
                self.epoch += 1;
                let entry = &mut self.entries[index];
                entry.epoch = self.epoch;
                FeatureCacheEntry::New(&mut entry.store)
            }
        }
    }

    fn find_entry(
        &mut self,
        id: [u64; 2],
        coords: &[i16],
        has_feature_vars: bool,
        tags: &[u32; 4],
    ) -> (bool, usize) {
        let epoch = self.epoch;
        let mut lowest_serial = epoch;
        let mut lowest_index = 0;
        for (i, entry) in self.entries.iter().enumerate() {
            if entry.id == id && &entry.tags == tags {
                if has_feature_vars && coords != &entry.coords[..] {
                    continue;
                }
                return (true, i);
            }
            if entry.epoch < lowest_serial {
                lowest_serial = entry.epoch;
                lowest_index = i;
            }
        }
        if self.entries.len() < self.max_entries {
            lowest_index = self.entries.len();
            self.entries.push(FeatureEntry {
                epoch,
                id,
                coords: Vec::from(coords),
                store: FeatureStore::default(),
                tags: *tags,
            });
        } else {
            let entry = &mut self.entries[lowest_index];
            entry.epoch = epoch;
            entry.id = id;
            entry.coords.clear();
            entry.coords.extend_from_slice(coords);
            entry.store.clear();
            entry.tags = *tags;
        }
        (false, lowest_index)
    }
}