1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{Attribute, ImplItem, ItemImpl, ItemStruct, LitStr, parse_macro_input};
4
5mod inventory_derive;
6
7#[proc_macro_derive(AllInventoryVarsGen)]
8pub fn all_inventory_vars_gen_derive(input: TokenStream) -> TokenStream {
9 inventory_derive::vars_gen_derive(input)
10}
11
12fn get_doc_comment(attrs: &[Attribute]) -> String {
16 attrs
17 .iter()
18 .filter_map(|attr| {
19 if attr.path().is_ident("doc") {
20 if let syn::Meta::NameValue(meta) = &attr.meta {
21 if let syn::Expr::Lit(expr) = &meta.value {
22 if let syn::Lit::Str(str) = &expr.lit {
23 return Some(str.value().trim().to_string());
24 }
25 }
26 }
27 }
28 None
29 })
30 .collect::<Vec<_>>()
31 .join("\n")
32}
33
34fn get_env_var_pattern_from_attr(attrs: &[Attribute]) -> Option<String> {
38 attrs
39 .iter()
40 .find(|attr| attr.path().is_ident("attr_env_var_pattern"))
41 .and_then(|attr| attr.parse_args::<LitStr>().ok())
42 .map(|lit_str| lit_str.value())
43}
44
45fn is_hidden(attrs: &[Attribute]) -> bool {
49 attrs.iter().any(|attr| attr.path().is_ident("attr_hidden"))
50}
51
52#[proc_macro_attribute]
56pub fn attr_hidden(_attr: TokenStream, item: TokenStream) -> TokenStream {
57 item
58}
59
60#[proc_macro_attribute]
66pub fn attribute_env_vars_metadata(_attr: TokenStream, input: TokenStream) -> TokenStream {
67 let ast = parse_macro_input!(input as ItemImpl);
68
69 let constants: Vec<_> = ast
70 .items
71 .iter()
72 .filter_map(|item| match item {
73 ImplItem::Const(item) if !is_hidden(&item.attrs) => {
74 let name = item.ident.to_string();
75 let doc = get_doc_comment(&item.attrs);
76 Some((name, doc))
77 }
78 ImplItem::Fn(item) if !is_hidden(&item.attrs) => {
79 match get_env_var_pattern_from_attr(&item.attrs) {
81 Some(pattern) => {
82 let doc = get_doc_comment(&item.attrs);
83 Some((pattern, doc))
84 }
85 _ => {
86 None }
88 }
89 }
90 _ => None,
91 })
92 .collect();
93
94 let struct_name = &ast.self_ty;
95 let pairs = constants.iter().map(|(name, doc)| {
96 quote! {
97 (#name, #doc)
98 }
99 });
100
101 let expanded = quote! {
102 #ast
103
104 impl #struct_name {
105 pub fn metadata<'a>() -> &'a [(&'static str, &'static str)] {
107 &[#(#pairs),*]
108 }
109 }
110 };
111
112 expanded.into()
113}
114
115#[proc_macro_derive(FieldCount)]
117pub fn derive_field_count(input: TokenStream) -> TokenStream {
118 let input = parse_macro_input!(input as ItemStruct);
119 let field_count = input.fields.iter().count();
120 let name = &input.ident;
121 let output = quote! {
122 impl #name {
123 pub fn field_count() -> usize {
124 #field_count
125 }
126 }
127 };
128 TokenStream::from(output)
129}