History

sketch of mailmap snapshot for lookups (#366)

Sebastian Thiel committed 4 years ago

Commit d71d0671 parent b67b0f93 files · +108 −16Browse files

Unified · Split

3 files
  1. git-mailmap/src/entry.rs +11 −11
  2. git-mailmap/src/lib.rs +13 −5
  3. git-mailmap/src/snapshot.rs +84 −0
git-mailmap/src/entry.rs+11−11
@@ -4,15 +4,15 @@ use bstr::BStr; · 3 unmodified lines
4impl<'a> Entry<'a> {4impl<'a> Entry<'a> {
5 pub fn change_name_by_email(proper_name: impl Into<&'a BStr>, commit_email: impl Into<&'a BStr>) -> Self {5 pub fn change_name_by_email(proper_name: impl Into<&'a BStr>, commit_email: impl Into<&'a BStr>) -> Self {
6 Entry {6 Entry {
7 canonical_name: Some(proper_name.into()),7 new_name: Some(proper_name.into()),
8 commit_email: Some(commit_email.into()),8 old_email: Some(commit_email.into()),
9 ..Default::default()9 ..Default::default()
10 }10 }
11 }11 }
12 pub fn change_email_by_email(proper_email: impl Into<&'a BStr>, commit_email: impl Into<&'a BStr>) -> Self {12 pub fn change_email_by_email(proper_email: impl Into<&'a BStr>, commit_email: impl Into<&'a BStr>) -> Self {
13 Entry {13 Entry {
14 canonical_email: Some(proper_email.into()),14 new_email: Some(proper_email.into()),
15 commit_email: Some(commit_email.into()),15 old_email: Some(commit_email.into()),
16 ..Default::default()16 ..Default::default()
17 }17 }
18 }18 }
@@ -22,9 +22,9 @@ impl<'a> Entry<'a> { · 3 unmodified lines
22 commit_email: impl Into<&'a BStr>,22 commit_email: impl Into<&'a BStr>,
23 ) -> Self {23 ) -> Self {
24 Entry {24 Entry {
25 canonical_name: Some(proper_name.into()),25 new_name: Some(proper_name.into()),
26 canonical_email: Some(proper_email.into()),26 new_email: Some(proper_email.into()),
27 commit_email: Some(commit_email.into()),27 old_email: Some(commit_email.into()),
28 ..Default::default()28 ..Default::default()
29 }29 }
30 }30 }
@@ -36,10 +36,10 @@ impl<'a> Entry<'a> { · 5 unmodified lines
36 commit_email: impl Into<&'a BStr>,36 commit_email: impl Into<&'a BStr>,
37 ) -> Self {37 ) -> Self {
38 Entry {38 Entry {
39 canonical_name: Some(proper_name.into()),39 new_name: Some(proper_name.into()),
40 canonical_email: Some(proper_email.into()),40 new_email: Some(proper_email.into()),
41 commit_name: Some(commit_name.into()),41 old_name: Some(commit_name.into()),
42 commit_email: Some(commit_email.into()),42 old_email: Some(commit_email.into()),
43 }43 }
44 }44 }
45}45}
git-mailmap/src/lib.rs+13−5
@@ -10,16 +10,24 @@ pub fn parse(buf: &[u8]) -> parse::Lines<'_> { · 9 unmodified lines
10 10
11mod entry;11mod entry;
12 12
13#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Default)]13mod snapshot;
14
15#[derive(Default, Clone)]
16pub struct Snapshot {
17 /// Sorted by `old_email`
18 entries_by_old_email: Vec<snapshot::EmailEntry>,
19}
20
21#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy, Default)]
14#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]22#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
15pub struct Entry<'a> {23pub struct Entry<'a> {
16 #[cfg_attr(feature = "serde1", serde(borrow))]24 #[cfg_attr(feature = "serde1", serde(borrow))]
17 /// The name to map to.25 /// The name to map to.
18 canonical_name: Option<&'a BStr>,26 new_name: Option<&'a BStr>,
19 /// The email map to.27 /// The email map to.
20 canonical_email: Option<&'a BStr>,28 new_email: Option<&'a BStr>,
21 /// The name to look for and replace.29 /// The name to look for and replace.
22 commit_name: Option<&'a BStr>,30 old_name: Option<&'a BStr>,
23 /// The email to look for and replace.31 /// The email to look for and replace.
24 commit_email: Option<&'a BStr>,32 old_email: Option<&'a BStr>,
25}33}
git-mailmap/src/snapshot.rs+84−0
@@ -0,0 +1,84 @@
1use bstr::{BString, ByteSlice};
2use std::cmp::Ordering;
3use std::ops::Deref;
4
5#[cfg_attr(test, derive(Debug))]
6#[derive(Clone)]
7enum EncodedString {
8 Utf8(String),
9 Unknown(BString),
10}
11
12impl Eq for EncodedString {}
13
14impl PartialEq<Self> for EncodedString {
15 fn eq(&self, other: &Self) -> bool {
16 self.cmp(other) == Ordering::Equal
17 }
18}
19
20impl PartialOrd<Self> for EncodedString {
21 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
22 self.cmp(other).into()
23 }
24}
25
26impl Ord for EncodedString {
27 fn cmp(&self, other: &Self) -> Ordering {
28 use EncodedString::*;
29 match (self, other) {
30 (Utf8(a), Utf8(b)) => {
31 let a = a.chars().map(|c| c.to_ascii_lowercase());
32 let b = b.chars().map(|c| c.to_ascii_lowercase());
33 a.cmp(b)
34 }
35 (Unknown(a), Unknown(b)) => a.cmp(b),
36 (Utf8(a), Unknown(b)) => a.as_bytes().cmp(b.as_ref()),
37 (Unknown(a), Utf8(b)) => a.deref().as_bytes().cmp(b.as_bytes()),
38 }
39 }
40}
41
42#[derive(Clone)]
43pub(crate) struct NameEntry {
44 new_name: Option<BString>,
45 new_email: Option<BString>,
46 old_name: EncodedString,
47}
48
49#[derive(Clone)]
50pub(crate) struct EmailEntry {
51 new_name: Option<BString>,
52 new_email: Option<BString>,
53 old_email: EncodedString,
54
55 entries_by_old_name: Vec<NameEntry>,
56}
57
58#[cfg(test)]
59mod encoded_string {
60 use crate::snapshot::EncodedString;
61
62 #[test]
63 fn basic_ascii_case_folding() {
64 assert_eq!(
65 EncodedString::Utf8("FooBar".into()),
66 EncodedString::Utf8("foobar".into())
67 )
68 }
69
70 #[test]
71 fn no_advanced_unicode_folding() {
72 assert_ne!(EncodedString::Utf8("Masse".into()), EncodedString::Utf8("Maße".into()))
73 }
74
75 #[test]
76 fn unknown_encoding_pairs_do_not_try_to_ignore_cases() {
77 assert_ne!(EncodedString::Utf8("Foo".into()), EncodedString::Unknown("foo".into()));
78 assert_ne!(EncodedString::Unknown("Foo".into()), EncodedString::Utf8("foo".into()));
79 assert_ne!(
80 EncodedString::Unknown("Foo".into()),
81 EncodedString::Unknown("foo".into())
82 );
83 }
84}