diff options
Diffstat (limited to 'vendor/portable-atomic/version.rs')
-rw-r--r-- | vendor/portable-atomic/version.rs | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/vendor/portable-atomic/version.rs b/vendor/portable-atomic/version.rs new file mode 100644 index 0000000..92f6ae1 --- /dev/null +++ b/vendor/portable-atomic/version.rs @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use std::{env, process::Command, str}; + +pub(crate) fn rustc_version() -> Option<Version> { + let rustc = env::var_os("RUSTC")?; + // Use verbose version output because the packagers add extra strings to the normal version output. + let output = Command::new(rustc).args(&["--version", "--verbose"]).output().ok()?; + let verbose_version = str::from_utf8(&output.stdout).ok()?; + Version::parse(verbose_version) +} + +#[cfg_attr(test, derive(Debug, PartialEq))] +pub(crate) struct Version { + pub(crate) minor: u32, + pub(crate) nightly: bool, + commit_date: Date, + pub(crate) llvm: u32, +} + +impl Version { + // The known latest stable version. If we unable to determine + // the rustc version, we assume this is the current version. + // It is no problem if this is older than the actual latest stable. + // LLVM version is assumed to be the minimum external LLVM version: + // https://github.com/rust-lang/rust/blob/1.74.0/src/bootstrap/llvm.rs#L558 + pub(crate) const LATEST: Self = Self::stable(74, 15); + + pub(crate) const fn stable(rustc_minor: u32, llvm_major: u32) -> Self { + Self { minor: rustc_minor, nightly: false, commit_date: Date::UNKNOWN, llvm: llvm_major } + } + + pub(crate) fn probe(&self, minor: u32, year: u16, month: u8, day: u8) -> bool { + if self.nightly { + self.minor > minor || self.commit_date >= Date::new(year, month, day) + } else { + self.minor >= minor + } + } + + #[cfg(test)] + pub(crate) fn commit_date(&self) -> &Date { + &self.commit_date + } + + pub(crate) fn parse(verbose_version: &str) -> Option<Self> { + let mut release = verbose_version + .lines() + .find(|line| line.starts_with("release: ")) + .map(|line| &line["release: ".len()..])? + .splitn(2, '-'); + let version = release.next().unwrap(); + let channel = release.next().unwrap_or_default(); + let mut digits = version.splitn(3, '.'); + let major = digits.next()?.parse::<u32>().ok()?; + if major != 1 { + return None; + } + let minor = digits.next()?.parse::<u32>().ok()?; + let _patch = digits.next().unwrap_or("0").parse::<u32>().ok()?; + let nightly = channel == "nightly" || channel == "dev"; + + let llvm_major = (|| { + let version = verbose_version + .lines() + .find(|line| line.starts_with("LLVM version: ")) + .map(|line| &line["LLVM version: ".len()..])?; + let mut digits = version.splitn(3, '.'); + let major = digits.next()?.parse::<u32>().ok()?; + let _minor = digits.next()?.parse::<u32>().ok()?; + let _patch = digits.next().unwrap_or("0").parse::<u32>().ok()?; + Some(major) + })() + .unwrap_or(0); + + // we don't refer commit date on stable/beta. + if nightly { + let commit_date = (|| { + let mut commit_date = verbose_version + .lines() + .find(|line| line.starts_with("commit-date: ")) + .map(|line| &line["commit-date: ".len()..])? + .splitn(3, '-'); + let year = commit_date.next()?.parse::<u16>().ok()?; + let month = commit_date.next()?.parse::<u8>().ok()?; + let day = commit_date.next()?.parse::<u8>().ok()?; + if month > 12 || day > 31 { + return None; + } + Some(Date::new(year, month, day)) + })(); + Some(Self { + minor, + nightly, + commit_date: commit_date.unwrap_or(Date::UNKNOWN), + llvm: llvm_major, + }) + } else { + Some(Self::stable(minor, llvm_major)) + } + } +} + +#[derive(PartialEq, PartialOrd)] +#[cfg_attr(test, derive(Debug))] +pub(crate) struct Date { + pub(crate) year: u16, + pub(crate) month: u8, + pub(crate) day: u8, +} + +impl Date { + const UNKNOWN: Self = Self::new(0, 0, 0); + + const fn new(year: u16, month: u8, day: u8) -> Self { + Self { year, month, day } + } +} |