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