1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{DeriveInput, Error, Expr, Lit, Meta, parse_macro_input};
4
5#[proc_macro_attribute]
6pub fn config(args: TokenStream, input: TokenStream) -> TokenStream {
7 let input = parse_macro_input!(input as DeriveInput);
8
9 match config_impl(args, &input) {
10 Ok(tokens) => tokens,
11 Err(err) => err.to_compile_error().into(),
12 }
13}
14
15fn config_impl(args: TokenStream, input: &DeriveInput) -> syn::Result<TokenStream> {
16 let name = &input.ident;
17 let meta = syn::parse::<Meta>(args)?;
18
19 let nv = meta.require_name_value().map_err(|_| {
20 Error::new_spanned(&meta, r#"expected format: #[config(key = "section_name")]"#)
21 })?;
22
23 if !nv.path.is_ident("key") {
24 return Err(Error::new_spanned(&nv.path, "expected `key` attribute"));
25 }
26
27 let Expr::Lit(expr_lit) = &nv.value else {
28 return Err(Error::new_spanned(
29 &nv.value,
30 "expected string literal for key",
31 ));
32 };
33
34 let Lit::Str(lit_str) = &expr_lit.lit else {
35 return Err(Error::new_spanned(
36 &expr_lit.lit,
37 "expected string literal for key",
38 ));
39 };
40
41 #[cfg(feature = "axum")]
42 let expanded = quote! {
43 #input
44
45 impl ::axum_config::ConfigItem for #name {
46 fn key() -> &'static str {
47 #lit_str
48 }
49 }
50 };
51
52 #[cfg(not(feature = "axum"))]
53 let expanded = quote! {
54 #input
55
56 impl ::thisconfig::ConfigItem for #name {
57 fn key() -> &'static str {
58 #lit_str
59 }
60 }
61 };
62
63 Ok(expanded.into())
64}