semver/
error.rs

1use crate::parse::Error;
2use core::fmt::{self, Debug, Display};
3
4pub(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)]
20pub(crate) enum Position {
21    Major,
22    Minor,
23    Patch,
24    Pre,
25    Build,
26}
27
28#[cfg(feature = "std")]
29#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
30impl std::error::Error for Error {}
31
32impl Display for Error {
33    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
92impl Display for Position {
93    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
104impl Debug for Error {
105    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
113struct QuotedChar(char);
114
115impl Display for QuotedChar {
116    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}