@@ -41,3 +41,203 @@ where
41
41
<T as WriteTo >:: size ( self )
42
42
}
43
43
}
44
+
45
+ mod find {
46
+ use crate :: find;
47
+
48
+ /// Check if an object is present in an object store.
49
+ pub trait Exists {
50
+ /// Returns `true` if the object exists in the database.
51
+ fn exists ( & self , id : & gix_hash:: oid ) -> bool ;
52
+ }
53
+
54
+ /// Find an object in the object store.
55
+ ///
56
+ /// ## Notes
57
+ ///
58
+ /// Find effectively needs [generic associated types][issue] to allow a trait for the returned object type.
59
+ /// Until then, we will have to make due with explicit types and give them the potentially added features we want.
60
+ ///
61
+ /// [issue]: https://github.com/rust-lang/rust/issues/44265
62
+ pub trait Find {
63
+ /// Find an object matching `id` in the database while placing its raw, possibly encoded data into `buffer`.
64
+ ///
65
+ /// Returns `Some` object if it was present in the database, or the error that occurred during lookup or object
66
+ /// retrieval.
67
+ fn try_find < ' a > (
68
+ & self ,
69
+ id : & gix_hash:: oid ,
70
+ buffer : & ' a mut Vec < u8 > ,
71
+ ) -> Result < Option < crate :: Data < ' a > > , find:: Error > ;
72
+ }
73
+
74
+ mod _impls {
75
+ use std:: { ops:: Deref , rc:: Rc , sync:: Arc } ;
76
+
77
+ use crate :: Data ;
78
+ use gix_hash:: oid;
79
+
80
+ impl < T > crate :: Exists for & T
81
+ where
82
+ T : crate :: Exists ,
83
+ {
84
+ fn exists ( & self , id : & oid ) -> bool {
85
+ ( * self ) . exists ( id)
86
+ }
87
+ }
88
+
89
+ impl < T > crate :: Find for & T
90
+ where
91
+ T : crate :: Find ,
92
+ {
93
+ fn try_find < ' a > ( & self , id : & oid , buffer : & ' a mut Vec < u8 > ) -> Result < Option < Data < ' a > > , crate :: find:: Error > {
94
+ ( * self ) . try_find ( id, buffer)
95
+ }
96
+ }
97
+
98
+ impl < T > crate :: Exists for Box < T >
99
+ where
100
+ T : crate :: Exists ,
101
+ {
102
+ fn exists ( & self , id : & oid ) -> bool {
103
+ self . deref ( ) . exists ( id)
104
+ }
105
+ }
106
+
107
+ impl < T > crate :: Exists for Rc < T >
108
+ where
109
+ T : crate :: Exists ,
110
+ {
111
+ fn exists ( & self , id : & oid ) -> bool {
112
+ self . deref ( ) . exists ( id)
113
+ }
114
+ }
115
+
116
+ impl < T > crate :: Find for Rc < T >
117
+ where
118
+ T : crate :: Find ,
119
+ {
120
+ fn try_find < ' a > ( & self , id : & oid , buffer : & ' a mut Vec < u8 > ) -> Result < Option < Data < ' a > > , crate :: find:: Error > {
121
+ self . deref ( ) . try_find ( id, buffer)
122
+ }
123
+ }
124
+
125
+ impl < T > crate :: Find for Box < T >
126
+ where
127
+ T : crate :: Find ,
128
+ {
129
+ fn try_find < ' a > ( & self , id : & oid , buffer : & ' a mut Vec < u8 > ) -> Result < Option < Data < ' a > > , crate :: find:: Error > {
130
+ self . deref ( ) . try_find ( id, buffer)
131
+ }
132
+ }
133
+
134
+ impl < T > crate :: Exists for Arc < T >
135
+ where
136
+ T : crate :: Exists ,
137
+ {
138
+ fn exists ( & self , id : & oid ) -> bool {
139
+ self . deref ( ) . exists ( id)
140
+ }
141
+ }
142
+
143
+ impl < T > crate :: Find for Arc < T >
144
+ where
145
+ T : crate :: Find ,
146
+ {
147
+ fn try_find < ' a > ( & self , id : & oid , buffer : & ' a mut Vec < u8 > ) -> Result < Option < Data < ' a > > , crate :: find:: Error > {
148
+ self . deref ( ) . try_find ( id, buffer)
149
+ }
150
+ }
151
+ }
152
+
153
+ mod ext {
154
+ use crate :: { BlobRef , CommitRef , CommitRefIter , Kind , ObjectRef , TagRef , TagRefIter , TreeRef , TreeRefIter } ;
155
+
156
+ use crate :: find;
157
+
158
+ macro_rules! make_obj_lookup {
159
+ ( $method: ident, $object_variant: path, $object_kind: path, $object_type: ty) => {
160
+ /// Like [`find(…)`][Self::find()], but flattens the `Result<Option<_>>` into a single `Result` making a non-existing object an error
161
+ /// while returning the desired object type.
162
+ 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( )
174
+ . map_err( |err| find:: existing_object:: Error :: Decode {
175
+ source: err,
176
+ oid: id. as_ref( ) . to_owned( ) ,
177
+ } )
178
+ } )
179
+ . and_then( |o| match o {
180
+ $object_variant( o) => return Ok ( o) ,
181
+ o => Err ( find:: existing_object:: Error :: ObjectKind {
182
+ oid: id. as_ref( ) . to_owned( ) ,
183
+ actual: o. kind( ) ,
184
+ expected: $object_kind,
185
+ } ) ,
186
+ } )
187
+ }
188
+ } ;
189
+ }
190
+
191
+ macro_rules! make_iter_lookup {
192
+ ( $method: ident, $object_kind: path, $object_type: ty, $into_iter: tt) => {
193
+ /// Like [`find(…)`][Self::find()], but flattens the `Result<Option<_>>` into a single `Result` making a non-existing object an error
194
+ /// while returning the desired iterator type.
195
+ fn $method<' a>(
196
+ & self ,
197
+ id: & gix_hash:: oid,
198
+ buffer: & ' a mut Vec <u8 >,
199
+ ) -> Result <$object_type, find:: existing_iter:: Error > {
200
+ self . try_find( id, buffer)
201
+ . map_err( find:: existing_iter:: Error :: Find ) ?
202
+ . ok_or_else( || find:: existing_iter:: Error :: NotFound {
203
+ oid: id. as_ref( ) . to_owned( ) ,
204
+ } )
205
+ . and_then( |o| {
206
+ o. $into_iter( )
207
+ . ok_or_else( || find:: existing_iter:: Error :: ObjectKind {
208
+ oid: id. as_ref( ) . to_owned( ) ,
209
+ actual: o. kind,
210
+ expected: $object_kind,
211
+ } )
212
+ } )
213
+ }
214
+ } ;
215
+ }
216
+
217
+ /// An extension trait with convenience functions.
218
+ pub trait FindExt : super :: Find {
219
+ /// Like [`try_find(…)`][super::Find::try_find()], but flattens the `Result<Option<_>>` into a single `Result` making a non-existing object an error.
220
+ fn find < ' a > (
221
+ & self ,
222
+ id : & gix_hash:: oid ,
223
+ buffer : & ' a mut Vec < u8 > ,
224
+ ) -> Result < crate :: Data < ' a > , find:: existing:: Error > {
225
+ self . try_find ( id, buffer)
226
+ . map_err ( find:: existing:: Error :: Find ) ?
227
+ . ok_or_else ( || find:: existing:: Error :: NotFound { oid : id. to_owned ( ) } )
228
+ }
229
+
230
+ make_obj_lookup ! ( find_commit, ObjectRef :: Commit , Kind :: Commit , CommitRef <' a>) ;
231
+ make_obj_lookup ! ( find_tree, ObjectRef :: Tree , Kind :: Tree , TreeRef <' a>) ;
232
+ make_obj_lookup ! ( find_tag, ObjectRef :: Tag , Kind :: Tag , TagRef <' a>) ;
233
+ make_obj_lookup ! ( find_blob, ObjectRef :: Blob , Kind :: Blob , BlobRef <' a>) ;
234
+ make_iter_lookup ! ( find_commit_iter, Kind :: Commit , CommitRefIter <' a>, try_into_commit_iter) ;
235
+ make_iter_lookup ! ( find_tree_iter, Kind :: Tree , TreeRefIter <' a>, try_into_tree_iter) ;
236
+ make_iter_lookup ! ( find_tag_iter, Kind :: Tag , TagRefIter <' a>, try_into_tag_iter) ;
237
+ }
238
+
239
+ impl < T : super :: Find + ?Sized > FindExt for T { }
240
+ }
241
+ pub use ext:: FindExt ;
242
+ }
243
+ pub use find:: * ;
0 commit comments