diff options
Diffstat (limited to 'third_party/rust/rustversion/build/rustc.rs')
-rw-r--r-- | third_party/rust/rustversion/build/rustc.rs | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/third_party/rust/rustversion/build/rustc.rs b/third_party/rust/rustversion/build/rustc.rs new file mode 100644 index 0000000000..71a830b93a --- /dev/null +++ b/third_party/rust/rustversion/build/rustc.rs @@ -0,0 +1,124 @@ +use self::Channel::*; +use std::fmt::{self, Debug}; + +pub enum ParseResult { + Success(Version), + OopsClippy, + Unrecognized, +} + +#[cfg_attr(test, derive(PartialEq))] +pub struct Version { + pub minor: u16, + pub patch: u16, + pub channel: Channel, +} + +#[cfg_attr(test, derive(PartialEq))] +pub enum Channel { + Stable, + Beta, + Nightly(Date), + Dev, +} + +#[cfg_attr(test, derive(PartialEq))] +pub struct Date { + pub year: u16, + pub month: u8, + pub day: u8, +} + +pub fn parse(string: &str) -> ParseResult { + let last_line = string.lines().last().unwrap_or(string); + let mut words = last_line.trim().split(' '); + + match words.next() { + Some("rustc") => {} + Some(word) if word.starts_with("clippy") => return ParseResult::OopsClippy, + Some(_) | None => return ParseResult::Unrecognized, + } + + parse_words(&mut words).map_or(ParseResult::Unrecognized, ParseResult::Success) +} + +fn parse_words(words: &mut dyn Iterator<Item = &str>) -> Option<Version> { + let mut version_channel = words.next()?.split('-'); + let version = version_channel.next()?; + let channel = version_channel.next(); + + let mut digits = version.split('.'); + let major = digits.next()?; + if major != "1" { + return None; + } + let minor = digits.next()?.parse().ok()?; + let patch = digits.next().unwrap_or("0").parse().ok()?; + + let channel = match channel { + None => Stable, + Some(channel) if channel == "dev" => Dev, + Some(channel) if channel.starts_with("beta") => Beta, + Some(channel) if channel == "nightly" => match words.next() { + Some(hash) if hash.starts_with('(') => match words.next() { + None if hash.ends_with(')') => Dev, + Some(date) if date.ends_with(')') => { + let mut date = date[..date.len() - 1].split('-'); + let year = date.next()?.parse().ok()?; + let month = date.next()?.parse().ok()?; + let day = date.next()?.parse().ok()?; + match date.next() { + None => Nightly(Date { year, month, day }), + Some(_) => return None, + } + } + None | Some(_) => return None, + }, + Some(_) => return None, + None => Dev, + }, + Some(_) => return None, + }; + + Some(Version { + minor, + patch, + channel, + }) +} + +impl Debug for Version { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_struct("crate::version::Version") + .field("minor", &self.minor) + .field("patch", &self.patch) + .field("channel", &self.channel) + .finish() + } +} + +impl Debug for Channel { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Channel::Stable => formatter.write_str("crate::version::Channel::Stable"), + Channel::Beta => formatter.write_str("crate::version::Channel::Beta"), + Channel::Nightly(date) => formatter + .debug_tuple("crate::version::Channel::Nightly") + .field(date) + .finish(), + Channel::Dev => formatter.write_str("crate::version::Channel::Dev"), + } + } +} + +impl Debug for Date { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_struct("crate::date::Date") + .field("year", &self.year) + .field("month", &self.month) + .field("day", &self.day) + .finish() + } +} |