1use crate::find::Header;
2use crate::Cache;
3use gix_object::Data;
4use std::cell::RefCell;
5use std::ops::{Deref, DerefMut};
6use std::rc::Rc;
7use std::sync::Arc;
8
9pub struct Proxy<T> {
16 inner: T,
18 object_hash: gix_hash::Kind,
20 memory: Option<RefCell<Storage>>,
23}
24
25impl<T> Proxy<T> {
27 pub fn new(odb: T, object_hash: gix_hash::Kind) -> Proxy<T> {
31 Proxy {
32 inner: odb,
33 object_hash,
34 memory: Some(Default::default()),
35 }
36 }
37
38 pub fn into_inner(self) -> T {
40 self.inner
41 }
42
43 pub fn with_write_passthrough(mut self) -> Self {
47 self.memory.take();
48 self
49 }
50}
51
52impl Proxy<Cache<crate::store::Handle<Arc<crate::Store>>>> {
53 pub fn into_arc(self) -> std::io::Result<Proxy<Cache<crate::store::Handle<Arc<crate::Store>>>>> {
55 Ok(self)
56 }
57}
58
59impl Proxy<Cache<crate::store::Handle<Rc<crate::Store>>>> {
60 pub fn into_arc(self) -> std::io::Result<Proxy<Cache<crate::store::Handle<Arc<crate::Store>>>>> {
62 Ok(Proxy {
63 inner: self.inner.into_arc()?,
64 object_hash: self.object_hash,
65 memory: self.memory,
66 })
67 }
68}
69
70impl From<crate::Handle> for Proxy<crate::Handle> {
71 fn from(odb: crate::Handle) -> Self {
72 let object_hash = odb.store.object_hash;
73 Proxy::new(odb, object_hash)
74 }
75}
76
77impl<T> Proxy<T> {
79 pub fn take_object_memory(&mut self) -> Option<Storage> {
88 self.memory.take().map(RefCell::into_inner)
89 }
90
91 pub fn set_object_memory(&mut self, new: Storage) -> Option<Storage> {
93 let previous = self.take_object_memory();
94 self.memory = Some(RefCell::new(new));
95 previous
96 }
97
98 pub fn enable_object_memory(&mut self) -> &mut Self {
102 if self.memory.is_none() {
103 self.memory = Some(Default::default());
104 }
105 self
106 }
107
108 pub fn reset_object_memory(&self) -> Option<Storage> {
114 self.memory.as_ref().map(|m| std::mem::take(&mut *m.borrow_mut()))
115 }
116
117 pub fn num_objects_in_memory(&self) -> usize {
119 self.memory.as_ref().map_or(0, |m| m.borrow().len())
120 }
121}
122
123impl<T> Clone for Proxy<T>
124where
125 T: Clone,
126{
127 fn clone(&self) -> Self {
128 Proxy {
129 inner: self.inner.clone(),
130 object_hash: self.object_hash,
131 memory: self.memory.clone(),
132 }
133 }
134}
135
136impl<T> gix_object::Find for Proxy<T>
137where
138 T: gix_object::Find,
139{
140 fn try_find<'a>(
141 &self,
142 id: &gix_hash::oid,
143 buffer: &'a mut Vec<u8>,
144 ) -> Result<Option<Data<'a>>, gix_object::find::Error> {
145 if let Some(map) = self.memory.as_ref() {
146 let map = map.borrow();
147 if let Some((kind, data)) = map.get(id) {
148 buffer.clear();
149 buffer.extend_from_slice(data);
150 return Ok(Some(Data {
151 kind: *kind,
152 data: &*buffer,
153 }));
154 }
155 }
156 self.inner.try_find(id, buffer)
157 }
158}
159
160impl<T> gix_object::Exists for Proxy<T>
161where
162 T: gix_object::Exists,
163{
164 fn exists(&self, id: &gix_hash::oid) -> bool {
165 self.memory.as_ref().is_some_and(|map| map.borrow().contains_key(id)) || self.inner.exists(id)
166 }
167}
168
169impl<T> crate::Header for Proxy<T>
170where
171 T: crate::Header,
172{
173 fn try_header(&self, id: &gix_hash::oid) -> Result<Option<Header>, gix_object::find::Error> {
174 if let Some(map) = self.memory.as_ref() {
175 let map = map.borrow();
176 if let Some((kind, data)) = map.get(id) {
177 return Ok(Some(Header::Loose {
178 kind: *kind,
179 size: data.len() as u64,
180 }));
181 }
182 }
183 self.inner.try_header(id)
184 }
185}
186
187impl<T> gix_object::FindHeader for Proxy<T>
188where
189 T: gix_object::FindHeader,
190{
191 fn try_header(&self, id: &gix_hash::oid) -> Result<Option<gix_object::Header>, gix_object::find::Error> {
192 if let Some(map) = self.memory.as_ref() {
193 let map = map.borrow();
194 if let Some((kind, data)) = map.get(id) {
195 return Ok(Some(gix_object::Header {
196 kind: *kind,
197 size: data.len() as u64,
198 }));
199 }
200 }
201 self.inner.try_header(id)
202 }
203}
204
205impl<T> gix_object::Write for Proxy<T>
206where
207 T: gix_object::Write,
208{
209 fn write_stream(
210 &self,
211 kind: gix_object::Kind,
212 size: u64,
213 from: &mut dyn std::io::Read,
214 ) -> Result<gix_hash::ObjectId, gix_object::write::Error> {
215 let Some(map) = self.memory.as_ref() else {
216 return self.inner.write_stream(kind, size, from);
217 };
218
219 let mut buf = Vec::new();
220 from.read_to_end(&mut buf)?;
221
222 let id = gix_object::compute_hash(self.object_hash, kind, &buf);
223 map.borrow_mut().insert(id, (kind, buf));
224 Ok(id)
225 }
226}
227
228impl<T> Deref for Proxy<T> {
229 type Target = T;
230
231 fn deref(&self) -> &Self::Target {
232 &self.inner
233 }
234}
235
236impl<T> DerefMut for Proxy<T> {
237 fn deref_mut(&mut self) -> &mut Self::Target {
238 &mut self.inner
239 }
240}
241
242#[derive(Default, Debug, Clone, Eq, PartialEq)]
244pub struct Storage(gix_hashtable::HashMap<gix_hash::ObjectId, (gix_object::Kind, Vec<u8>)>);
245
246impl Deref for Storage {
247 type Target = gix_hashtable::HashMap<gix_hash::ObjectId, (gix_object::Kind, Vec<u8>)>;
248
249 fn deref(&self) -> &Self::Target {
250 &self.0
251 }
252}
253
254impl DerefMut for Storage {
255 fn deref_mut(&mut self) -> &mut Self::Target {
256 &mut self.0
257 }
258}