1use gix_error::Result;
2pub trait Exists {
4 fn exists(&self, id: &gix_hash::oid) -> bool;
6}
7
8pub trait Find {
17 fn try_find<'a>(&self, id: &gix_hash::oid, buffer: &'a mut Vec<u8>) -> Result<Option<crate::Data<'a>>>;
22}
23
24pub trait Header {
26 fn try_header(&self, id: &gix_hash::oid) -> Result<Option<crate::Header>>;
30}
31
32pub trait FindObjectOrHeader: Find + Header {}
34
35mod _impls {
36 use gix_error::Result;
37 use std::{ops::Deref, rc::Rc, sync::Arc};
38
39 use gix_hash::oid;
40
41 use crate::Data;
42
43 impl<T> crate::Exists for &T
44 where
45 T: crate::Exists,
46 {
47 fn exists(&self, id: &oid) -> bool {
48 (*self).exists(id)
49 }
50 }
51
52 impl<T> crate::FindObjectOrHeader for T where T: crate::Find + crate::FindHeader {}
53
54 impl<T> crate::Find for &T
55 where
56 T: crate::Find,
57 {
58 fn try_find<'a>(&self, id: &oid, buffer: &'a mut Vec<u8>) -> Result<Option<Data<'a>>> {
59 (*self).try_find(id, buffer)
60 }
61 }
62
63 impl<T> crate::FindHeader for &T
64 where
65 T: crate::FindHeader,
66 {
67 fn try_header(&self, id: &gix_hash::oid) -> Result<Option<crate::Header>> {
68 (*self).try_header(id)
69 }
70 }
71
72 impl<T> crate::Exists for Box<T>
73 where
74 T: crate::Exists,
75 {
76 fn exists(&self, id: &oid) -> bool {
77 self.deref().exists(id)
78 }
79 }
80
81 impl<T> crate::Exists for Rc<T>
82 where
83 T: crate::Exists,
84 {
85 fn exists(&self, id: &oid) -> bool {
86 self.deref().exists(id)
87 }
88 }
89
90 impl<T> crate::Find for Rc<T>
91 where
92 T: crate::Find,
93 {
94 fn try_find<'a>(&self, id: &oid, buffer: &'a mut Vec<u8>) -> Result<Option<Data<'a>>> {
95 self.deref().try_find(id, buffer)
96 }
97 }
98
99 impl<T> crate::FindHeader for Rc<T>
100 where
101 T: crate::FindHeader,
102 {
103 fn try_header(&self, id: &gix_hash::oid) -> Result<Option<crate::Header>> {
104 self.deref().try_header(id)
105 }
106 }
107
108 impl<T> crate::Find for Box<T>
109 where
110 T: crate::Find,
111 {
112 fn try_find<'a>(&self, id: &oid, buffer: &'a mut Vec<u8>) -> Result<Option<Data<'a>>> {
113 self.deref().try_find(id, buffer)
114 }
115 }
116
117 impl<T> crate::FindHeader for Box<T>
118 where
119 T: crate::FindHeader,
120 {
121 fn try_header(&self, id: &gix_hash::oid) -> Result<Option<crate::Header>> {
122 self.deref().try_header(id)
123 }
124 }
125
126 impl<T> crate::Exists for Arc<T>
127 where
128 T: crate::Exists,
129 {
130 fn exists(&self, id: &oid) -> bool {
131 self.deref().exists(id)
132 }
133 }
134
135 impl<T> crate::Find for Arc<T>
136 where
137 T: crate::Find,
138 {
139 fn try_find<'a>(&self, id: &oid, buffer: &'a mut Vec<u8>) -> Result<Option<Data<'a>>> {
140 self.deref().try_find(id, buffer)
141 }
142 }
143
144 impl<T> crate::FindHeader for Arc<T>
145 where
146 T: crate::FindHeader,
147 {
148 fn try_header(&self, id: &gix_hash::oid) -> Result<Option<crate::Header>> {
149 self.deref().try_header(id)
150 }
151 }
152}
153
154mod ext {
155 use gix_error::{Error, Result, ResultExt, message};
156
157 use crate::{BlobRef, CommitRef, CommitRefIter, Kind, ObjectRef, TagRef, TagRefIter, TreeRef, TreeRefIter};
158
159 fn not_found(id: &gix_hash::oid) -> Error {
160 gix_error::message!("An object with id {id} could not be found").not_found_error()
161 }
162
163 fn wrong_kind(id: &gix_hash::oid, actual: Kind, expected: Kind) -> Error {
164 message!("Expected object of kind {expected} but got {actual} at {id}").validation_error()
165 }
166
167 macro_rules! make_obj_lookup {
168 ($method:ident, $object_variant:path, $object_kind:path, $object_type:ty) => {
169 fn $method<'a>(&self, id: &gix_hash::oid, buffer: &'a mut Vec<u8>) -> Result<$object_type> {
172 self.try_find(id, buffer)?
173 .ok_or_else(|| not_found(id))
174 .and_then(|o| {
175 o.decode()
176 .or_raise(|| message!("Could not decode object at {id}").corrupted())
177 })
178 .and_then(|o| match o {
179 $object_variant(o) => return Ok(o),
180 o => Err(wrong_kind(id, o.kind(), $object_kind)),
181 })
182 }
183 };
184 }
185
186 macro_rules! make_iter_lookup {
187 ($method:ident, $object_kind:path, $object_type:ty, $into_iter:tt) => {
188 fn $method<'a>(&self, id: &gix_hash::oid, buffer: &'a mut Vec<u8>) -> Result<$object_type> {
191 self.try_find(id, buffer)?
192 .ok_or_else(|| not_found(id))
193 .and_then(|o| o.$into_iter().ok_or_else(|| wrong_kind(id, o.kind, $object_kind)))
194 }
195 };
196 }
197
198 pub trait HeaderExt: super::Header {
200 fn header(&self, id: &gix_hash::oid) -> Result<crate::Header> {
202 self.try_header(id)?.ok_or_else(|| not_found(id))
203 }
204 }
205
206 pub trait FindExt: super::Find {
208 fn find<'a>(&self, id: &gix_hash::oid, buffer: &'a mut Vec<u8>) -> Result<crate::Data<'a>> {
210 self.try_find(id, buffer)?.ok_or_else(|| not_found(id))
211 }
212
213 fn find_blob<'a>(&self, id: &gix_hash::oid, buffer: &'a mut Vec<u8>) -> Result<BlobRef<'a>> {
216 if id == gix_hash::ObjectId::empty_blob(id.kind()) {
217 return Ok(BlobRef { data: &[] });
218 }
219 self.try_find(id, buffer)?
220 .ok_or_else(|| not_found(id))
221 .and_then(|o| {
222 o.decode()
223 .or_raise(|| message!("Could not decode object at {id}").corrupted())
224 })
225 .and_then(|o| match o {
226 ObjectRef::Blob(o) => Ok(o),
227 o => Err(wrong_kind(id, o.kind(), Kind::Blob)),
228 })
229 }
230
231 fn find_tree<'a>(&self, id: &gix_hash::oid, buffer: &'a mut Vec<u8>) -> Result<TreeRef<'a>> {
234 if id == gix_hash::ObjectId::empty_tree(id.kind()) {
235 return Ok(TreeRef { entries: Vec::new() });
236 }
237 self.try_find(id, buffer)?
238 .ok_or_else(|| not_found(id))
239 .and_then(|o| {
240 o.decode()
241 .or_raise(|| message!("Could not decode object at {id}").corrupted())
242 })
243 .and_then(|o| match o {
244 ObjectRef::Tree(o) => Ok(o),
245 o => Err(wrong_kind(id, o.kind(), Kind::Tree)),
246 })
247 }
248
249 make_obj_lookup!(find_commit, ObjectRef::Commit, Kind::Commit, CommitRef<'a>);
250 make_obj_lookup!(find_tag, ObjectRef::Tag, Kind::Tag, TagRef<'a>);
251 make_iter_lookup!(find_commit_iter, Kind::Commit, CommitRefIter<'a>, try_into_commit_iter);
252 make_iter_lookup!(find_tree_iter, Kind::Tree, TreeRefIter<'a>, try_into_tree_iter);
253 make_iter_lookup!(find_tag_iter, Kind::Tag, TagRefIter<'a>, try_into_tag_iter);
254 }
255
256 impl<T: super::Find + ?Sized> FindExt for T {}
257}
258pub use ext::{FindExt, HeaderExt};