• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use self::Channel::*;
2 use std::fmt::{self, Debug};
3 
4 pub enum ParseResult {
5     Success(Version),
6     OopsClippy,
7     Unrecognized,
8 }
9 
10 #[cfg_attr(test, derive(PartialEq))]
11 pub struct Version {
12     pub minor: u16,
13     pub patch: u16,
14     pub channel: Channel,
15 }
16 
17 #[cfg_attr(test, derive(PartialEq))]
18 pub enum Channel {
19     Stable,
20     Beta,
21     Nightly(Date),
22     Dev,
23 }
24 
25 #[cfg_attr(test, derive(PartialEq))]
26 pub struct Date {
27     pub year: u16,
28     pub month: u8,
29     pub day: u8,
30 }
31 
parse(string: &str) -> ParseResult32 pub fn parse(string: &str) -> ParseResult {
33     let last_line = string.lines().last().unwrap_or(string);
34     let mut words = last_line.trim().split(' ');
35 
36     match words.next() {
37         Some("rustc") => {}
38         Some(word) if word.starts_with("clippy") => return ParseResult::OopsClippy,
39         Some(_) | None => return ParseResult::Unrecognized,
40     }
41 
42     parse_words(&mut words).map_or(ParseResult::Unrecognized, ParseResult::Success)
43 }
44 
parse_words(words: &mut dyn Iterator<Item = &str>) -> Option<Version>45 fn parse_words(words: &mut dyn Iterator<Item = &str>) -> Option<Version> {
46     let mut version_channel = words.next()?.split('-');
47     let version = version_channel.next()?;
48     let channel = version_channel.next();
49 
50     let mut digits = version.split('.');
51     let major = digits.next()?;
52     if major != "1" {
53         return None;
54     }
55     let minor = digits.next()?.parse().ok()?;
56     let patch = digits.next().unwrap_or("0").parse().ok()?;
57 
58     let channel = match channel {
59         None => Stable,
60         Some(channel) if channel == "dev" => Dev,
61         Some(channel) if channel.starts_with("beta") => Beta,
62         Some(channel) if channel == "nightly" => match words.next() {
63             Some(hash) if hash.starts_with('(') => match words.next() {
64                 None if hash.ends_with(')') => Dev,
65                 Some(date) if date.ends_with(')') => {
66                     let mut date = date[..date.len() - 1].split('-');
67                     let year = date.next()?.parse().ok()?;
68                     let month = date.next()?.parse().ok()?;
69                     let day = date.next()?.parse().ok()?;
70                     match date.next() {
71                         None => Nightly(Date { year, month, day }),
72                         Some(_) => return None,
73                     }
74                 }
75                 None | Some(_) => return None,
76             },
77             Some(_) => return None,
78             None => Dev,
79         },
80         Some(_) => return None,
81     };
82 
83     Some(Version {
84         minor,
85         patch,
86         channel,
87     })
88 }
89 
90 impl Debug for Version {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result91     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
92         formatter
93             .debug_struct("crate::version::Version")
94             .field("minor", &self.minor)
95             .field("patch", &self.patch)
96             .field("channel", &self.channel)
97             .finish()
98     }
99 }
100 
101 impl Debug for Channel {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result102     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
103         match self {
104             Channel::Stable => formatter.write_str("crate::version::Channel::Stable"),
105             Channel::Beta => formatter.write_str("crate::version::Channel::Beta"),
106             Channel::Nightly(date) => formatter
107                 .debug_tuple("crate::version::Channel::Nightly")
108                 .field(date)
109                 .finish(),
110             Channel::Dev => formatter.write_str("crate::version::Channel::Dev"),
111         }
112     }
113 }
114 
115 impl Debug for Date {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result116     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
117         formatter
118             .debug_struct("crate::date::Date")
119             .field("year", &self.year)
120             .field("month", &self.month)
121             .field("day", &self.day)
122             .finish()
123     }
124 }
125