feat: Add ability to inspect build information and features at runtime

Also re-adds ability to inspect used features
This commit is contained in:
Jade Ellis
2026-01-20 21:01:21 +00:00
parent 108a4fe336
commit 16de2a2cc0
26 changed files with 317 additions and 4 deletions
+2
View File
@@ -2,6 +2,7 @@
name = "conduwuit_macros"
description.workspace = true
edition.workspace = true
homepage.workspace = true
license.workspace = true
readme.workspace = true
repository.workspace = true
@@ -17,6 +18,7 @@ syn.workspace = true
quote.workspace = true
proc-macro2.workspace = true
itertools.workspace = true
cargo_toml.workspace = true
[lints]
workspace = true
+63
View File
@@ -0,0 +1,63 @@
use proc_macro2::TokenStream;
use quote::quote;
use crate::Result;
pub(super) fn introspect(_args: TokenStream) -> Result<TokenStream> {
let cargo_crate_name = std::env::var("CARGO_CRATE_NAME").unwrap();
let crate_name = cargo_crate_name.trim_start_matches("conduwuit_");
let is_core = cargo_crate_name == "conduwuit_core";
let flags = std::env::args().collect::<Vec<_>>();
let mut enabled_features = Vec::new();
append_features(&mut enabled_features, flags);
let enabled_count = enabled_features.len();
let import_path = if is_core {
quote! { use crate::conduwuit_core; }
} else {
quote! { use ::conduwuit_core; }
};
let ret = quote! {
#[doc(hidden)]
mod __compile_introspection {
#import_path
/// Features that were enabled when this crate was compiled
const ENABLED: [&str; #enabled_count] = [#( #enabled_features ),*];
const CRATE_NAME: &str = #crate_name;
/// Register this crate's features with the global registry during static initialization
#[::ctor::ctor]
fn register() {
conduwuit_core::info::introspection::ENABLED_FEATURES.lock().unwrap().insert(#crate_name, &ENABLED);
}
#[::ctor::dtor]
fn unregister() {
conduwuit_core::info::introspection::ENABLED_FEATURES.lock().unwrap().remove(#crate_name);
}
}
};
Ok(ret)
}
fn append_features(features: &mut Vec<String>, flags: Vec<String>) {
let mut next_is_cfg = false;
for flag in flags {
let is_cfg = flag == "--cfg";
let is_feature = flag.starts_with("feature=");
if std::mem::replace(&mut next_is_cfg, is_cfg) && is_feature {
if let Some(feature) = flag
.split_once('=')
.map(|(_, feature)| feature.trim_matches('"'))
{
features.push(feature.to_owned());
}
}
}
}
+8
View File
@@ -1,4 +1,5 @@
mod admin;
mod build_info;
mod config;
mod debug;
mod implement;
@@ -44,6 +45,13 @@ pub fn config_example_generator(args: TokenStream, input: TokenStream) -> TokenS
attribute_macro::<ItemStruct, _>(args, input, config::example_generator)
}
#[proc_macro]
pub fn introspect_crate(input: TokenStream) -> TokenStream {
build_info::introspect(input.into())
.unwrap_or_else(|e| e.to_compile_error())
.into()
}
fn attribute_macro<I, F>(args: TokenStream, input: TokenStream, func: F) -> TokenStream
where
F: Fn(I, &[Meta]) -> Result<TokenStream>,