use lru::LruCache;
use std::num::NonZeroUsize;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RenderMode {
Greyscale,
Lcd,
Sdf,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BitmapCacheKey {
pub glyph_id: u16,
pub px_size_times_64: u32,
pub render_mode: RenderMode,
}
pub struct BitmapCache {
inner: LruCache<BitmapCacheKey, Vec<u8>>,
}
impl BitmapCache {
pub fn new(capacity: usize) -> Self {
let cap = NonZeroUsize::new(capacity.max(1))
.unwrap_or_else(|| NonZeroUsize::new(1).expect("1 is non-zero"));
Self {
inner: LruCache::new(cap),
}
}
pub fn get(&mut self, key: &BitmapCacheKey) -> Option<&Vec<u8>> {
self.inner.get(key)
}
pub fn insert(&mut self, key: BitmapCacheKey, data: Vec<u8>) {
self.inner.put(key, data);
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn clear(&mut self) {
self.inner.clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
fn make_key(glyph_id: u16) -> BitmapCacheKey {
BitmapCacheKey {
glyph_id,
px_size_times_64: 64,
render_mode: RenderMode::Greyscale,
}
}
#[test]
fn cache_hit_miss() {
let mut cache = BitmapCache::new(2);
let key = make_key(1);
assert!(cache.get(&key).is_none());
cache.insert(key, vec![255u8]);
assert_eq!(cache.get(&key), Some(&vec![255u8]));
}
#[test]
fn eviction() {
let mut cache = BitmapCache::new(1);
let k1 = make_key(1);
let k2 = make_key(2);
cache.insert(k1, vec![1u8]);
cache.insert(k2, vec![2u8]);
assert!(cache.get(&k1).is_none() || cache.get(&k2).is_some());
}
#[test]
fn len_and_is_empty() {
let mut cache = BitmapCache::new(4);
assert!(cache.is_empty());
cache.insert(make_key(1), vec![]);
assert_eq!(cache.len(), 1);
assert!(!cache.is_empty());
}
#[test]
fn capacity_zero_treated_as_one() {
let mut cache = BitmapCache::new(0);
cache.insert(make_key(1), vec![42u8]);
assert_eq!(cache.len(), 1);
}
}