Unified · Split
| @@ -4,15 +4,15 @@ use bstr::BStr; · 3 unmodified lines | |||
| 4 | impl<'a> Entry<'a> { | 4 | impl<'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 | } |
| @@ -10,16 +10,24 @@ pub fn parse(buf: &[u8]) -> parse::Lines<'_> { · 9 unmodified lines | |||
| 10 | 10 | ||
| 11 | mod entry; | 11 | mod entry; |
| 12 | 12 | ||
| 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)] | ||
| 14 | #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] | 22 | #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] |
| 15 | pub struct Entry<'a> { | 23 | pub 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 | } |
| @@ -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 | } | ||