scuffle_metrics_derive/
enum_impl.rs1use darling::FromMeta;
2use darling::ast::NestedMeta;
3use proc_macro2::TokenStream;
4
5#[derive(Debug, darling::FromMeta)]
6struct VariantAttr {
7 rename: Option<syn::LitStr>,
8}
9
10#[derive(Debug, darling::FromMeta)]
11struct EnumAttr {
12 crate_path: Option<syn::Path>,
13}
14
15pub(crate) fn metric_enum_impl(input: TokenStream) -> syn::Result<TokenStream> {
16 let input = syn::parse2::<syn::ItemEnum>(input)?;
17 let enum_ident = &input.ident;
18
19 let branches = input
21 .variants
22 .iter()
23 .map(|variant| {
24 let ident = &variant.ident;
25 if matches!(variant.fields, syn::Fields::Named(_) | syn::Fields::Unnamed(_)) {
26 return Err(syn::Error::new_spanned(ident, "only unit enums are supported"));
27 }
28
29 let mut meta = Vec::new();
31 for attr in &variant.attrs {
32 if attr.path().is_ident("metrics") {
33 match &attr.meta {
34 syn::Meta::List(syn::MetaList { tokens, .. }) => {
35 meta.extend(NestedMeta::parse_meta_list(tokens.clone())?);
36 }
37 _ => return Err(syn::Error::new_spanned(attr, "expected list")),
38 }
39 }
40 }
41
42 let options = VariantAttr::from_list(&meta)?;
43
44 let name = options.rename.map(|lit| lit.value()).unwrap_or_else(|| ident.to_string());
45
46 Ok(quote::quote! {
47 #enum_ident::#ident => #name,
48 })
49 })
50 .collect::<syn::Result<Vec<_>>>()?;
51
52 let mut meta = Vec::new();
53 for attr in &input.attrs {
54 if attr.path().is_ident("metrics") {
55 match &attr.meta {
56 syn::Meta::List(syn::MetaList { tokens, .. }) => {
57 meta.extend(NestedMeta::parse_meta_list(tokens.clone())?);
58 }
59 _ => return Err(syn::Error::new_spanned(attr, "expected list")),
60 }
61 }
62 }
63
64 let options = EnumAttr::from_list(&meta)?;
65
66 let crate_path = options.crate_path.unwrap_or_else(|| syn::parse_quote!(::scuffle_metrics));
67
68 Ok(quote::quote! {
69 impl ::core::convert::From<#enum_ident> for #crate_path::opentelemetry::Value {
70 fn from(value: #enum_ident) -> Self {
71 let value = match value {
72 #(#branches)*
73 };
74
75 #crate_path::opentelemetry::Value::String(value.into())
76 }
77 }
78 })
79}