1use std::collections::HashMap;
2
3use crate::page::{RenderSize, RenderedPage};
4
5pub struct PageCache {
10 entries: HashMap<CacheKey, RenderedPage>,
11 order: Vec<CacheKey>,
12 capacity: usize,
13}
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16struct CacheKey {
17 page_index: usize,
18 size: RenderSize,
19}
20
21impl PageCache {
22 pub fn new(capacity: usize) -> Self {
24 Self {
25 entries: HashMap::with_capacity(capacity),
26 order: Vec::with_capacity(capacity),
27 capacity,
28 }
29 }
30
31 pub fn get(&mut self, page_index: usize, size: RenderSize) -> Option<&RenderedPage> {
33 let key = CacheKey { page_index, size };
34 if self.entries.contains_key(&key) {
35 self.order.retain(|k| *k != key);
37 self.order.push(key);
38 self.entries.get(&key)
39 } else {
40 None
41 }
42 }
43
44 pub fn insert(&mut self, page_index: usize, size: RenderSize, page: RenderedPage) {
46 let key = CacheKey { page_index, size };
47
48 if self.entries.len() >= self.capacity && !self.entries.contains_key(&key) {
49 if let Some(evicted) = self.order.first().copied() {
51 self.order.remove(0);
52 self.entries.remove(&evicted);
53 }
54 }
55
56 self.order.retain(|k| *k != key);
57 self.order.push(key);
58 self.entries.insert(key, page);
59 }
60
61 pub fn clear(&mut self) {
63 self.entries.clear();
64 self.order.clear();
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 fn dummy_page(id: u8) -> RenderedPage {
73 RenderedPage { data: vec![id; 4], width: 1, height: 1 }
74 }
75
76 #[test]
77 fn cache_insert_and_get() {
78 let mut cache = PageCache::new(5);
79 let size = RenderSize { width: 1920, height: 1080 };
80 cache.insert(0, size, dummy_page(0));
81 assert!(cache.get(0, size).is_some());
82 assert!(cache.get(1, size).is_none());
83 }
84
85 #[test]
86 fn cache_evicts_lru() {
87 let mut cache = PageCache::new(2);
88 let size = RenderSize { width: 1920, height: 1080 };
89 cache.insert(0, size, dummy_page(0));
90 cache.insert(1, size, dummy_page(1));
91 cache.insert(2, size, dummy_page(2)); assert!(cache.get(0, size).is_none());
93 assert!(cache.get(1, size).is_some());
94 assert!(cache.get(2, size).is_some());
95 }
96}