diff --git a/Cargo.lock b/Cargo.lock index adc7bd51..94a03272 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -278,7 +278,7 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" name = "mailmap" version = "0.1.0" dependencies = [ - "unicase", + "uncased", ] [[package]] @@ -602,7 +602,7 @@ dependencies = [ "semver", "serde", "tempfile", - "unicase", + "uncased", "ureq", "walkdir", ] @@ -655,10 +655,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] -name = "unicase" -version = "2.8.0" +name = "uncased" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" +checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" +dependencies = [ + "version_check", +] [[package]] name = "unicode-bidi" diff --git a/Cargo.toml b/Cargo.toml index 9de95ec2..25ed6c4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ walkdir = "2" regex = "1.5.5" mailmap = { path = "./mailmap" } ureq = { version = "2.6.2", features = ["json"] } -unicase = "2.6.0" +uncased = "0.9.10" [profile.release] debug = 2 diff --git a/mailmap/Cargo.toml b/mailmap/Cargo.toml index 8ee1af24..dd3a0d39 100644 --- a/mailmap/Cargo.toml +++ b/mailmap/Cargo.toml @@ -11,4 +11,4 @@ categories = ["parsing"] license = "MIT OR Apache-2.0" [dependencies] -unicase = "2.6.0" +uncased = "0.9.10" diff --git a/mailmap/src/lib.rs b/mailmap/src/lib.rs index 3ecebf6e..036acd28 100644 --- a/mailmap/src/lib.rs +++ b/mailmap/src/lib.rs @@ -3,7 +3,7 @@ use std::hash::Hash; use std::pin::Pin; use std::ptr::NonNull; -use unicase::UniCase; +use uncased::{Uncased, UncasedStr}; #[cfg(test)] mod test; @@ -39,10 +39,10 @@ impl fmt::Debug for Mailmap { #[derive(Copy, Clone)] struct RawMapEntry { - canonical_name: Option>, - canonical_email: Option>, - current_name: Option>, - current_email: Option>, + canonical_name: Option>, + canonical_email: Option>, + current_name: Option>, + current_email: Option>, } impl RawMapEntry { @@ -58,10 +58,10 @@ impl RawMapEntry { #[derive(Copy, Clone, Debug, PartialEq, Eq)] struct MapEntry<'a> { - canonical_name: Option<&'a str>, - canonical_email: Option<&'a str>, - current_name: Option<&'a str>, - current_email: Option<&'a str>, + canonical_name: Option<&'a UncasedStr>, + canonical_email: Option<&'a UncasedStr>, + current_name: Option<&'a UncasedStr>, + current_email: Option<&'a UncasedStr>, } impl<'a> MapEntry<'a> { @@ -77,15 +77,15 @@ impl<'a> MapEntry<'a> { #[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Hash)] pub struct Author { - pub name: UniCase, - pub email: UniCase, + pub name: Uncased<'static>, + pub email: Uncased<'static>, } impl Author { pub fn new(name: String, email: String) -> Self { Self { - name: UniCase::new(name), - email: UniCase::new(email), + name: name.into(), + email: email.into(), } } } @@ -117,17 +117,17 @@ impl Mailmap { let entry = unsafe { entry.to_entry(&self.buffer) }; if let Some(email) = entry.current_email { if let Some(name) = entry.current_name { - if author.name == UniCase::new(name) && author.email == UniCase::new(email) { + if author.name == name && author.email == email { return Author::new( - entry.canonical_name.unwrap_or(&author.name).to_owned(), - entry.canonical_email.expect("canonical email").to_owned(), + entry.canonical_name.unwrap_or(&author.name).to_string(), + entry.canonical_email.expect("canonical email").to_string(), ); } } else { - if author.email == UniCase::new(email) { + if author.email == email { return Author::new( - entry.canonical_name.unwrap_or(&author.name).to_owned(), - entry.canonical_email.expect("canonical email").to_owned(), + entry.canonical_name.unwrap_or(&author.name).to_string(), + entry.canonical_email.expect("canonical email").to_string(), ); } } @@ -138,7 +138,7 @@ impl Mailmap { } } -fn read_email<'a>(line: &mut &'a str) -> Option<&'a str> { +fn read_email<'a>(line: &mut &'a str) -> Option<&'a UncasedStr> { if !line.starts_with('<') { return None; } @@ -148,21 +148,21 @@ fn read_email<'a>(line: &mut &'a str) -> Option<&'a str> { .unwrap_or_else(|| panic!("could not find email end in {:?}", line)); let ret = &line[1..end]; *line = &line[end + 1..]; - Some(ret) + Some(ret.into()) } -fn read_name<'a>(line: &mut &'a str) -> Option<&'a str> { +fn read_name<'a>(line: &mut &'a str) -> Option<&'a UncasedStr> { let end = if let Some(end) = line.find('<') { end } else { return None; }; - let ret = &line[..end].trim(); + let ret = line[..end].trim(); *line = &line[end..]; if ret.is_empty() { None } else { - Some(ret) + Some(ret.into()) } } diff --git a/mailmap/src/test.rs b/mailmap/src/test.rs index a6407545..c58b9c2a 100644 --- a/mailmap/src/test.rs +++ b/mailmap/src/test.rs @@ -23,7 +23,7 @@ fn comment_2() { fn email_1() { assert_eq!( test_parser!(read_email, "", ""), - Some("foo@example.com") + Some("foo@example.com".into()) ); } @@ -35,7 +35,7 @@ fn email_2() { " ", " " ), - Some("foo@example.com") + Some("foo@example.com".into()) ); } @@ -59,7 +59,7 @@ fn name_1() { "Canonical Name ", "" ), - Some("Canonical Name"), + Some("Canonical Name".into()), ); } @@ -68,10 +68,10 @@ fn line_1() { assert_eq!( parse_line("Joe Bob ", 0), Some(MapEntry { - canonical_name: Some("Joe Bob"), - canonical_email: Some("email1"), + canonical_name: Some("Joe Bob".into()), + canonical_email: Some("email1".into()), current_name: None, - current_email: Some("email2"), + current_email: Some("email2".into()), }) ); } @@ -81,18 +81,18 @@ fn line_2() { assert_eq!( parse_line("Joe Bob ", 0), Some(MapEntry { - canonical_name: Some("Joe Bob"), - canonical_email: Some("email1"), + canonical_name: Some("Joe Bob".into()), + canonical_email: Some("email1".into()), current_name: None, - current_email: Some("email1"), + current_email: Some("email1".into()), }) ); } fn a(name: &str, email: &str) -> Author { Author { - name: name.into(), - email: email.into(), + name: name.to_owned().into(), + email: email.to_owned().into(), } } @@ -123,3 +123,12 @@ fn map_4() { let mm = map(" "); assert_eq!(mm.canonicalize(&a("any", "CE")), a("any", "PE")); } + +#[test] +fn case_insensitive() { + let mm = map("Proper Name CoMmIt NaMe "); + assert_eq!( + mm.canonicalize(&a("Commit Name", "commit@email.xx")), + a("Proper Name", "proper@email.xx") + ); +} diff --git a/src/reviewers.rs b/src/reviewers.rs index aa712694..bbd73c90 100644 --- a/src/reviewers.rs +++ b/src/reviewers.rs @@ -21,10 +21,10 @@ impl Reviewers { } fn a(name: &str, email: &str) -> AddKind { - AddKind::New(Author { - name: name.into(), - email: email.into(), - }) + AddKind::New(Author::new( + name.into(), + email.into(), + )) } fn alias(name: &'static str) -> AddKind { diff --git a/src/site.rs b/src/site.rs index 17588ae9..d53989b5 100644 --- a/src/site.rs +++ b/src/site.rs @@ -3,7 +3,6 @@ use handlebars::Handlebars; use std::collections::{BTreeMap, HashMap}; use std::fs; use std::path::Path; -use unicase::UniCase; pub fn render( by_version: BTreeMap, @@ -149,16 +148,16 @@ fn author_map_to_scores(map: &AuthorMap) -> Vec { let scores = map .iter() .map(|(author, commits)| { - let name = UniCase::into_inner(author.name.clone()); + let name = author.name.to_string(); Entry { rank: 0, author: if debug_emails { - format!("{name} ({})", UniCase::into_inner(author.email.clone())) + format!("{name} ({})", author.email) } else { name }, - email: UniCase::into_inner(author.email.clone()), + email: author.email.to_string(), commits, } }) @@ -189,21 +188,27 @@ fn author_map_to_scores(map: &AuthorMap) -> Vec { fn deduplicate_scores(entries: Vec) -> Vec { let mut entry_map: HashMap> = HashMap::with_capacity(entries.len()); for entry in entries { - entry_map.entry(entry.email.clone()).or_default().push(entry); + entry_map + .entry(entry.email.clone()) + .or_default() + .push(entry); } - entry_map.into_values().map(|mut entry| { - // If there are multiple entries with the same maximum commit count, ensure that - // the ordering is stable, by sorting based on the whole entry. - entry.sort(); - let canonical_entry = entry.iter().max_by_key(|entry| entry.commits).unwrap(); - Entry { - rank: 0, - author: canonical_entry.author.clone(), - email: canonical_entry.email.clone(), - commits: entry.iter().map(|e| e.commits).sum(), - } - }).collect() + entry_map + .into_values() + .map(|mut entry| { + // If there are multiple entries with the same maximum commit count, ensure that + // the ordering is stable, by sorting based on the whole entry. + entry.sort(); + let canonical_entry = entry.iter().max_by_key(|entry| entry.commits).unwrap(); + Entry { + rank: 0, + author: canonical_entry.author.clone(), + email: canonical_entry.email.clone(), + commits: entry.iter().map(|e| e.commits).sum(), + } + }) + .collect() } fn releases(