1use crate::cache;
4
5#[cfg(feature = "object-cache-dynamic")]
6mod memory {
7 use crate::{cache, cache::set_vec_to_slice};
8 use clru::WeightScale;
9 use std::num::NonZeroUsize;
10
11 struct Entry {
12 data: Vec<u8>,
13 kind: gix_object::Kind,
14 }
15
16 type Key = gix_hash::ObjectId;
17
18 struct CustomScale;
19
20 impl WeightScale<Key, Entry> for CustomScale {
21 fn weight(&self, key: &Key, value: &Entry) -> usize {
22 value.data.len() + std::mem::size_of::<Entry>() + key.as_bytes().len()
23 }
24 }
25
26 pub struct MemoryCappedHashmap {
28 inner: clru::CLruCache<Key, Entry, gix_hashtable::hash::Builder, CustomScale>,
29 free_list: Vec<Vec<u8>>,
30 debug: gix_features::cache::Debug,
31 }
32
33 impl MemoryCappedHashmap {
34 pub fn capacity(&self) -> usize {
36 self.inner.capacity()
37 }
38 pub fn new(memory_cap_in_bytes: usize) -> MemoryCappedHashmap {
41 MemoryCappedHashmap {
42 inner: clru::CLruCache::with_config(
43 clru::CLruCacheConfig::new(NonZeroUsize::new(memory_cap_in_bytes).expect("non zero"))
44 .with_hasher(gix_hashtable::hash::Builder)
45 .with_scale(CustomScale),
46 ),
47 free_list: Vec::new(),
48 debug: gix_features::cache::Debug::new(format!("MemoryCappedObjectHashmap({memory_cap_in_bytes}B)")),
49 }
50 }
51 }
52
53 impl cache::Object for MemoryCappedHashmap {
54 fn put(&mut self, id: gix_hash::ObjectId, kind: gix_object::Kind, data: &[u8]) {
56 self.debug.put();
57 let Some(data) = set_vec_to_slice(self.free_list.pop().unwrap_or_default(), data) else {
58 return;
59 };
60 let res = self.inner.put_with_weight(id, Entry { data, kind });
61 match res {
62 Ok(Some(previous_entry)) => self.free_list.push(previous_entry.data),
63 Ok(None) => {}
64 Err((_key, value)) => self.free_list.push(value.data),
65 }
66 }
67
68 fn get(&mut self, id: &gix_hash::ObjectId, out: &mut Vec<u8>) -> Option<gix_object::Kind> {
70 let res = self.inner.get(id).and_then(|e| {
71 set_vec_to_slice(out, &e.data)?;
72 Some(e.kind)
73 });
74 if res.is_some() {
75 self.debug.hit();
76 } else {
77 self.debug.miss();
78 }
79 res
80 }
81 }
82}
83#[cfg(feature = "object-cache-dynamic")]
84pub use memory::MemoryCappedHashmap;
85
86pub struct Never;
88
89impl cache::Object for Never {
90 fn put(&mut self, _id: gix_hash::ObjectId, _kind: gix_object::Kind, _data: &[u8]) {}
92
93 fn get(&mut self, _id: &gix_hash::ObjectId, _out: &mut Vec<u8>) -> Option<gix_object::Kind> {
95 None
96 }
97}
98
99impl<T: cache::Object + ?Sized> cache::Object for Box<T> {
100 fn put(&mut self, id: gix_hash::ObjectId, kind: gix_object::Kind, data: &[u8]) {
101 use std::ops::DerefMut;
102 self.deref_mut().put(id, kind, data);
103 }
104
105 fn get(&mut self, id: &gix_hash::ObjectId, out: &mut Vec<u8>) -> Option<gix_object::Kind> {
106 use std::ops::DerefMut;
107 self.deref_mut().get(id, out)
108 }
109}