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) => {
52 if !hash.starts_with('(') {
53 return None;
54 }
55 let date = words.next()?;
56 if !date.ends_with(')') {
57 return None;
58 }
59 let mut date = date[..date.len() - 1].split('-');
60 let year = date.next()?.parse().ok()?;
61 let month = date.next()?.parse().ok()?;
62 let day = date.next()?.parse().ok()?;
63 match date.next() {
64 None => Nightly(Date { year, month, day }),
65 Some(_) => return None,
66 }
67 }
68 None => Dev,
69 },
70 Some(_) => return None,
71 };
72
73 Some(Version {
74 minor,
75 patch,
76 channel,
77 })
78 }
79
80 impl Debug for Version {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result81 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
82 formatter
83 .debug_struct("crate::version::Version")
84 .field("minor", &self.minor)
85 .field("patch", &self.patch)
86 .field("channel", &self.channel)
87 .finish()
88 }
89 }
90
91 impl Debug for Channel {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result92 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
93 match self {
94 Channel::Stable => formatter.write_str("crate::version::Channel::Stable"),
95 Channel::Beta => formatter.write_str("crate::version::Channel::Beta"),
96 Channel::Nightly(date) => formatter
97 .debug_tuple("crate::version::Channel::Nightly")
98 .field(date)
99 .finish(),
100 Channel::Dev => formatter.write_str("crate::version::Channel::Dev"),
101 }
102 }
103 }
104
105 impl Debug for Date {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result106 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
107 formatter
108 .debug_struct("crate::date::Date")
109 .field("year", &self.year)
110 .field("month", &self.month)
111 .field("day", &self.day)
112 .finish()
113 }
114 }
115