1use std::borrow::Cow;
2use std::fmt::{self, Display};
3use std::sync::OnceLock;
4
5use rustc_error_messages::{DiagArgValue, IntoDiagArg};
6use rustc_macros::{
7 Decodable, Encodable, HashStable_Generic, PrintAttribute, current_rustc_version,
8};
9
10use crate::attrs::PrintAttribute;
11
12#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
13#[derive(HashStable_Generic, PrintAttribute)]
14pub struct RustcVersion {
15 pub major: u16,
16 pub minor: u16,
17 pub patch: u16,
18}
19
20impl RustcVersion {
21 pub const CURRENT: Self = current_rustc_version!();
22 pub fn current_overridable() -> Self {
23 *CURRENT_OVERRIDABLE.get_or_init(|| {
24 if let Ok(override_var) = std::env::var("RUSTC_OVERRIDE_VERSION_STRING")
25 && let Some(override_) = Self::parse_str(&override_var)
26 {
27 override_
28 } else {
29 Self::CURRENT
30 }
31 })
32 }
33 fn parse_str(value: &str) -> Option<Self> {
34 let mut components = value.split('-').next().unwrap().splitn(3, '.');
36 let major = components.next()?.parse().ok()?;
37 let minor = components.next()?.parse().ok()?;
38 let patch = components.next().unwrap_or("0").parse().ok()?;
39 Some(RustcVersion { major, minor, patch })
40 }
41}
42
43static CURRENT_OVERRIDABLE: OnceLock<RustcVersion> = OnceLock::new();
44
45impl Display for RustcVersion {
46 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
47 write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
48 }
49}
50
51impl IntoDiagArg for RustcVersion {
52 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
53 DiagArgValue::Str(Cow::Owned(self.to_string()))
54 }
55}