use std::{collections::VecDeque, sync::Arc};
use super::{
VisualProjectionResult, visual_projection_identity::VisualProjectionIdentity,
visual_projection_retention::retained_bytes,
};
const MAX_ENTRIES: usize = 8;
const MAX_RETAINED_BYTES: usize = 32 * 1024 * 1024;
#[derive(Debug, Default)]
pub(super) struct VisualProjectionCache {
entries: VecDeque<(VisualProjectionIdentity, Arc<VisualProjectionResult>, usize)>,
retained: usize,
}
impl VisualProjectionCache {
pub(super) fn get(
&mut self,
identity: &VisualProjectionIdentity,
) -> Option<Arc<VisualProjectionResult>> {
let position = self
.entries
.iter()
.position(|(key, _, _)| key == identity)?;
let entry = self.entries.remove(position)?;
let result = Arc::clone(&entry.1);
self.entries.push_back(entry);
Some(result)
}
pub(super) fn put(
&mut self,
identity: VisualProjectionIdentity,
result: &VisualProjectionResult,
) {
self.entries
.retain(|(key, _, _)| key.revision == identity.revision && key != &identity);
self.retained = self.entries.iter().map(|entry| entry.2).sum();
let bytes = retained_bytes(&identity, result);
if bytes > MAX_RETAINED_BYTES {
return;
}
while self.entries.len() >= MAX_ENTRIES
|| self.retained.saturating_add(bytes) > MAX_RETAINED_BYTES
{
if let Some((_, _, charge)) = self.entries.pop_front() {
self.retained -= charge;
}
}
self.retained += bytes;
self.entries
.push_back((identity, Arc::new(result.clone()), bytes));
}
}
#[cfg(test)]
#[path = "visual_projection_cache_tests.rs"]
mod tests;