tidy/features/
version.rs

1use std::fmt;
2use std::num::ParseIntError;
3use std::str::FromStr;
4
5#[cfg(test)]
6mod tests;
7
8pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
11#[cfg_attr(feature = "build-metrics", derive(serde::Serialize))]
12pub enum Version {
13    Explicit { parts: [u32; 3] },
14    CurrentPlaceholder,
15}
16
17impl fmt::Display for Version {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        match self {
20            Version::Explicit { parts } => {
21                f.pad(&format!("{}.{}.{}", parts[0], parts[1], parts[2]))
22            }
23            Version::CurrentPlaceholder => f.pad(&format!("CURRENT")),
24        }
25    }
26}
27
28#[derive(Debug, PartialEq, Eq)]
29pub enum ParseVersionError {
30    ParseIntError(ParseIntError),
31    WrongNumberOfParts,
32}
33
34impl From<ParseIntError> for ParseVersionError {
35    fn from(err: ParseIntError) -> Self {
36        ParseVersionError::ParseIntError(err)
37    }
38}
39
40impl FromStr for Version {
41    type Err = ParseVersionError;
42
43    fn from_str(s: &str) -> Result<Self, Self::Err> {
44        if s == VERSION_PLACEHOLDER {
45            return Ok(Version::CurrentPlaceholder);
46        }
47        let mut iter = s.split('.').map(|part| Ok(part.parse()?));
48
49        let mut part = || iter.next().unwrap_or(Err(ParseVersionError::WrongNumberOfParts));
50
51        let parts = [part()?, part()?, part()?];
52
53        if iter.next().is_some() {
54            // Ensure we don't have more than 3 parts.
55            return Err(ParseVersionError::WrongNumberOfParts);
56        }
57
58        Ok(Version::Explicit { parts })
59    }
60}