@@ -6,6 +6,7 @@ use git2::{Repository, RepositoryOpenFlags, Status, StatusOptions, StatusShow};
6
6
use git_repository as git;
7
7
use git_repository:: bstr:: ByteSlice ;
8
8
use regex:: Regex ;
9
+ use std:: cmp:: Ordering ;
9
10
use std:: collections:: HashMap ;
10
11
use std:: path:: Path ;
11
12
use time:: format_description:: well_known:: Rfc3339 ;
@@ -23,23 +24,53 @@ pub struct Repo<'a> {
23
24
time_of_first_commit : git:: actor:: Time ,
24
25
}
25
26
26
- #[ derive( Hash , PartialEq , Eq , Ord , PartialOrd ) ]
27
+ #[ derive( Hash ) ]
27
28
pub struct Sig {
28
29
name : git:: bstr:: BString ,
29
30
email : git:: bstr:: BString ,
31
+ email_lowercase : Option < String > ,
30
32
}
31
33
32
34
impl From < git:: actor:: Signature > for Sig {
33
- fn from (
34
- git:: actor:: Signature {
35
- name, mut email, ..
36
- } : git:: actor:: Signature ,
37
- ) -> Self {
38
- // authors who aren't mail-mapped would otherwise seem dissimilar if the email case is different.
39
- // Explicitly lower-casing it normalizes for that.
40
- // This comes at the cost of displaying only lower-case emails as well, which seems beneficial.
41
- email. make_ascii_lowercase ( ) ;
42
- Self { name, email }
35
+ fn from ( git:: actor:: Signature { name, email, .. } : git:: actor:: Signature ) -> Self {
36
+ let needs_lowercase = email. chars ( ) . any ( |c| c. to_ascii_lowercase ( ) != c) ;
37
+ let email_lowercase = needs_lowercase. then ( || email. chars ( ) . collect :: < String > ( ) ) ;
38
+ Self {
39
+ name,
40
+ email,
41
+ email_lowercase,
42
+ }
43
+ }
44
+ }
45
+
46
+ impl Eq for Sig { }
47
+
48
+ impl PartialEq < Self > for Sig {
49
+ fn eq ( & self , other : & Self ) -> bool {
50
+ self . cmp ( other) == Ordering :: Equal
51
+ }
52
+ }
53
+
54
+ impl PartialOrd < Self > for Sig {
55
+ fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > {
56
+ self . cmp ( other) . into ( )
57
+ }
58
+ }
59
+
60
+ impl Ord for Sig {
61
+ fn cmp ( & self , other : & Self ) -> Ordering {
62
+ self . email_lowercase
63
+ . as_ref ( )
64
+ . and_then ( |a_email_lc| {
65
+ other
66
+ . email_lowercase
67
+ . as_ref ( )
68
+ . map ( |b_email_lc| ( a_email_lc, b_email_lc) )
69
+ } )
70
+ . map_or_else (
71
+ || self . email . cmp ( & other. email ) ,
72
+ |( a_email_lc, b_email_lc) | a_email_lc. cmp ( b_email_lc) ,
73
+ )
43
74
}
44
75
}
45
76
@@ -98,8 +129,9 @@ impl<'a> Repo<'a> {
98
129
author_to_number_of_commits. into_iter ( ) . collect ( ) ;
99
130
100
131
let total_num_authors = authors_by_number_of_commits. len ( ) ;
101
- authors_by_number_of_commits
102
- . sort_by ( |( sa, a_count) , ( sb, b_count) | b_count. cmp ( a_count) . then_with ( || sa. cmp ( & sb) ) ) ;
132
+ authors_by_number_of_commits. sort_by ( |( sa, a_count) , ( sb, b_count) | {
133
+ b_count. cmp ( a_count) . then_with ( || sa. name . cmp ( & sb. name ) )
134
+ } ) ;
103
135
104
136
let authors: Vec < Author > = authors_by_number_of_commits
105
137
. into_iter ( )
0 commit comments