Skip to main content

tuwunel_core/info/
cargo.rs

1//! Cargo metadata captured for the running build.
2//!
3//! Build-time macros embed the workspace manifest and selected crate manifests.
4//! This module processes that data lazily for runtime queries about project
5//! features and dependencies.
6
7use std::sync::OnceLock;
8
9use cargo_toml::{DepsSet, Manifest};
10use tuwunel_macros::cargo_manifest;
11
12use crate::Result;
13
14// Raw captures of the cargo manifest for each crate. This is provided by a
15// proc-macro at build time since the source directory and the cargo toml's may
16// not be present during execution.
17
18#[cargo_manifest]
19const WORKSPACE_MANIFEST: &'static str = ();
20#[cargo_manifest(crate = "macros")]
21const MACROS_MANIFEST: &'static str = ();
22#[cargo_manifest(crate = "core")]
23const CORE_MANIFEST: &'static str = ();
24#[cargo_manifest(crate = "database")]
25const DATABASE_MANIFEST: &'static str = ();
26#[cargo_manifest(crate = "service")]
27const SERVICE_MANIFEST: &'static str = ();
28#[cargo_manifest(crate = "admin")]
29const ADMIN_MANIFEST: &'static str = ();
30#[cargo_manifest(crate = "router")]
31const ROUTER_MANIFEST: &'static str = ();
32#[cargo_manifest(crate = "main")]
33const MAIN_MANIFEST: &'static str = ();
34
35/// Processed list of features across all project crates. This is generated from
36/// the data in the MANIFEST strings and contains all possible project features.
37/// For *enabled* features see the info::rustc module instead.
38static FEATURES: OnceLock<Vec<String>> = OnceLock::new();
39
40/// Processed list of dependencies. This is generated from the data captured in
41/// the MANIFEST.
42static DEPENDENCIES: OnceLock<DepsSet> = OnceLock::new();
43
44#[must_use]
45/// Lists dependency names declared by the workspace manifest.
46///
47/// Names borrow from the lazily parsed dependency map. Their ordering follows
48/// the map's deterministic key order.
49///
50/// # Panics
51///
52/// Panics when the embedded workspace manifest is invalid or lacks its
53/// workspace section.
54pub fn dependencies_names() -> Vec<&'static str> {
55	dependencies()
56		.keys()
57		.map(String::as_str)
58		.collect()
59}
60
61/// Returns dependencies declared by the embedded workspace manifest.
62///
63/// The manifest is parsed once on first access and the ordered map is retained
64/// for the process lifetime. Package-specific dependency tables are not merged
65/// here.
66///
67/// # Panics
68///
69/// Panics when the manifest is invalid or lacks its workspace section.
70pub fn dependencies() -> &'static DepsSet {
71	DEPENDENCIES.get_or_init(|| {
72		init_dependencies().unwrap_or_else(|e| panic!("Failed to initialize dependencies: {e}"))
73	})
74}
75
76/// List of all possible features for the project. For *enabled* features in
77/// this build see the companion function in info::rustc.
78pub fn features() -> &'static Vec<String> {
79	FEATURES.get_or_init(|| {
80		init_features().unwrap_or_else(|e| panic!("Failed initialize features: {e}"))
81	})
82}
83
84fn init_features() -> Result<Vec<String>> {
85	let mut features = Vec::new();
86	append_features(&mut features, WORKSPACE_MANIFEST)?;
87	append_features(&mut features, MACROS_MANIFEST)?;
88	append_features(&mut features, CORE_MANIFEST)?;
89	append_features(&mut features, DATABASE_MANIFEST)?;
90	append_features(&mut features, SERVICE_MANIFEST)?;
91	append_features(&mut features, ADMIN_MANIFEST)?;
92	append_features(&mut features, ROUTER_MANIFEST)?;
93	append_features(&mut features, MAIN_MANIFEST)?;
94	features.sort();
95	features.dedup();
96
97	Ok(features)
98}
99
100fn append_features(features: &mut Vec<String>, manifest: &str) -> Result {
101	let manifest = Manifest::from_str(manifest)?;
102	features.extend(manifest.features.keys().cloned());
103
104	Ok(())
105}
106
107fn init_dependencies() -> Result<DepsSet> {
108	let manifest = Manifest::from_str(WORKSPACE_MANIFEST)?;
109	let deps_set = manifest
110		.workspace
111		.as_ref()
112		.expect("manifest has workspace section")
113		.dependencies
114		.clone();
115
116	Ok(deps_set)
117}