opentelemetry_derive_impl/
lib.rs

1use darling::{util::Ignored, FromDeriveInput};
2use proc_macro2::TokenStream;
3use quote::quote;
4use syn::{parse_macro_input, DeriveInput, Path};
5
6#[derive(FromDeriveInput)]
7#[darling(attributes(otel))]
8struct Options<Key, Variant> {
9    key: Key,
10    variant: Variant,
11}
12
13#[proc_macro_derive(Key, attributes(otel))]
14pub fn key(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
15    derive(input, key_impl)
16}
17
18fn key_impl(input: DeriveInput) -> syn::Result<TokenStream> {
19    let options = Options::<Option<String>, Option<Ignored>>::from_derive_input(&input)?;
20    let ident = input.ident;
21    let key = options.key.unwrap_or(ident.to_string().to_lowercase());
22    Ok(quote! {
23        impl #ident {
24            const KEY: opentelemetry::Key = opentelemetry::Key::from_static_str(#key);
25        }
26
27        #[automatically_derived]
28        impl From<&#ident> for opentelemetry::Key {
29            fn from(_: &#ident) -> Self {
30                #ident::KEY
31            }
32        }
33
34        #[automatically_derived]
35        impl From<#ident> for opentelemetry::Key {
36            fn from(_: #ident) -> Self {
37                #ident::KEY
38            }
39        }
40    })
41}
42
43#[proc_macro_derive(KeyValue)]
44pub fn key_value(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
45    derive(input, key_value_impl)
46}
47
48fn key_value_impl(input: DeriveInput) -> syn::Result<TokenStream> {
49    let ident = input.ident;
50    Ok(quote! {
51        #[automatically_derived]
52        impl From<&#ident> for opentelemetry::KeyValue {
53            fn from(value: &#ident) -> Self {
54                Self::new(value, value)
55            }
56        }
57
58        #[automatically_derived]
59        impl From<#ident> for opentelemetry::KeyValue {
60            fn from(value: #ident) -> Self {
61                Self::from(&value)
62            }
63        }
64    })
65}
66
67#[proc_macro_derive(StringValue)]
68pub fn string_value(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
69    derive(input, string_value_impl)
70}
71
72fn string_value_impl(input: DeriveInput) -> syn::Result<TokenStream> {
73    let ident = input.ident;
74    Ok(quote! {
75        const _: () = {
76            struct AssertToString where #ident: ToString;
77        };
78
79        #[automatically_derived]
80        impl From<&#ident> for opentelemetry::StringValue {
81            fn from(value: &#ident) -> Self {
82                value.to_string().into()
83            }
84        }
85
86        #[automatically_derived]
87        impl From<#ident> for opentelemetry::StringValue {
88            fn from(value: #ident) -> Self {
89                Self::from(&value)
90            }
91        }
92    })
93}
94
95#[proc_macro_derive(Value, attributes(otel))]
96pub fn value(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
97    derive(input, value_impl)
98}
99
100fn value_impl(input: DeriveInput) -> syn::Result<TokenStream> {
101    let options = Options::<Option<Ignored>, Path>::from_derive_input(&input)?;
102    let ident = input.ident;
103    let variant = options.variant;
104    Ok(quote! {
105        #[automatically_derived]
106        impl From<&#ident> for opentelemetry::Value {
107            fn from(value: &#ident) -> Self {
108                #variant::from(value).into()
109            }
110        }
111
112        #[automatically_derived]
113        impl From<#ident> for opentelemetry::Value {
114            fn from(value: #ident) -> Self {
115                Self::from(&value)
116            }
117        }
118    })
119}
120
121fn derive(
122    input: proc_macro::TokenStream,
123    f: fn(DeriveInput) -> syn::Result<TokenStream>,
124) -> proc_macro::TokenStream {
125    let input = parse_macro_input!(input as DeriveInput);
126    f(input)
127        .unwrap_or_else(syn::Error::into_compile_error)
128        .into()
129}