@@ -41,3 +41,175 @@ 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 Rc < 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 :: Find for Rc < T >
108
+ where
109
+ T : crate :: Find ,
110
+ {
111
+ fn try_find < ' a > ( & self , id : & oid , buffer : & ' a mut Vec < u8 > ) -> Result < Option < Data < ' a > > , crate :: find:: Error > {
112
+ self . deref ( ) . try_find ( id, buffer)
113
+ }
114
+ }
115
+
116
+ impl < T > crate :: Exists for Arc < T >
117
+ where
118
+ T : crate :: Exists ,
119
+ {
120
+ fn exists ( & self , id : & oid ) -> bool {
121
+ self . deref ( ) . exists ( id)
122
+ }
123
+ }
124
+
125
+ impl < T > crate :: Find for Arc < 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
+
135
+ mod ext {
136
+ use crate :: { BlobRef , CommitRef , CommitRefIter , Kind , ObjectRef , TagRef , TagRefIter , TreeRef , TreeRefIter } ;
137
+
138
+ use crate :: find;
139
+
140
+ macro_rules! make_obj_lookup {
141
+ ( $method: ident, $object_variant: path, $object_kind: path, $object_type: ty) => {
142
+ /// Like [`find(…)`][Self::find()], but flattens the `Result<Option<_>>` into a single `Result` making a non-existing object an error
143
+ /// while returning the desired object type.
144
+ fn $method<' a>(
145
+ & self ,
146
+ id: & gix_hash:: oid,
147
+ buffer: & ' a mut Vec <u8 >,
148
+ ) -> Result <$object_type, find:: existing_object:: Error > {
149
+ self . try_find( id, buffer)
150
+ . map_err( find:: existing_object:: Error :: Find ) ?
151
+ . ok_or_else( || find:: existing_object:: Error :: NotFound {
152
+ oid: id. as_ref( ) . to_owned( ) ,
153
+ } )
154
+ . and_then( |o| o. decode( ) . map_err( find:: existing_object:: Error :: Decode ) )
155
+ . and_then( |o| match o {
156
+ $object_variant( o) => return Ok ( o) ,
157
+ _other => Err ( find:: existing_object:: Error :: ObjectKind {
158
+ expected: $object_kind,
159
+ } ) ,
160
+ } )
161
+ }
162
+ } ;
163
+ }
164
+
165
+ macro_rules! make_iter_lookup {
166
+ ( $method: ident, $object_kind: path, $object_type: ty, $into_iter: tt) => {
167
+ /// Like [`find(…)`][Self::find()], but flattens the `Result<Option<_>>` into a single `Result` making a non-existing object an error
168
+ /// while returning the desired iterator type.
169
+ fn $method<' a>(
170
+ & self ,
171
+ id: & gix_hash:: oid,
172
+ buffer: & ' a mut Vec <u8 >,
173
+ ) -> Result <$object_type, find:: existing_iter:: Error > {
174
+ self . try_find( id, buffer)
175
+ . map_err( find:: existing_iter:: Error :: Find ) ?
176
+ . ok_or_else( || find:: existing_iter:: Error :: NotFound {
177
+ oid: id. as_ref( ) . to_owned( ) ,
178
+ } )
179
+ . and_then( |o| {
180
+ o. $into_iter( )
181
+ . ok_or_else( || find:: existing_iter:: Error :: ObjectKind {
182
+ expected: $object_kind,
183
+ } )
184
+ } )
185
+ }
186
+ } ;
187
+ }
188
+
189
+ /// An extension trait with convenience functions.
190
+ pub trait FindExt : super :: Find {
191
+ /// Like [`try_find(…)`][super::Find::try_find()], but flattens the `Result<Option<_>>` into a single `Result` making a non-existing object an error.
192
+ fn find < ' a > (
193
+ & self ,
194
+ id : & gix_hash:: oid ,
195
+ buffer : & ' a mut Vec < u8 > ,
196
+ ) -> Result < crate :: Data < ' a > , find:: existing:: Error > {
197
+ self . try_find ( id, buffer)
198
+ . map_err ( find:: existing:: Error :: Find ) ?
199
+ . ok_or_else ( || find:: existing:: Error :: NotFound { oid : id. to_owned ( ) } )
200
+ }
201
+
202
+ make_obj_lookup ! ( find_commit, ObjectRef :: Commit , Kind :: Commit , CommitRef <' a>) ;
203
+ make_obj_lookup ! ( find_tree, ObjectRef :: Tree , Kind :: Tree , TreeRef <' a>) ;
204
+ make_obj_lookup ! ( find_tag, ObjectRef :: Tag , Kind :: Tag , TagRef <' a>) ;
205
+ make_obj_lookup ! ( find_blob, ObjectRef :: Blob , Kind :: Blob , BlobRef <' a>) ;
206
+ make_iter_lookup ! ( find_commit_iter, Kind :: Commit , CommitRefIter <' a>, try_into_commit_iter) ;
207
+ make_iter_lookup ! ( find_tree_iter, Kind :: Tree , TreeRefIter <' a>, try_into_tree_iter) ;
208
+ make_iter_lookup ! ( find_tag_iter, Kind :: Tag , TagRefIter <' a>, try_into_tag_iter) ;
209
+ }
210
+
211
+ impl < T : super :: Find > FindExt for T { }
212
+ }
213
+ pub use ext:: FindExt ;
214
+ }
215
+ pub use find:: * ;
0 commit comments