Skip to main content

git_zero_core/cache/selected/
fixed.rs

1use super::{Key, PackCache};
2use crate::{Error, Result};
3
4#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
5pub struct Statistics {
6    pub hits: u64,
7    pub misses: u64,
8    pub insertions: u64,
9    pub evictions: u64,
10}
11
12/// One immutable pack in caller-owned storage. Capacity failures preserve the
13/// previous entry. Disabling bypasses reads and insertions, retaining the entry
14/// until explicit eviction or replacement. Counters saturate at u64::MAX.
15pub struct FixedCache<'a> {
16    storage: &'a mut [u8],
17    entry: Option<(Key, usize)>,
18    enabled: bool,
19    statistics: Statistics,
20}
21
22impl<'a> FixedCache<'a> {
23    pub fn new(storage: &'a mut [u8]) -> Self {
24        Self {
25            storage,
26            entry: None,
27            enabled: true,
28            statistics: Statistics::default(),
29        }
30    }
31    pub fn set_enabled(&mut self, enabled: bool) {
32        self.enabled = enabled;
33    }
34    pub fn statistics(&self) -> Statistics {
35        self.statistics
36    }
37    pub fn evict(&mut self) {
38        if self.entry.take().is_some() {
39            self.statistics.evictions = self.statistics.evictions.saturating_add(1);
40        }
41    }
42}
43
44impl PackCache for FixedCache<'_> {
45    fn get(&mut self, key: Key) -> Result<Option<&[u8]>> {
46        if let Some((_, length)) = self
47            .entry
48            .filter(|(stored, _)| self.enabled && *stored == key)
49        {
50            self.statistics.hits = self.statistics.hits.saturating_add(1);
51            return Ok(Some(&self.storage[..length]));
52        }
53        self.statistics.misses = self.statistics.misses.saturating_add(1);
54        Ok(None)
55    }
56    fn put(&mut self, key: Key, pack: &[u8]) -> Result<()> {
57        if !self.enabled {
58            return Ok(());
59        }
60        let destination = self
61            .storage
62            .get_mut(..pack.len())
63            .ok_or(Error::BufferTooSmall)?;
64        destination.copy_from_slice(pack);
65        self.entry = Some((key, pack.len()));
66        self.statistics.insertions = self.statistics.insertions.saturating_add(1);
67        Ok(())
68    }
69}