1 use crate::parse::Error; 2 use core::fmt::{self, Debug, Display}; 3 4 pub(crate) enum ErrorKind { 5 Empty, 6 UnexpectedEnd(Position), 7 UnexpectedChar(Position, char), 8 UnexpectedCharAfter(Position, char), 9 ExpectedCommaFound(Position, char), 10 LeadingZero(Position), 11 Overflow(Position), 12 EmptySegment(Position), 13 IllegalCharacter(Position), 14 WildcardNotTheOnlyComparator(char), 15 UnexpectedAfterWildcard, 16 ExcessiveComparators, 17 } 18 19 #[derive(Copy, Clone, Eq, PartialEq)] 20 pub(crate) enum Position { 21 Major, 22 Minor, 23 Patch, 24 Pre, 25 Build, 26 } 27 28 #[cfg(feature = "std")] 29 #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] 30 impl std::error::Error for Error {} 31 32 impl Display for Error { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result33 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 34 match &self.kind { 35 ErrorKind::Empty => formatter.write_str("empty string, expected a semver version"), 36 ErrorKind::UnexpectedEnd(pos) => { 37 write!(formatter, "unexpected end of input while parsing {}", pos) 38 } 39 ErrorKind::UnexpectedChar(pos, ch) => { 40 write!( 41 formatter, 42 "unexpected character {} while parsing {}", 43 QuotedChar(*ch), 44 pos, 45 ) 46 } 47 ErrorKind::UnexpectedCharAfter(pos, ch) => { 48 write!( 49 formatter, 50 "unexpected character {} after {}", 51 QuotedChar(*ch), 52 pos, 53 ) 54 } 55 ErrorKind::ExpectedCommaFound(pos, ch) => { 56 write!( 57 formatter, 58 "expected comma after {}, found {}", 59 pos, 60 QuotedChar(*ch), 61 ) 62 } 63 ErrorKind::LeadingZero(pos) => { 64 write!(formatter, "invalid leading zero in {}", pos) 65 } 66 ErrorKind::Overflow(pos) => { 67 write!(formatter, "value of {} exceeds u64::MAX", pos) 68 } 69 ErrorKind::EmptySegment(pos) => { 70 write!(formatter, "empty identifier segment in {}", pos) 71 } 72 ErrorKind::IllegalCharacter(pos) => { 73 write!(formatter, "unexpected character in {}", pos) 74 } 75 ErrorKind::WildcardNotTheOnlyComparator(ch) => { 76 write!( 77 formatter, 78 "wildcard req ({}) must be the only comparator in the version req", 79 ch, 80 ) 81 } 82 ErrorKind::UnexpectedAfterWildcard => { 83 formatter.write_str("unexpected character after wildcard in version req") 84 } 85 ErrorKind::ExcessiveComparators => { 86 formatter.write_str("excessive number of version comparators") 87 } 88 } 89 } 90 } 91 92 impl Display for Position { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result93 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 94 formatter.write_str(match self { 95 Position::Major => "major version number", 96 Position::Minor => "minor version number", 97 Position::Patch => "patch version number", 98 Position::Pre => "pre-release identifier", 99 Position::Build => "build metadata", 100 }) 101 } 102 } 103 104 impl Debug for Error { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result105 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 106 formatter.write_str("Error(\"")?; 107 Display::fmt(self, formatter)?; 108 formatter.write_str("\")")?; 109 Ok(()) 110 } 111 } 112 113 struct QuotedChar(char); 114 115 impl Display for QuotedChar { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result116 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 117 // Standard library versions prior to https://github.com/rust-lang/rust/pull/95345 118 // print character 0 as '\u{0}'. We prefer '\0' to keep error messages 119 // the same across all supported Rust versions. 120 if self.0 == '\0' { 121 formatter.write_str("'\\0'") 122 } else { 123 write!(formatter, "{:?}", self.0) 124 } 125 } 126 } 127