Skip to main content

tuwunel_core/info/
rustc.rs

1//! Information about the build related to rustc. This is a frontend interface
2//! informed by proc-macros at build time. Since the project is split into
3//! several crates, lower-level information is supplied from each crate during
4//! static initialization.
5
6use std::{
7	collections::BTreeMap,
8	mem::replace,
9	sync::{Mutex, OnceLock},
10};
11
12// Capture rustc version during compilation.
13tuwunel_macros::rustc_version! {}
14
15/// Raw capture of rustc flags used to build each crate in the project. Informed
16/// by rustc_flags_capture macro (one in each crate's mod.rs). This is
17/// done during static initialization which is why it's mutex-protected and pub.
18/// Should not be written to by anything other than our macro.
19pub static FLAGS: Mutex<BTreeMap<&str, &[&str]>> = Mutex::new(BTreeMap::new());
20
21/// Processed list of enabled features across all project crates. This is
22/// generated from the data in FLAGS.
23static FEATURES: OnceLock<Vec<&'static str>> = OnceLock::new();
24
25/// List of features enabled for the project.
26pub fn features() -> &'static Vec<&'static str> { FEATURES.get_or_init(init_features) }
27
28/// Version of the rustc compiler used during build.
29#[inline]
30#[must_use]
31pub fn version() -> Option<&'static str> {
32	RUSTC_VERSION
33		.len()
34		.gt(&0)
35		.then_some(RUSTC_VERSION)
36}
37
38fn init_features() -> Vec<&'static str> {
39	let mut features = Vec::new();
40	FLAGS
41		.lock()
42		.expect("locked")
43		.iter()
44		.for_each(|(_, flags)| append_features(&mut features, flags));
45
46	features.sort_unstable();
47	features.dedup();
48	features
49}
50
51fn append_features(features: &mut Vec<&'static str>, flags: &[&'static str]) {
52	let mut next_is_cfg = false;
53	for flag in flags {
54		let is_cfg = *flag == "--cfg";
55		let is_feature = flag.starts_with("feature=");
56		if replace(&mut next_is_cfg, is_cfg)
57			&& is_feature
58			&& let Some(feature) = flag
59				.split_once('=')
60				.map(|(_, feature)| feature.trim_matches('"'))
61		{
62			features.push(feature);
63		}
64	}
65}