summaryrefslogtreecommitdiffstats
path: root/vendor/gix-mailmap/src/parse.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:41:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:41:35 +0000
commit7e5d7eea9c580ef4b41a765bde624af431942b96 (patch)
tree2c0d9ca12878fc4525650aa4e54d77a81a07cc09 /vendor/gix-mailmap/src/parse.rs
parentAdding debian version 1.70.0+dfsg1-9. (diff)
downloadrustc-7e5d7eea9c580ef4b41a765bde624af431942b96.tar.xz
rustc-7e5d7eea9c580ef4b41a765bde624af431942b96.zip
Merging upstream version 1.70.0+dfsg2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/gix-mailmap/src/parse.rs')
-rw-r--r--vendor/gix-mailmap/src/parse.rs116
1 files changed, 116 insertions, 0 deletions
diff --git a/vendor/gix-mailmap/src/parse.rs b/vendor/gix-mailmap/src/parse.rs
new file mode 100644
index 000000000..c6752f6f3
--- /dev/null
+++ b/vendor/gix-mailmap/src/parse.rs
@@ -0,0 +1,116 @@
+mod error {
+ use bstr::BString;
+
+ /// The error returned by [`parse()`][crate::parse()].
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error("Line {line_number} has too many names or emails, or none at all: {line:?}")]
+ UnconsumedInput { line_number: usize, line: BString },
+ #[error("{line_number}: {line:?}: {message}")]
+ Malformed {
+ line_number: usize,
+ line: BString,
+ message: String,
+ },
+ }
+}
+
+use bstr::{BStr, ByteSlice};
+pub use error::Error;
+
+use crate::Entry;
+
+/// An iterator to parse mailmap lines on-demand.
+pub struct Lines<'a> {
+ lines: bstr::Lines<'a>,
+ line_no: usize,
+}
+
+impl<'a> Lines<'a> {
+ pub(crate) fn new(input: &'a [u8]) -> Self {
+ Lines {
+ lines: input.as_bstr().lines(),
+ line_no: 0,
+ }
+ }
+}
+
+impl<'a> Iterator for Lines<'a> {
+ type Item = Result<Entry<'a>, Error>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ for line in self.lines.by_ref() {
+ self.line_no += 1;
+ match line.first() {
+ None => continue,
+ Some(b) if *b == b'#' => continue,
+ Some(_) => {}
+ }
+ let line = line.trim();
+ if line.is_empty() {
+ continue;
+ }
+ return parse_line(line.into(), self.line_no).into();
+ }
+ None
+ }
+}
+
+fn parse_line(line: &BStr, line_number: usize) -> Result<Entry<'_>, Error> {
+ let (name1, email1, rest) = parse_name_and_email(line, line_number)?;
+ let (name2, email2, rest) = parse_name_and_email(rest, line_number)?;
+ if !rest.trim().is_empty() {
+ return Err(Error::UnconsumedInput {
+ line_number,
+ line: line.into(),
+ });
+ }
+ Ok(match (name1, email1, name2, email2) {
+ (Some(proper_name), Some(commit_email), None, None) => Entry::change_name_by_email(proper_name, commit_email),
+ (None, Some(proper_email), None, Some(commit_email)) => {
+ Entry::change_email_by_email(proper_email, commit_email)
+ }
+ (Some(proper_name), Some(proper_email), None, Some(commit_email)) => {
+ Entry::change_name_and_email_by_email(proper_name, proper_email, commit_email)
+ }
+ (Some(proper_name), Some(proper_email), Some(commit_name), Some(commit_email)) => {
+ Entry::change_name_and_email_by_name_and_email(proper_name, proper_email, commit_name, commit_email)
+ }
+ _ => {
+ return Err(Error::Malformed {
+ line_number,
+ line: line.into(),
+ message: "Emails without a name or email to map to are invalid".into(),
+ })
+ }
+ })
+}
+
+fn parse_name_and_email(
+ line: &BStr,
+ line_number: usize,
+) -> Result<(Option<&'_ BStr>, Option<&'_ BStr>, &'_ BStr), Error> {
+ match line.find_byte(b'<') {
+ Some(start_bracket) => {
+ let email = &line[start_bracket + 1..];
+ let closing_bracket = email.find_byte(b'>').ok_or_else(|| Error::Malformed {
+ line_number,
+ line: line.into(),
+ message: "Missing closing bracket '>' in email".into(),
+ })?;
+ let email = email[..closing_bracket].trim().as_bstr();
+ if email.is_empty() {
+ return Err(Error::Malformed {
+ line_number,
+ line: line.into(),
+ message: "Email must not be empty".into(),
+ });
+ }
+ let name = line[..start_bracket].trim().as_bstr();
+ let rest = line[start_bracket + closing_bracket + 2..].as_bstr();
+ Ok(((!name.is_empty()).then_some(name), Some(email), rest))
+ }
+ None => Ok((None, None, line)),
+ }
+}