From cf82eb0ad61edff04e62daa2c0ca8f479299f1cb Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 4 Feb 2022 12:29:35 -0800 Subject: [PATCH] Improve error on comma after wildcard --- src/error.rs | 8 ++++++++ src/parse.rs | 19 +++++++++++-------- tests/test_version_req.rs | 5 ++++- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/error.rs b/src/error.rs index 4d57950e..56cb69fe 100644 --- a/src/error.rs +++ b/src/error.rs @@ -10,6 +10,7 @@ pub(crate) enum ErrorKind { Overflow(Position), EmptySegment(Position), IllegalCharacter(Position), + CommaAfterWildcard(char), UnexpectedAfterWildcard, ExcessiveComparators, } @@ -58,6 +59,13 @@ impl Display for Error { ErrorKind::IllegalCharacter(pos) => { write!(formatter, "unexpected character in {}", pos) } + ErrorKind::CommaAfterWildcard(ch) => { + write!( + formatter, + "wildcard req ({}) must be the only comparator in the version req", + ch, + ) + } ErrorKind::UnexpectedAfterWildcard => { formatter.write_str("unexpected character after wildcard in version req") } diff --git a/src/parse.rs b/src/parse.rs index 017a5b53..fd10bcfd 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -82,14 +82,17 @@ impl FromStr for VersionReq { fn from_str(text: &str) -> Result { let text = text.trim_start_matches(' '); - if let Some(text) = wildcard(text) { - if text.trim_start_matches(' ').is_empty() { + if let Some((ch, text)) = wildcard(text) { + let rest = text.trim_start_matches(' '); + if rest.is_empty() { #[cfg(not(no_const_vec_new))] return Ok(VersionReq::STAR); #[cfg(no_const_vec_new)] // rustc <1.39 return Ok(VersionReq { comparators: Vec::new(), }); + } else if rest.starts_with(',') { + return Err(Error::new(ErrorKind::CommaAfterWildcard(ch))); } else { return Err(Error::new(ErrorKind::UnexpectedAfterWildcard)); } @@ -181,13 +184,13 @@ fn numeric_identifier(input: &str, pos: Position) -> Result<(u64, &str), Error> } } -fn wildcard(input: &str) -> Option<&str> { +fn wildcard(input: &str) -> Option<(char, &str)> { if let Some(rest) = input.strip_prefix('*') { - Some(rest) + Some(('*', rest)) } else if let Some(rest) = input.strip_prefix('x') { - Some(rest) + Some(('x', rest)) } else if let Some(rest) = input.strip_prefix('X') { - Some(rest) + Some(('X', rest)) } else { None } @@ -293,7 +296,7 @@ fn comparator(input: &str) -> Result<(Comparator, Position, &str), Error> { let (minor, text) = if let Some(text) = text.strip_prefix('.') { pos = Position::Minor; - if let Some(text) = wildcard(text) { + if let Some((_, text)) = wildcard(text) { has_wildcard = true; if default_op { op = Op::Wildcard; @@ -309,7 +312,7 @@ fn comparator(input: &str) -> Result<(Comparator, Position, &str), Error> { let (patch, text) = if let Some(text) = text.strip_prefix('.') { pos = Position::Patch; - if let Some(text) = wildcard(text) { + if let Some((_, text)) = wildcard(text) { if default_op { op = Op::Wildcard; } diff --git a/tests/test_version_req.rs b/tests/test_version_req.rs index d22e092b..51eba1ce 100644 --- a/tests/test_version_req.rs +++ b/tests/test_version_req.rs @@ -417,7 +417,10 @@ fn test_leading_digit_in_pre_and_build() { #[test] fn test_wildcard_and_another() { let err = req_err("*, 0.20.0-any"); - assert_to_string(err, "unexpected character after wildcard in version req"); + assert_to_string( + err, + "wildcard req (*) must be the only comparator in the version req", + ); let err = req_err("0.20.0-any, *"); assert_to_string(