Skip to main content

tuwunel_core/info/
cargo.rs

1//! Information about the build related to Cargo. This is a frontend interface
2//! informed by proc-macros that capture raw information at build time which is
3//! further processed at runtime either during static initialization or as
4//! necessary.
5
6use std::sync::OnceLock;
7
8use cargo_toml::{DepsSet, Manifest};
9use tuwunel_macros::cargo_manifest;
10
11use crate::Result;
12
13// Raw captures of the cargo manifest for each crate. This is provided by a
14// proc-macro at build time since the source directory and the cargo toml's may
15// not be present during execution.
16
17#[cargo_manifest]
18const WORKSPACE_MANIFEST: &'static str = ();
19#[cargo_manifest(crate = "macros")]
20const MACROS_MANIFEST: &'static str = ();
21#[cargo_manifest(crate = "core")]
22const CORE_MANIFEST: &'static str = ();
23#[cargo_manifest(crate = "database")]
24const DATABASE_MANIFEST: &'static str = ();
25#[cargo_manifest(crate = "service")]
26const SERVICE_MANIFEST: &'static str = ();
27#[cargo_manifest(crate = "admin")]
28const ADMIN_MANIFEST: &'static str = ();
29#[cargo_manifest(crate = "router")]
30const ROUTER_MANIFEST: &'static str = ();
31#[cargo_manifest(crate = "main")]
32const MAIN_MANIFEST: &'static str = ();
33
34/// Processed list of features across all project crates. This is generated from
35/// the data in the MANIFEST strings and contains all possible project features.
36/// For *enabled* features see the info::rustc module instead.
37static FEATURES: OnceLock<Vec<String>> = OnceLock::new();
38
39/// Processed list of dependencies. This is generated from the data captured in
40/// the MANIFEST.
41static DEPENDENCIES: OnceLock<DepsSet> = OnceLock::new();
42
43#[must_use]
44pub fn dependencies_names() -> Vec<&'static str> {
45	dependencies()
46		.keys()
47		.map(String::as_str)
48		.collect()
49}
50
51pub fn dependencies() -> &'static DepsSet {
52	DEPENDENCIES.get_or_init(|| {
53		init_dependencies().unwrap_or_else(|e| panic!("Failed to initialize dependencies: {e}"))
54	})
55}
56
57/// List of all possible features for the project. For *enabled* features in
58/// this build see the companion function in info::rustc.
59pub fn features() -> &'static Vec<String> {
60	FEATURES.get_or_init(|| {
61		init_features().unwrap_or_else(|e| panic!("Failed initialize features: {e}"))
62	})
63}
64
65fn init_features() -> Result<Vec<String>> {
66	let mut features = Vec::new();
67	append_features(&mut features, WORKSPACE_MANIFEST)?;
68	append_features(&mut features, MACROS_MANIFEST)?;
69	append_features(&mut features, CORE_MANIFEST)?;
70	append_features(&mut features, DATABASE_MANIFEST)?;
71	append_features(&mut features, SERVICE_MANIFEST)?;
72	append_features(&mut features, ADMIN_MANIFEST)?;
73	append_features(&mut features, ROUTER_MANIFEST)?;
74	append_features(&mut features, MAIN_MANIFEST)?;
75	features.sort();
76	features.dedup();
77
78	Ok(features)
79}
80
81fn append_features(features: &mut Vec<String>, manifest: &str) -> Result {
82	let manifest = Manifest::from_str(manifest)?;
83	features.extend(manifest.features.keys().cloned());
84
85	Ok(())
86}
87
88fn init_dependencies() -> Result<DepsSet> {
89	let manifest = Manifest::from_str(WORKSPACE_MANIFEST)?;
90	let deps_set = manifest
91		.workspace
92		.as_ref()
93		.expect("manifest has workspace section")
94		.dependencies
95		.clone();
96
97	Ok(deps_set)
98}