1use std::io;
2
3use git_object::WriteTo;
4
5pub trait Write {
7 type Error: std::error::Error + From<io::Error>;
11
12 fn write(&self, object: impl WriteTo) -> Result<git_hash::ObjectId, Self::Error> {
15 let mut buf = Vec::with_capacity(2048);
16 object.write_to(&mut buf)?;
17 self.write_stream(object.kind(), buf.len() as u64, buf.as_slice())
18 }
19 fn write_buf(&self, object: git_object::Kind, from: &[u8]) -> Result<git_hash::ObjectId, Self::Error> {
21 self.write_stream(object, from.len() as u64, from)
22 }
23 fn write_stream(
26 &self,
27 kind: git_object::Kind,
28 size: u64,
29 from: impl io::Read,
30 ) -> Result<git_hash::ObjectId, Self::Error>;
31}
32
33pub trait Find {
42 type Error: std::error::Error + 'static;
44
45 fn contains(&self, id: impl AsRef<git_hash::oid>) -> bool;
47
48 fn try_find<'a>(
53 &self,
54 id: impl AsRef<git_hash::oid>,
55 buffer: &'a mut Vec<u8>,
56 ) -> Result<Option<git_object::Data<'a>>, Self::Error>;
57}
58
59pub trait Header {
61 type Error: std::error::Error + 'static;
63 fn try_header(&self, id: impl AsRef<git_hash::oid>) -> Result<Option<find::Header>, Self::Error>;
65}
66
67mod _impls {
68 use std::{io::Read, ops::Deref, rc::Rc, sync::Arc};
69
70 use git_hash::{oid, ObjectId};
71 use git_object::{Data, Kind, WriteTo};
72
73 use crate::find::Header;
74
75 impl<T> crate::Write for &T
76 where
77 T: crate::Write,
78 {
79 type Error = T::Error;
80
81 fn write(&self, object: impl WriteTo) -> Result<ObjectId, Self::Error> {
82 (*self).write(object)
83 }
84
85 fn write_buf(&self, object: Kind, from: &[u8]) -> Result<ObjectId, Self::Error> {
86 (*self).write_buf(object, from)
87 }
88
89 fn write_stream(&self, kind: Kind, size: u64, from: impl Read) -> Result<ObjectId, Self::Error> {
90 (*self).write_stream(kind, size, from)
91 }
92 }
93
94 impl<T> crate::Write for Arc<T>
95 where
96 T: crate::Write,
97 {
98 type Error = T::Error;
99
100 fn write(&self, object: impl WriteTo) -> Result<ObjectId, Self::Error> {
101 self.deref().write(object)
102 }
103
104 fn write_buf(&self, object: Kind, from: &[u8]) -> Result<ObjectId, Self::Error> {
105 self.deref().write_buf(object, from)
106 }
107
108 fn write_stream(&self, kind: Kind, size: u64, from: impl Read) -> Result<ObjectId, Self::Error> {
109 self.deref().write_stream(kind, size, from)
110 }
111 }
112
113 impl<T> crate::Write for Rc<T>
114 where
115 T: crate::Write,
116 {
117 type Error = T::Error;
118
119 fn write(&self, object: impl WriteTo) -> Result<ObjectId, Self::Error> {
120 self.deref().write(object)
121 }
122
123 fn write_buf(&self, object: Kind, from: &[u8]) -> Result<ObjectId, Self::Error> {
124 self.deref().write_buf(object, from)
125 }
126
127 fn write_stream(&self, kind: Kind, size: u64, from: impl Read) -> Result<ObjectId, Self::Error> {
128 self.deref().write_stream(kind, size, from)
129 }
130 }
131
132 impl<T> crate::Find for &T
133 where
134 T: crate::Find,
135 {
136 type Error = T::Error;
137
138 fn contains(&self, id: impl AsRef<oid>) -> bool {
139 (*self).contains(id)
140 }
141
142 fn try_find<'a>(&self, id: impl AsRef<oid>, buffer: &'a mut Vec<u8>) -> Result<Option<Data<'a>>, Self::Error> {
143 (*self).try_find(id, buffer)
144 }
145 }
146
147 impl<T> crate::Header for &T
148 where
149 T: crate::Header,
150 {
151 type Error = T::Error;
152
153 fn try_header(&self, id: impl AsRef<oid>) -> Result<Option<Header>, Self::Error> {
154 (*self).try_header(id)
155 }
156 }
157
158 impl<T> crate::Find for Rc<T>
159 where
160 T: crate::Find,
161 {
162 type Error = T::Error;
163
164 fn contains(&self, id: impl AsRef<oid>) -> bool {
165 self.deref().contains(id)
166 }
167
168 fn try_find<'a>(&self, id: impl AsRef<oid>, buffer: &'a mut Vec<u8>) -> Result<Option<Data<'a>>, Self::Error> {
169 self.deref().try_find(id, buffer)
170 }
171 }
172
173 impl<T> crate::Header for Rc<T>
174 where
175 T: crate::Header,
176 {
177 type Error = T::Error;
178
179 fn try_header(&self, id: impl AsRef<oid>) -> Result<Option<Header>, Self::Error> {
180 self.deref().try_header(id)
181 }
182 }
183
184 impl<T> crate::Find for Arc<T>
185 where
186 T: crate::Find,
187 {
188 type Error = T::Error;
189
190 fn contains(&self, id: impl AsRef<oid>) -> bool {
191 self.deref().contains(id)
192 }
193
194 fn try_find<'a>(&self, id: impl AsRef<oid>, buffer: &'a mut Vec<u8>) -> Result<Option<Data<'a>>, Self::Error> {
195 self.deref().try_find(id, buffer)
196 }
197 }
198
199 impl<T> crate::Header for Arc<T>
200 where
201 T: crate::Header,
202 {
203 type Error = T::Error;
204
205 fn try_header(&self, id: impl AsRef<oid>) -> Result<Option<Header>, Self::Error> {
206 self.deref().try_header(id)
207 }
208 }
209}
210
211mod ext {
212 use git_object::{BlobRef, CommitRef, CommitRefIter, Kind, ObjectRef, TagRef, TagRefIter, TreeRef, TreeRefIter};
213
214 use crate::find;
215
216 macro_rules! make_obj_lookup {
217 ($method:ident, $object_variant:path, $object_kind:path, $object_type:ty) => {
218 fn $method<'a>(
221 &self,
222 id: impl AsRef<git_hash::oid>,
223 buffer: &'a mut Vec<u8>,
224 ) -> Result<$object_type, find::existing_object::Error<Self::Error>> {
225 let id = id.as_ref();
226 self.try_find(id, buffer)
227 .map_err(find::existing_object::Error::Find)?
228 .ok_or_else(|| find::existing_object::Error::NotFound {
229 oid: id.as_ref().to_owned(),
230 })
231 .and_then(|o| o.decode().map_err(find::existing_object::Error::Decode))
232 .and_then(|o| match o {
233 $object_variant(o) => return Ok(o),
234 _other => Err(find::existing_object::Error::ObjectKind {
235 expected: $object_kind,
236 }),
237 })
238 }
239 };
240 }
241
242 macro_rules! make_iter_lookup {
243 ($method:ident, $object_kind:path, $object_type:ty, $into_iter:tt) => {
244 fn $method<'a>(
247 &self,
248 id: impl AsRef<git_hash::oid>,
249 buffer: &'a mut Vec<u8>,
250 ) -> Result<$object_type, find::existing_iter::Error<Self::Error>> {
251 let id = id.as_ref();
252 self.try_find(id, buffer)
253 .map_err(find::existing_iter::Error::Find)?
254 .ok_or_else(|| find::existing_iter::Error::NotFound {
255 oid: id.as_ref().to_owned(),
256 })
257 .and_then(|o| {
258 o.$into_iter()
259 .ok_or_else(|| find::existing_iter::Error::ObjectKind {
260 expected: $object_kind,
261 })
262 })
263 }
264 };
265 }
266
267 pub trait HeaderExt: super::Header {
269 fn header(
271 &self,
272 id: impl AsRef<git_hash::oid>,
273 ) -> Result<crate::find::Header, find::existing::Error<Self::Error>> {
274 let id = id.as_ref();
275 self.try_header(id)
276 .map_err(find::existing::Error::Find)?
277 .ok_or_else(|| find::existing::Error::NotFound { oid: id.to_owned() })
278 }
279 }
280
281 impl<T: super::Header> HeaderExt for T {}
282
283 pub trait FindExt: super::Find {
285 fn find<'a>(
287 &self,
288 id: impl AsRef<git_hash::oid>,
289 buffer: &'a mut Vec<u8>,
290 ) -> Result<git_object::Data<'a>, find::existing::Error<Self::Error>> {
291 let id = id.as_ref();
292 self.try_find(id, buffer)
293 .map_err(find::existing::Error::Find)?
294 .ok_or_else(|| find::existing::Error::NotFound { oid: id.to_owned() })
295 }
296
297 make_obj_lookup!(find_commit, ObjectRef::Commit, Kind::Commit, CommitRef<'a>);
298 make_obj_lookup!(find_tree, ObjectRef::Tree, Kind::Tree, TreeRef<'a>);
299 make_obj_lookup!(find_tag, ObjectRef::Tag, Kind::Tag, TagRef<'a>);
300 make_obj_lookup!(find_blob, ObjectRef::Blob, Kind::Blob, BlobRef<'a>);
301 make_iter_lookup!(find_commit_iter, Kind::Commit, CommitRefIter<'a>, try_into_commit_iter);
302 make_iter_lookup!(find_tree_iter, Kind::Tree, TreeRefIter<'a>, try_into_tree_iter);
303 make_iter_lookup!(find_tag_iter, Kind::Tag, TagRefIter<'a>, try_into_tag_iter);
304 }
305
306 impl<T: super::Find> FindExt for T {}
307}
308pub use ext::{FindExt, HeaderExt};
309
310use crate::find;