1use crate::find;
2
3pub trait Exists {
5 fn exists(&self, id: &gix_hash::oid) -> bool;
7}
8
9pub trait Find {
18 fn try_find<'a>(&self, id: &gix_hash::oid, buffer: &'a mut Vec<u8>)
23 -> Result<Option<crate::Data<'a>>, find::Error>;
24}
25
26pub trait Header {
28 fn try_header(&self, id: &gix_hash::oid) -> Result<Option<crate::Header>, find::Error>;
32}
33
34pub trait FindObjectOrHeader: Find + Header {}
36
37mod _impls {
38 use std::{ops::Deref, rc::Rc, sync::Arc};
39
40 use gix_hash::oid;
41
42 use crate::Data;
43
44 impl<T> crate::Exists for &T
45 where
46 T: crate::Exists,
47 {
48 fn exists(&self, id: &oid) -> bool {
49 (*self).exists(id)
50 }
51 }
52
53 impl<T> crate::FindObjectOrHeader for T where T: crate::Find + crate::FindHeader {}
54
55 impl<T> crate::Find for &T
56 where
57 T: crate::Find,
58 {
59 fn try_find<'a>(&self, id: &oid, buffer: &'a mut Vec<u8>) -> Result<Option<Data<'a>>, crate::find::Error> {
60 (*self).try_find(id, buffer)
61 }
62 }
63
64 impl<T> crate::FindHeader for &T
65 where
66 T: crate::FindHeader,
67 {
68 fn try_header(&self, id: &gix_hash::oid) -> Result<Option<crate::Header>, crate::find::Error> {
69 (*self).try_header(id)
70 }
71 }
72
73 impl<T> crate::Exists for Box<T>
74 where
75 T: crate::Exists,
76 {
77 fn exists(&self, id: &oid) -> bool {
78 self.deref().exists(id)
79 }
80 }
81
82 impl<T> crate::Exists for Rc<T>
83 where
84 T: crate::Exists,
85 {
86 fn exists(&self, id: &oid) -> bool {
87 self.deref().exists(id)
88 }
89 }
90
91 impl<T> crate::Find for Rc<T>
92 where
93 T: crate::Find,
94 {
95 fn try_find<'a>(&self, id: &oid, buffer: &'a mut Vec<u8>) -> Result<Option<Data<'a>>, crate::find::Error> {
96 self.deref().try_find(id, buffer)
97 }
98 }
99
100 impl<T> crate::FindHeader for Rc<T>
101 where
102 T: crate::FindHeader,
103 {
104 fn try_header(&self, id: &gix_hash::oid) -> Result<Option<crate::Header>, crate::find::Error> {
105 self.deref().try_header(id)
106 }
107 }
108
109 impl<T> crate::Find for Box<T>
110 where
111 T: crate::Find,
112 {
113 fn try_find<'a>(&self, id: &oid, buffer: &'a mut Vec<u8>) -> Result<Option<Data<'a>>, crate::find::Error> {
114 self.deref().try_find(id, buffer)
115 }
116 }
117
118 impl<T> crate::FindHeader for Box<T>
119 where
120 T: crate::FindHeader,
121 {
122 fn try_header(&self, id: &gix_hash::oid) -> Result<Option<crate::Header>, crate::find::Error> {
123 self.deref().try_header(id)
124 }
125 }
126
127 impl<T> crate::Exists for Arc<T>
128 where
129 T: crate::Exists,
130 {
131 fn exists(&self, id: &oid) -> bool {
132 self.deref().exists(id)
133 }
134 }
135
136 impl<T> crate::Find for Arc<T>
137 where
138 T: crate::Find,
139 {
140 fn try_find<'a>(&self, id: &oid, buffer: &'a mut Vec<u8>) -> Result<Option<Data<'a>>, crate::find::Error> {
141 self.deref().try_find(id, buffer)
142 }
143 }
144
145 impl<T> crate::FindHeader for Arc<T>
146 where
147 T: crate::FindHeader,
148 {
149 fn try_header(&self, id: &gix_hash::oid) -> Result<Option<crate::Header>, crate::find::Error> {
150 self.deref().try_header(id)
151 }
152 }
153}
154
155mod ext {
156 use crate::{find, BlobRef, CommitRef, CommitRefIter, Kind, ObjectRef, TagRef, TagRefIter, TreeRef, TreeRefIter};
157
158 macro_rules! make_obj_lookup {
159 ($method:ident, $object_variant:path, $object_kind:path, $object_type:ty) => {
160 fn $method<'a>(
163 &self,
164 id: &gix_hash::oid,
165 buffer: &'a mut Vec<u8>,
166 ) -> Result<$object_type, find::existing_object::Error> {
167 self.try_find(id, buffer)
168 .map_err(find::existing_object::Error::Find)?
169 .ok_or_else(|| find::existing_object::Error::NotFound {
170 oid: id.as_ref().to_owned(),
171 })
172 .and_then(|o| {
173 o.decode().map_err(|err| find::existing_object::Error::Decode {
174 source: err,
175 oid: id.as_ref().to_owned(),
176 })
177 })
178 .and_then(|o| match o {
179 $object_variant(o) => return Ok(o),
180 o => Err(find::existing_object::Error::ObjectKind {
181 oid: id.as_ref().to_owned(),
182 actual: o.kind(),
183 expected: $object_kind,
184 }),
185 })
186 }
187 };
188 }
189
190 macro_rules! make_iter_lookup {
191 ($method:ident, $object_kind:path, $object_type:ty, $into_iter:tt) => {
192 fn $method<'a>(
195 &self,
196 id: &gix_hash::oid,
197 buffer: &'a mut Vec<u8>,
198 ) -> Result<$object_type, find::existing_iter::Error> {
199 self.try_find(id, buffer)
200 .map_err(find::existing_iter::Error::Find)?
201 .ok_or_else(|| find::existing_iter::Error::NotFound {
202 oid: id.as_ref().to_owned(),
203 })
204 .and_then(|o| {
205 o.$into_iter()
206 .ok_or_else(|| find::existing_iter::Error::ObjectKind {
207 oid: id.as_ref().to_owned(),
208 actual: o.kind,
209 expected: $object_kind,
210 })
211 })
212 }
213 };
214 }
215
216 pub trait HeaderExt: super::Header {
218 fn header(&self, id: &gix_hash::oid) -> Result<crate::Header, find::existing::Error> {
220 self.try_header(id)
221 .map_err(find::existing::Error::Find)?
222 .ok_or_else(|| find::existing::Error::NotFound { oid: id.to_owned() })
223 }
224 }
225
226 pub trait FindExt: super::Find {
228 fn find<'a>(
230 &self,
231 id: &gix_hash::oid,
232 buffer: &'a mut Vec<u8>,
233 ) -> Result<crate::Data<'a>, find::existing::Error> {
234 self.try_find(id, buffer)
235 .map_err(find::existing::Error::Find)?
236 .ok_or_else(|| find::existing::Error::NotFound { oid: id.to_owned() })
237 }
238
239 fn find_blob<'a>(
242 &self,
243 id: &gix_hash::oid,
244 buffer: &'a mut Vec<u8>,
245 ) -> Result<BlobRef<'a>, find::existing_object::Error> {
246 if id == gix_hash::ObjectId::empty_blob(id.kind()) {
247 return Ok(BlobRef { data: &[] });
248 }
249 self.try_find(id, buffer)
250 .map_err(find::existing_object::Error::Find)?
251 .ok_or_else(|| find::existing_object::Error::NotFound {
252 oid: id.as_ref().to_owned(),
253 })
254 .and_then(|o| {
255 o.decode().map_err(|err| find::existing_object::Error::Decode {
256 source: err,
257 oid: id.as_ref().to_owned(),
258 })
259 })
260 .and_then(|o| match o {
261 ObjectRef::Blob(o) => Ok(o),
262 o => Err(find::existing_object::Error::ObjectKind {
263 oid: id.as_ref().to_owned(),
264 actual: o.kind(),
265 expected: Kind::Blob,
266 }),
267 })
268 }
269
270 fn find_tree<'a>(
273 &self,
274 id: &gix_hash::oid,
275 buffer: &'a mut Vec<u8>,
276 ) -> Result<TreeRef<'a>, find::existing_object::Error> {
277 if id == gix_hash::ObjectId::empty_tree(id.kind()) {
278 return Ok(TreeRef { entries: Vec::new() });
279 }
280 self.try_find(id, buffer)
281 .map_err(find::existing_object::Error::Find)?
282 .ok_or_else(|| find::existing_object::Error::NotFound {
283 oid: id.as_ref().to_owned(),
284 })
285 .and_then(|o| {
286 o.decode().map_err(|err| find::existing_object::Error::Decode {
287 source: err,
288 oid: id.as_ref().to_owned(),
289 })
290 })
291 .and_then(|o| match o {
292 ObjectRef::Tree(o) => Ok(o),
293 o => Err(find::existing_object::Error::ObjectKind {
294 oid: id.as_ref().to_owned(),
295 actual: o.kind(),
296 expected: Kind::Tree,
297 }),
298 })
299 }
300
301 make_obj_lookup!(find_commit, ObjectRef::Commit, Kind::Commit, CommitRef<'a>);
302 make_obj_lookup!(find_tag, ObjectRef::Tag, Kind::Tag, TagRef<'a>);
303 make_iter_lookup!(find_commit_iter, Kind::Commit, CommitRefIter<'a>, try_into_commit_iter);
304 make_iter_lookup!(find_tree_iter, Kind::Tree, TreeRefIter<'a>, try_into_tree_iter);
305 make_iter_lookup!(find_tag_iter, Kind::Tag, TagRefIter<'a>, try_into_tag_iter);
306 }
307
308 impl<T: super::Find + ?Sized> FindExt for T {}
309}
310pub use ext::{FindExt, HeaderExt};