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