1use crate::{data, find};
2use gix_error::Result;
3
4pub trait Find {
16 fn contains(&self, id: &gix_hash::oid) -> bool;
18
19 fn try_find<'a>(
26 &self,
27 id: &gix_hash::oid,
28 buffer: &'a mut Vec<u8>,
29 ) -> Result<Option<(gix_object::Data<'a>, Option<data::entry::Location>)>> {
30 self.try_find_cached(id, buffer, &mut crate::cache::Never)
31 }
32
33 fn try_find_cached<'a>(
40 &self,
41 id: &gix_hash::oid,
42 buffer: &'a mut Vec<u8>,
43 pack_cache: &mut dyn crate::cache::DecodeEntry,
44 ) -> Result<Option<(gix_object::Data<'a>, Option<data::entry::Location>)>>;
45
46 fn location_by_oid(&self, id: &gix_hash::oid, buf: &mut Vec<u8>) -> Result<Option<data::entry::Location>>;
51
52 fn pack_offsets_and_oid(&self, pack_id: u32) -> Result<Option<Vec<(data::Offset, gix_hash::ObjectId)>>>;
56
57 fn entry_by_location(&self, location: &data::entry::Location) -> Option<find::Entry>;
67}
68
69mod ext {
70 use gix_error::{Error, Result};
71 use gix_error::{ResultExt, message};
72 use gix_object::{BlobRef, CommitRef, CommitRefIter, Kind, ObjectRef, TagRef, TagRefIter, TreeRef, TreeRefIter};
73
74 fn not_found(id: &gix_hash::oid) -> Error {
75 message!("An object with id {id} could not be found").not_found_error()
76 }
77
78 fn wrong_kind(id: &gix_hash::oid, actual: Kind, expected: Kind) -> Error {
79 message!("Expected object of kind {expected} but got {actual} at {id}").validation_error()
80 }
81
82 macro_rules! make_obj_lookup {
83 ($method:ident, $object_variant:path, $object_kind:path, $object_type:ty) => {
84 fn $method<'a>(
87 &self,
88 id: &gix_hash::oid,
89 buffer: &'a mut Vec<u8>,
90 ) -> Result<($object_type, Option<crate::data::entry::Location>)> {
91 let id = id.as_ref();
92 self.try_find(id, buffer)?
93 .ok_or_else(|| not_found(id))
94 .and_then(|(o, l)| {
95 o.decode()
96 .or_raise(|| message!("Could not decode object at {id}").corrupted())
97 .map(|o| (o, l))
98 })
99 .and_then(|(o, l)| match o {
100 $object_variant(o) => return Ok((o, l)),
101 o => Err(wrong_kind(id, o.kind(), $object_kind)),
102 })
103 }
104 };
105 }
106
107 macro_rules! make_iter_lookup {
108 ($method:ident, $object_kind:path, $object_type:ty, $into_iter:tt) => {
109 fn $method<'a>(
112 &self,
113 id: &gix_hash::oid,
114 buffer: &'a mut Vec<u8>,
115 ) -> Result<($object_type, Option<crate::data::entry::Location>)> {
116 let id = id.as_ref();
117 self.try_find(id, buffer)?
118 .ok_or_else(|| not_found(id))
119 .and_then(|(o, l)| {
120 o.$into_iter()
121 .ok_or_else(|| wrong_kind(id, o.kind, $object_kind))
122 .map(|i| (i, l))
123 })
124 }
125 };
126 }
127
128 pub trait FindExt: super::Find {
130 fn find<'a>(
132 &self,
133 id: &gix_hash::oid,
134 buffer: &'a mut Vec<u8>,
135 ) -> Result<(gix_object::Data<'a>, Option<crate::data::entry::Location>)> {
136 self.try_find(id, buffer)?.ok_or_else(|| not_found(id))
137 }
138
139 make_obj_lookup!(find_commit, ObjectRef::Commit, Kind::Commit, CommitRef<'a>);
140 make_obj_lookup!(find_tree, ObjectRef::Tree, Kind::Tree, TreeRef<'a>);
141 make_obj_lookup!(find_tag, ObjectRef::Tag, Kind::Tag, TagRef<'a>);
142 make_obj_lookup!(find_blob, ObjectRef::Blob, Kind::Blob, BlobRef<'a>);
143 make_iter_lookup!(find_commit_iter, Kind::Blob, CommitRefIter<'a>, try_into_commit_iter);
144 make_iter_lookup!(find_tree_iter, Kind::Tree, TreeRefIter<'a>, try_into_tree_iter);
145 make_iter_lookup!(find_tag_iter, Kind::Tag, TagRefIter<'a>, try_into_tag_iter);
146 }
147
148 impl<T: super::Find + ?Sized> FindExt for T {}
149}
150pub use ext::FindExt;
151
152mod find_impls {
153 use gix_error::Result;
154 use std::{ops::Deref, rc::Rc};
155
156 use gix_hash::oid;
157
158 use crate::{data, find};
159
160 impl<T> crate::Find for &T
161 where
162 T: crate::Find,
163 {
164 fn contains(&self, id: &oid) -> bool {
165 (*self).contains(id)
166 }
167
168 fn try_find_cached<'a>(
169 &self,
170 id: &oid,
171 buffer: &'a mut Vec<u8>,
172 pack_cache: &mut dyn crate::cache::DecodeEntry,
173 ) -> Result<Option<(gix_object::Data<'a>, Option<data::entry::Location>)>> {
174 (*self).try_find_cached(id, buffer, pack_cache)
175 }
176
177 fn location_by_oid(&self, id: &oid, buf: &mut Vec<u8>) -> Result<Option<data::entry::Location>> {
178 (*self).location_by_oid(id, buf)
179 }
180
181 fn pack_offsets_and_oid(&self, pack_id: u32) -> Result<Option<Vec<(data::Offset, gix_hash::ObjectId)>>> {
182 (*self).pack_offsets_and_oid(pack_id)
183 }
184
185 fn entry_by_location(&self, location: &data::entry::Location) -> Option<find::Entry> {
186 (*self).entry_by_location(location)
187 }
188 }
189
190 impl<T> super::Find for std::sync::Arc<T>
191 where
192 T: super::Find,
193 {
194 fn contains(&self, id: &oid) -> bool {
195 self.deref().contains(id)
196 }
197
198 fn try_find_cached<'a>(
199 &self,
200 id: &oid,
201 buffer: &'a mut Vec<u8>,
202 pack_cache: &mut dyn crate::cache::DecodeEntry,
203 ) -> Result<Option<(gix_object::Data<'a>, Option<data::entry::Location>)>> {
204 self.deref().try_find_cached(id, buffer, pack_cache)
205 }
206
207 fn location_by_oid(&self, id: &oid, buf: &mut Vec<u8>) -> Result<Option<data::entry::Location>> {
208 self.deref().location_by_oid(id, buf)
209 }
210
211 fn pack_offsets_and_oid(&self, pack_id: u32) -> Result<Option<Vec<(data::Offset, gix_hash::ObjectId)>>> {
212 self.deref().pack_offsets_and_oid(pack_id)
213 }
214
215 fn entry_by_location(&self, object: &data::entry::Location) -> Option<find::Entry> {
216 self.deref().entry_by_location(object)
217 }
218 }
219
220 impl<T> super::Find for Rc<T>
221 where
222 T: super::Find,
223 {
224 fn contains(&self, id: &oid) -> bool {
225 self.deref().contains(id)
226 }
227
228 fn try_find_cached<'a>(
229 &self,
230 id: &oid,
231 buffer: &'a mut Vec<u8>,
232 pack_cache: &mut dyn crate::cache::DecodeEntry,
233 ) -> Result<Option<(gix_object::Data<'a>, Option<data::entry::Location>)>> {
234 self.deref().try_find_cached(id, buffer, pack_cache)
235 }
236
237 fn location_by_oid(&self, id: &oid, buf: &mut Vec<u8>) -> Result<Option<data::entry::Location>> {
238 self.deref().location_by_oid(id, buf)
239 }
240
241 fn pack_offsets_and_oid(&self, pack_id: u32) -> Result<Option<Vec<(data::Offset, gix_hash::ObjectId)>>> {
242 self.deref().pack_offsets_and_oid(pack_id)
243 }
244
245 fn entry_by_location(&self, location: &data::entry::Location) -> Option<find::Entry> {
246 self.deref().entry_by_location(location)
247 }
248 }
249
250 impl<T> super::Find for Box<T>
251 where
252 T: super::Find,
253 {
254 fn contains(&self, id: &oid) -> bool {
255 self.deref().contains(id)
256 }
257
258 fn try_find_cached<'a>(
259 &self,
260 id: &oid,
261 buffer: &'a mut Vec<u8>,
262 pack_cache: &mut dyn crate::cache::DecodeEntry,
263 ) -> Result<Option<(gix_object::Data<'a>, Option<data::entry::Location>)>> {
264 self.deref().try_find_cached(id, buffer, pack_cache)
265 }
266
267 fn location_by_oid(&self, id: &oid, buf: &mut Vec<u8>) -> Result<Option<data::entry::Location>> {
268 self.deref().location_by_oid(id, buf)
269 }
270
271 fn pack_offsets_and_oid(&self, pack_id: u32) -> Result<Option<Vec<(data::Offset, gix_hash::ObjectId)>>> {
272 self.deref().pack_offsets_and_oid(pack_id)
273 }
274
275 fn entry_by_location(&self, location: &data::entry::Location) -> Option<find::Entry> {
276 self.deref().entry_by_location(location)
277 }
278 }
279}