@@ -4,9 +4,11 @@ pub struct Ancestors<Find, Predicate, StateMut> {
4
4
predicate : Predicate ,
5
5
state : StateMut ,
6
6
mode : Parents ,
7
+ sorting : Sorting ,
7
8
}
8
9
9
10
/// Specify how to handle commit parents during traversal.
11
+ #[ derive( Copy , Clone ) ]
10
12
pub enum Parents {
11
13
/// Traverse all parents, useful for traversing the entire ancestry.
12
14
All ,
@@ -20,6 +22,22 @@ impl Default for Parents {
20
22
}
21
23
}
22
24
25
+ /// Specify how to sort commits during traversal.
26
+ #[ derive( Copy , Clone ) ]
27
+ pub enum Sorting {
28
+ /// Default order, sort commit looking up the first reachable parent
29
+ GraphOrder ,
30
+ /// Order commit looking up the most recent parent, since only parents are looked up
31
+ /// this ordering is partial
32
+ ByCommitterDate ,
33
+ }
34
+
35
+ impl Default for Sorting {
36
+ fn default ( ) -> Self {
37
+ Sorting :: GraphOrder
38
+ }
39
+ }
40
+
23
41
///
24
42
pub mod ancestors {
25
43
use std:: {
@@ -31,7 +49,7 @@ pub mod ancestors {
31
49
use git_object:: CommitRefIter ;
32
50
use quick_error:: quick_error;
33
51
34
- use crate :: commit:: { Ancestors , Parents } ;
52
+ use crate :: commit:: { Ancestors , Parents , Sorting } ;
35
53
36
54
quick_error ! {
37
55
/// The error is part of the item returned by the [Ancestors] iterator.
@@ -55,6 +73,8 @@ pub mod ancestors {
55
73
next : VecDeque < ObjectId > ,
56
74
buf : Vec < u8 > ,
57
75
seen : BTreeSet < ObjectId > ,
76
+ parents_with_date : Vec < ( ObjectId , u32 ) > ,
77
+ parents_buf : Vec < u8 > ,
58
78
}
59
79
60
80
impl State {
@@ -71,6 +91,12 @@ pub mod ancestors {
71
91
self . mode = mode;
72
92
self
73
93
}
94
+
95
+ /// Set the sorting method, either topological or by author date
96
+ pub fn sorting ( mut self , sorting : Sorting ) -> Self {
97
+ self . sorting = sorting;
98
+ self
99
+ }
74
100
}
75
101
76
102
impl < Find , StateMut > Ancestors < Find , fn ( & oid ) -> bool , StateMut >
@@ -138,6 +164,7 @@ pub mod ancestors {
138
164
predicate,
139
165
state,
140
166
mode : Default :: default ( ) ,
167
+ sorting : Default :: default ( ) ,
141
168
}
142
169
}
143
170
}
@@ -151,6 +178,80 @@ pub mod ancestors {
151
178
type Item = Result < ObjectId , Error > ;
152
179
153
180
fn next ( & mut self ) -> Option < Self :: Item > {
181
+ match self . sorting {
182
+ Sorting :: GraphOrder => self . graph_sort_next ( ) ,
183
+ Sorting :: ByCommitterDate => self . next_by_commit_date ( ) ,
184
+ }
185
+ }
186
+ }
187
+
188
+ impl < Find , Predicate , StateMut > Ancestors < Find , Predicate , StateMut >
189
+ where
190
+ Find : for < ' a > FnMut ( & oid , & ' a mut Vec < u8 > ) -> Option < CommitRefIter < ' a > > ,
191
+ Predicate : FnMut ( & oid ) -> bool ,
192
+ StateMut : BorrowMut < State > ,
193
+ {
194
+ fn next_by_commit_date ( & mut self ) -> Option < Result < ObjectId , Error > > {
195
+ let state = self . state . borrow_mut ( ) ;
196
+ state. parents_with_date . clear ( ) ;
197
+ state. parents_buf . clear ( ) ;
198
+ let res = state. next . pop_front ( ) ;
199
+
200
+ if let Some ( oid) = res {
201
+ match ( self . find ) ( & oid, & mut state. buf ) {
202
+ Some ( mut commit_iter) => {
203
+ if let Some ( Err ( decode_tree_err) ) = commit_iter. next ( ) {
204
+ return Some ( Err ( decode_tree_err. into ( ) ) ) ;
205
+ }
206
+
207
+ for token in commit_iter {
208
+ match token {
209
+ Ok ( git_object:: commit:: ref_iter:: Token :: Parent { id } ) => {
210
+ let parent = ( self . find ) ( id. as_ref ( ) , & mut state. parents_buf ) ;
211
+
212
+ let parent_committer_date = parent
213
+ . and_then ( |mut parent| parent. committer ( ) . map ( |committer| committer. time ) ) ;
214
+
215
+ if let Some ( parent_committer_date) = parent_committer_date {
216
+ state. parents_with_date . push ( ( id, parent_committer_date. time ) ) ;
217
+ }
218
+
219
+ if matches ! ( self . mode, Parents :: First ) {
220
+ break ;
221
+ }
222
+ }
223
+ Ok ( _unused_token) => break ,
224
+ Err ( err) => return Some ( Err ( err. into ( ) ) ) ,
225
+ }
226
+ }
227
+ }
228
+ None => return Some ( Err ( Error :: NotFound { oid } ) ) ,
229
+ }
230
+ }
231
+
232
+ state
233
+ . parents_with_date
234
+ . sort_by ( |( _, time) , ( _, other_time) | time. cmp ( & other_time) . reverse ( ) ) ;
235
+ for parent in & state. parents_with_date {
236
+ let id = parent. 0 ;
237
+ let was_inserted = state. seen . insert ( id) ;
238
+
239
+ if was_inserted && ( self . predicate ) ( & id) {
240
+ state. next . push_back ( id) ;
241
+ }
242
+ }
243
+
244
+ res. map ( Ok )
245
+ }
246
+ }
247
+
248
+ impl < Find , Predicate , StateMut > Ancestors < Find , Predicate , StateMut >
249
+ where
250
+ Find : for < ' a > FnMut ( & oid , & ' a mut Vec < u8 > ) -> Option < CommitRefIter < ' a > > ,
251
+ Predicate : FnMut ( & oid ) -> bool ,
252
+ StateMut : BorrowMut < State > ,
253
+ {
254
+ fn graph_sort_next ( & mut self ) -> Option < Result < ObjectId , Error > > {
154
255
let state = self . state . borrow_mut ( ) ;
155
256
let res = state. next . pop_front ( ) ;
156
257
if let Some ( oid) = res {
0 commit comments