pub const GLYPH_CACHE_SIZE: usize = 4_000;
#[derive(Debug, Clone)]
pub struct GlyphEntry {
pub width: u16,
pub height: u16,
pub pixels: Vec<u8>,
}
pub struct GlyphCache {
entries: Vec<Option<GlyphEntry>>,
}
impl GlyphCache {
pub fn new() -> Self {
let mut entries = Vec::with_capacity(GLYPH_CACHE_SIZE);
entries.resize_with(GLYPH_CACHE_SIZE, || None);
Self { entries }
}
pub fn get(&self, index: u16) -> Option<&GlyphEntry> {
self.entries.get(usize::from(index)).and_then(|slot| slot.as_ref())
}
pub fn store(&mut self, index: u16, entry: GlyphEntry) -> bool {
let idx = usize::from(index);
if idx < GLYPH_CACHE_SIZE {
self.entries[idx] = Some(entry);
true
} else {
false
}
}
pub fn reset(&mut self) {
for slot in &mut self.entries {
*slot = None;
}
}
}
impl Default for GlyphCache {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn store_and_retrieve() {
let mut cache = GlyphCache::new();
let entry = GlyphEntry {
width: 8,
height: 16,
pixels: vec![0xFF; 8 * 16 * 4],
};
assert!(cache.store(42, entry));
let retrieved = cache.get(42).unwrap();
assert_eq!(retrieved.width, 8);
assert_eq!(retrieved.height, 16);
}
#[test]
fn get_empty_returns_none() {
let cache = GlyphCache::new();
assert!(cache.get(0).is_none());
assert!(cache.get(3999).is_none());
}
#[test]
fn reject_out_of_range() {
let mut cache = GlyphCache::new();
let entry = GlyphEntry {
width: 1,
height: 1,
pixels: vec![0; 4],
};
assert!(!cache.store(4000, entry));
}
}