1use crate::{data, find};
2
3pub trait Find {
15 type Error: std::error::Error + Send + Sync + 'static;
17
18 fn contains(&self, id: impl AsRef<git_hash::oid>) -> bool;
20
21 fn try_find<'a>(
28 &self,
29 id: impl AsRef<git_hash::oid>,
30 buffer: &'a mut Vec<u8>,
31 ) -> Result<Option<(git_object::Data<'a>, Option<data::entry::Location>)>, Self::Error> {
32 self.try_find_cached(id, buffer, &mut crate::cache::Never)
33 }
34
35 fn try_find_cached<'a>(
42 &self,
43 id: impl AsRef<git_hash::oid>,
44 buffer: &'a mut Vec<u8>,
45 pack_cache: &mut impl crate::cache::DecodeEntry,
46 ) -> Result<Option<(git_object::Data<'a>, Option<data::entry::Location>)>, Self::Error>;
47
48 fn location_by_oid(&self, id: impl AsRef<git_hash::oid>, buf: &mut Vec<u8>) -> Option<data::entry::Location>;
53
54 fn pack_offsets_and_oid(&self, pack_id: u32) -> Option<Vec<(data::Offset, git_hash::ObjectId)>>;
56
57 fn entry_by_location(&self, location: &data::entry::Location) -> Option<find::Entry>;
67}
68
69mod ext {
70 use git_object::{BlobRef, CommitRef, CommitRefIter, Kind, ObjectRef, TagRef, TagRefIter, TreeRef, TreeRefIter};
71
72 use crate::find;
73
74 macro_rules! make_obj_lookup {
75 ($method:ident, $object_variant:path, $object_kind:path, $object_type:ty) => {
76 fn $method<'a>(
79 &self,
80 id: impl AsRef<git_hash::oid>,
81 buffer: &'a mut Vec<u8>,
82 ) -> Result<($object_type, Option<crate::data::entry::Location>), find::existing_object::Error<Self::Error>>
83 {
84 let id = id.as_ref();
85 self.try_find(id, buffer)
86 .map_err(find::existing_object::Error::Find)?
87 .ok_or_else(|| find::existing_object::Error::NotFound {
88 oid: id.as_ref().to_owned(),
89 })
90 .and_then(|(o, l)| {
91 o.decode()
92 .map_err(find::existing_object::Error::Decode)
93 .map(|o| (o, l))
94 })
95 .and_then(|(o, l)| match o {
96 $object_variant(o) => return Ok((o, l)),
97 _other => Err(find::existing_object::Error::ObjectKind {
98 expected: $object_kind,
99 }),
100 })
101 }
102 };
103 }
104
105 macro_rules! make_iter_lookup {
106 ($method:ident, $object_kind:path, $object_type:ty, $into_iter:tt) => {
107 fn $method<'a>(
110 &self,
111 id: impl AsRef<git_hash::oid>,
112 buffer: &'a mut Vec<u8>,
113 ) -> Result<($object_type, Option<crate::data::entry::Location>), find::existing_iter::Error<Self::Error>> {
114 let id = id.as_ref();
115 self.try_find(id, buffer)
116 .map_err(find::existing_iter::Error::Find)?
117 .ok_or_else(|| find::existing_iter::Error::NotFound {
118 oid: id.as_ref().to_owned(),
119 })
120 .and_then(|(o, l)| {
121 o.$into_iter()
122 .ok_or_else(|| find::existing_iter::Error::ObjectKind {
123 expected: $object_kind,
124 })
125 .map(|i| (i, l))
126 })
127 }
128 };
129 }
130
131 pub trait FindExt: super::Find {
133 fn find<'a>(
135 &self,
136 id: impl AsRef<git_hash::oid>,
137 buffer: &'a mut Vec<u8>,
138 ) -> Result<(git_object::Data<'a>, Option<crate::data::entry::Location>), find::existing::Error<Self::Error>>
139 {
140 let id = id.as_ref();
141 self.try_find(id, buffer)
142 .map_err(find::existing::Error::Find)?
143 .ok_or_else(|| find::existing::Error::NotFound {
144 oid: id.as_ref().to_owned(),
145 })
146 }
147
148 make_obj_lookup!(find_commit, ObjectRef::Commit, Kind::Commit, CommitRef<'a>);
149 make_obj_lookup!(find_tree, ObjectRef::Tree, Kind::Tree, TreeRef<'a>);
150 make_obj_lookup!(find_tag, ObjectRef::Tag, Kind::Tag, TagRef<'a>);
151 make_obj_lookup!(find_blob, ObjectRef::Blob, Kind::Blob, BlobRef<'a>);
152 make_iter_lookup!(find_commit_iter, Kind::Blob, CommitRefIter<'a>, try_into_commit_iter);
153 make_iter_lookup!(find_tree_iter, Kind::Tree, TreeRefIter<'a>, try_into_tree_iter);
154 make_iter_lookup!(find_tag_iter, Kind::Tag, TagRefIter<'a>, try_into_tag_iter);
155 }
156
157 impl<T: super::Find> FindExt for T {}
158}
159pub use ext::FindExt;
160
161mod find_impls {
162 use std::{ops::Deref, rc::Rc};
163
164 use git_hash::oid;
165
166 use crate::{data, find};
167
168 impl<T> crate::Find for &T
169 where
170 T: crate::Find,
171 {
172 type Error = T::Error;
173
174 fn contains(&self, id: impl AsRef<oid>) -> bool {
175 (*self).contains(id)
176 }
177
178 fn try_find_cached<'a>(
179 &self,
180 id: impl AsRef<oid>,
181 buffer: &'a mut Vec<u8>,
182 pack_cache: &mut impl crate::cache::DecodeEntry,
183 ) -> Result<Option<(git_object::Data<'a>, Option<data::entry::Location>)>, Self::Error> {
184 (*self).try_find_cached(id, buffer, pack_cache)
185 }
186
187 fn location_by_oid(&self, id: impl AsRef<oid>, buf: &mut Vec<u8>) -> Option<data::entry::Location> {
188 (*self).location_by_oid(id, buf)
189 }
190
191 fn pack_offsets_and_oid(&self, pack_id: u32) -> Option<Vec<(data::Offset, git_hash::ObjectId)>> {
192 (*self).pack_offsets_and_oid(pack_id)
193 }
194
195 fn entry_by_location(&self, location: &data::entry::Location) -> Option<find::Entry> {
196 (*self).entry_by_location(location)
197 }
198 }
199
200 impl<T> super::Find for std::sync::Arc<T>
201 where
202 T: super::Find,
203 {
204 type Error = T::Error;
205
206 fn contains(&self, id: impl AsRef<oid>) -> bool {
207 self.deref().contains(id)
208 }
209
210 fn try_find_cached<'a>(
211 &self,
212 id: impl AsRef<oid>,
213 buffer: &'a mut Vec<u8>,
214 pack_cache: &mut impl crate::cache::DecodeEntry,
215 ) -> Result<Option<(git_object::Data<'a>, Option<data::entry::Location>)>, Self::Error> {
216 self.deref().try_find_cached(id, buffer, pack_cache)
217 }
218
219 fn location_by_oid(&self, id: impl AsRef<oid>, buf: &mut Vec<u8>) -> Option<data::entry::Location> {
220 self.deref().location_by_oid(id, buf)
221 }
222
223 fn pack_offsets_and_oid(&self, pack_id: u32) -> Option<Vec<(data::Offset, git_hash::ObjectId)>> {
224 self.deref().pack_offsets_and_oid(pack_id)
225 }
226
227 fn entry_by_location(&self, object: &data::entry::Location) -> Option<find::Entry> {
228 self.deref().entry_by_location(object)
229 }
230 }
231
232 impl<T> super::Find for Rc<T>
233 where
234 T: super::Find,
235 {
236 type Error = T::Error;
237
238 fn contains(&self, id: impl AsRef<oid>) -> bool {
239 self.deref().contains(id)
240 }
241
242 fn try_find_cached<'a>(
243 &self,
244 id: impl AsRef<oid>,
245 buffer: &'a mut Vec<u8>,
246 pack_cache: &mut impl crate::cache::DecodeEntry,
247 ) -> Result<Option<(git_object::Data<'a>, Option<data::entry::Location>)>, Self::Error> {
248 self.deref().try_find_cached(id, buffer, pack_cache)
249 }
250
251 fn location_by_oid(&self, id: impl AsRef<oid>, buf: &mut Vec<u8>) -> Option<data::entry::Location> {
252 self.deref().location_by_oid(id, buf)
253 }
254
255 fn pack_offsets_and_oid(&self, pack_id: u32) -> Option<Vec<(data::Offset, git_hash::ObjectId)>> {
256 self.deref().pack_offsets_and_oid(pack_id)
257 }
258
259 fn entry_by_location(&self, location: &data::entry::Location) -> Option<find::Entry> {
260 self.deref().entry_by_location(location)
261 }
262 }
263
264 impl<T> super::Find for Box<T>
265 where
266 T: super::Find,
267 {
268 type Error = T::Error;
269
270 fn contains(&self, id: impl AsRef<oid>) -> bool {
271 self.deref().contains(id)
272 }
273
274 fn try_find_cached<'a>(
275 &self,
276 id: impl AsRef<oid>,
277 buffer: &'a mut Vec<u8>,
278 pack_cache: &mut impl crate::cache::DecodeEntry,
279 ) -> Result<Option<(git_object::Data<'a>, Option<data::entry::Location>)>, Self::Error> {
280 self.deref().try_find_cached(id, buffer, pack_cache)
281 }
282
283 fn location_by_oid(&self, id: impl AsRef<oid>, buf: &mut Vec<u8>) -> Option<data::entry::Location> {
284 self.deref().location_by_oid(id, buf)
285 }
286
287 fn pack_offsets_and_oid(&self, pack_id: u32) -> Option<Vec<(data::Offset, git_hash::ObjectId)>> {
288 self.deref().pack_offsets_and_oid(pack_id)
289 }
290
291 fn entry_by_location(&self, location: &data::entry::Location) -> Option<find::Entry> {
292 self.deref().entry_by_location(location)
293 }
294 }
295}