use std::env;
use std::process::Command;
fn str_to_ymd(ymd: &str) -> Option<u32> {
let ymd: Vec<u32> = ymd.split("-").filter_map(|s| s.parse::<u32>().ok()).collect();
if ymd.len() != 3 {
return None
}
let (y, m, d) = (ymd[0], ymd[1], ymd[2]);
Some((y << 9) | (m << 5) | d)
}
fn str_to_mmp(mmp: &str) -> Option<u64> {
let mmp: Vec<u16> = mmp.split('-')
.nth(0)
.unwrap_or("")
.split('.')
.filter_map(|s| s.parse::<u16>().ok())
.collect();
if mmp.len() != 3 {
return None
}
let (maj, min, patch) = (mmp[0] as u64, mmp[1] as u64, mmp[2] as u64);
Some((maj << 32) | (min << 16) | patch)
}
fn get_version_and_date() -> Option<(String, String)> {
let output = env::var("RUSTC").ok()
.and_then(|rustc| Command::new(rustc).arg("--version").output().ok())
.or_else(|| Command::new("rustc").arg("--version").output().ok())
.and_then(|output| String::from_utf8(output.stdout).ok())
.map(|s| {
let mut components = s.split(" ");
let version = components.nth(1);
let date = components.nth(1).map(|s| s.trim_right().trim_right_matches(")"));
(version.map(|s| s.to_string()), date.map(|s| s.to_string()))
});
match output {
Some((Some(version), Some(date))) => Some((version, date)),
_ => None
}
}
pub fn is_min_date(min_date: &str) -> Option<(bool, String)> {
if let Some((_, actual_date_str)) = get_version_and_date() {
str_to_ymd(&actual_date_str)
.and_then(|actual| str_to_ymd(min_date).map(|min| (min, actual)))
.map(|(min, actual)| (actual >= min, actual_date_str))
} else {
None
}
}
pub fn is_min_version(min_version: &str) -> Option<(bool, String)> {
if let Some((actual_version_str, _)) = get_version_and_date() {
str_to_mmp(&actual_version_str)
.and_then(|actual| str_to_mmp(min_version).map(|min| (min, actual)))
.map(|(min, actual)| (actual >= min, actual_version_str))
} else {
None
}
}
pub fn is_nightly() -> Option<bool> {
get_version_and_date()
.map(|(actual_version_str, _)| actual_version_str.contains("nightly"))
}
pub fn is_beta() -> Option<bool> {
get_version_and_date()
.map(|(actual_version_str, _)| actual_version_str.contains("beta"))
}