use proc_macro2::TokenStream;
use syn::{
Attribute, Expr, FieldValue, Ident, parse::Parse, punctuated::Punctuated, spanned::Spanned,
token::Comma,
};
use crate::{
args::{self, Arg},
hook, key,
util::FieldValueKey,
};
pub struct Args {
pub inspect: bool,
}
impl Parse for Args {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let mut inspect = Arg::bool("inspect");
args::set_from_field_values(
input.parse_terminated(FieldValue::parse, Token![,])?.iter(),
[&mut inspect],
)?;
Ok(Args {
inspect: inspect.take_or_default(),
})
}
}
pub fn eval_key_value_with_hook(
attrs: &[Attribute],
fv: &FieldValue,
fn_name: &TokenStream,
interpolated: bool,
captured: bool,
) -> syn::Result<TokenStream> {
let key_expr = fv.key_expr()?;
let value_expr = &fv.expr;
let key_tokens = key::key_with_hook(&[], &key_expr, interpolated, captured);
let value_tokens = value_with_hook(&value_expr, fn_name, interpolated, captured);
hook::eval_hooks(
&attrs,
syn::parse_quote_spanned!(fv.span()=>
{
(#key_tokens, #value_tokens)
}),
)
}
pub fn raw_key_value(fv: &FieldValue) -> syn::Result<TokenStream> {
let key = fv.key_expr()?;
let value = &fv.expr;
Ok(quote_spanned!(fv.span()=> (#key, #value)))
}
pub fn eval_key_with_hook(
attrs: &[Attribute],
fv: &FieldValue,
interpolated: bool,
captured: bool,
) -> syn::Result<TokenStream> {
let key_expr = fv.key_expr()?;
let key_tokens = key::key_with_hook(&[], &key_expr, interpolated, captured);
hook::eval_hooks(&attrs, syn::parse_quote_spanned!(fv.span()=>#key_tokens))
}
pub(crate) fn value_with_hook(
expr: &Expr,
fn_name: &TokenStream,
interpolated: bool,
captured: bool,
) -> TokenStream {
let interpolated_expr = if interpolated {
quote!(.__private_interpolated())
} else {
quote!(.__private_uninterpolated())
};
let captured_expr = if captured {
quote!(.__private_captured())
} else {
quote!(.__private_uncaptured())
};
quote_spanned!(expr.span()=> #[allow(unused_imports)] {
use emit::__private::{__PrivateCaptureHook as _, __PrivateOptionalCaptureHook as _, __PrivateOptionalHook as _, __PrivateInterpolatedHook as _, __PrivateKeyExternalHook as _};
(#expr).#fn_name().__private_key_external() #interpolated_expr #captured_expr
})
}
pub fn default_fn_name(fv: &FieldValue) -> TokenStream {
match fv.key_name().as_deref() {
Ok(emit_core::well_known::KEY_LVL) => {
quote_spanned!(fv.span()=> __private_capture_as_level)
}
Ok(emit_core::well_known::KEY_ERR) => {
quote_spanned!(fv.span()=> __private_capture_as_error)
}
Ok(emit_core::well_known::KEY_SPAN_ID) => {
quote_spanned!(fv.span()=> __private_capture_as_span_id)
}
Ok(emit_core::well_known::KEY_SPAN_PARENT) => {
quote_spanned!(fv.span()=> __private_capture_as_span_id)
}
Ok(emit_core::well_known::KEY_TRACE_ID) => {
quote_spanned!(fv.span()=> __private_capture_as_trace_id)
}
_ => quote_spanned!(fv.span()=> __private_capture_as_default),
}
}
pub struct RenameHookTokens<T> {
pub name: &'static str,
pub args: TokenStream,
pub expr: TokenStream,
pub to: T,
}
pub fn rename_hook_tokens(
opts: RenameHookTokens<impl Fn(&Args) -> TokenStream>,
) -> Result<TokenStream, syn::Error> {
hook::rename_hook_tokens(hook::RenameHookTokens {
name: opts.name,
target: "values in `emit` macros",
args: opts.args,
expr: opts.expr,
predicate: |ident: &str| {
ident.starts_with("__private_capture") || ident.starts_with("__private_captured")
},
to: move |hook_args: &Args, ident: &Ident, args: &Punctuated<Expr, Comma>| {
if ident.to_string().starts_with("__private_captured") {
return None;
}
let to_ident = (opts.to)(hook_args);
Some((to_ident, quote!(#args)))
},
})
}