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
44 impl<'a> Entry<'a> {
55 pub fn change_name_by_email(proper_name: impl Into<&'a BStr>, commit_email: impl Into<&'a BStr>) -> Self {
66 Entry {
7− canonical_name: Some(proper_name.into()),
8− commit_email: Some(commit_email.into()),
7+ new_name: Some(proper_name.into()),
8+ old_email: Some(commit_email.into()),
99 ..Default::default()
1010 }
1111 }
1212 pub fn change_email_by_email(proper_email: impl Into<&'a BStr>, commit_email: impl Into<&'a BStr>) -> Self {
1313 Entry {
14− canonical_email: Some(proper_email.into()),
15− commit_email: Some(commit_email.into()),
14+ new_email: Some(proper_email.into()),
15+ old_email: Some(commit_email.into()),
1616 ..Default::default()
1717 }
1818 }
@@ -22,9 +22,9 @@ impl<'a> Entry<'a> { · 3 unmodified lines
2222 commit_email: impl Into<&'a BStr>,
2323 ) -> Self {
2424 Entry {
25− canonical_name: Some(proper_name.into()),
26− canonical_email: Some(proper_email.into()),
27− commit_email: Some(commit_email.into()),
25+ new_name: Some(proper_name.into()),
26+ new_email: Some(proper_email.into()),
27+ old_email: Some(commit_email.into()),
2828 ..Default::default()
2929 }
3030 }
@@ -36,10 +36,10 @@ impl<'a> Entry<'a> { · 5 unmodified lines
3636 commit_email: impl Into<&'a BStr>,
3737 ) -> Self {
3838 Entry {
39− canonical_name: Some(proper_name.into()),
40− canonical_email: Some(proper_email.into()),
41− commit_name: Some(commit_name.into()),
42− commit_email: Some(commit_email.into()),
39+ new_name: Some(proper_name.into()),
40+ new_email: Some(proper_email.into()),
41+ old_name: Some(commit_name.into()),
42+ old_email: Some(commit_email.into()),
4343 }
4444 }
4545 }
git-mailmap/src/lib.rs+13−5
@@ -10,16 +10,24 @@ pub fn parse(buf: &[u8]) -> parse::Lines<'_> { · 9 unmodified lines
1010
1111 mod entry;
1212
13−#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Default)]
13+mod snapshot;
14+
15+#[derive(Default, Clone)]
16+pub 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)]
1422 #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
1523 pub struct Entry<'a> {
1624 #[cfg_attr(feature = "serde1", serde(borrow))]
1725 /// The name to map to.
18− canonical_name: Option<&'a BStr>,
26+ new_name: Option<&'a BStr>,
1927 /// The email map to.
20− canonical_email: Option<&'a BStr>,
28+ new_email: Option<&'a BStr>,
2129 /// The name to look for and replace.
22− commit_name: Option<&'a BStr>,
30+ old_name: Option<&'a BStr>,
2331 /// The email to look for and replace.
24− commit_email: Option<&'a BStr>,
32+ old_email: Option<&'a BStr>,
2533 }
git-mailmap/src/snapshot.rs+84−0
@@ -0,0 +1,84 @@
1+use bstr::{BString, ByteSlice};
2+use std::cmp::Ordering;
3+use std::ops::Deref;
4+
5+#[cfg_attr(test, derive(Debug))]
6+#[derive(Clone)]
7+enum EncodedString {
8+ Utf8(String),
9+ Unknown(BString),
10+}
11+
12+impl Eq for EncodedString {}
13+
14+impl PartialEq<Self> for EncodedString {
15+ fn eq(&self, other: &Self) -> bool {
16+ self.cmp(other) == Ordering::Equal
17+ }
18+}
19+
20+impl PartialOrd<Self> for EncodedString {
21+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
22+ self.cmp(other).into()
23+ }
24+}
25+
26+impl 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)]
43+pub(crate) struct NameEntry {
44+ new_name: Option<BString>,
45+ new_email: Option<BString>,
46+ old_name: EncodedString,
47+}
48+
49+#[derive(Clone)]
50+pub(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)]
59+mod 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+}