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