#![allow(clippy::module_name_repetitions)]
use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{
parse::{Parse, ParseStream},
parse_macro_input,
punctuated::Punctuated,
Ident, Result, Token,
};
struct ProfileArgs {
name: String,
args: Punctuated<Ident, Token![,]>,
}
impl Parse for ProfileArgs {
fn parse(input: ParseStream) -> Result<Self> {
let name = input.parse::<Ident>()?.to_string();
let args = if input.is_empty() {
Punctuated::new()
} else {
input.parse::<Token![,]>()?;
input.parse_terminated(Ident::parse, Token![,])?
};
Ok(Self { name, args })
}
}
pub fn profile_impl(input: TokenStream) -> TokenStream {
let ProfileArgs { name, args } = parse_macro_input!(input as ProfileArgs);
let has_time = args.iter().any(|arg| arg == "time" || arg == "both");
let has_mem_summary = args.iter().any(|arg| arg == "mem_summary" || arg == "both");
let has_mem_detail = args.iter().any(|arg| arg == "mem_detail");
let is_async = args.iter().any(|arg| arg == "async_fn");
let is_unbounded = args.iter().any(|arg| arg == "unbounded");
let use_global = args.iter().any(|arg| arg == "global");
let profile_type = if use_global {
quote! { ::thag_profiler::get_global_profile_type() }
} else if has_time && (has_mem_summary || has_mem_detail) {
quote! { ::thag_profiler::ProfileType::Both }
} else if has_time {
quote! { ::thag_profiler::ProfileType::Time }
} else if has_mem_summary || has_mem_detail {
quote! { ::thag_profiler::ProfileType::Memory }
} else {
quote! { ::thag_profiler::get_global_profile_type() }
};
let detailed_memory = has_mem_detail;
let (start_line, end_line) = if has_time && !(has_mem_summary || has_mem_detail) {
(quote! { None }, quote! { None })
} else if is_unbounded {
(quote! { Some(line!()) }, quote! { None })
} else {
let end_line_fn = format_ident!("end_{name}");
(quote! { Some(line!()) }, quote! { Some(#end_line_fn()) })
};
let profile_id = format_ident!("{name}");
#[cfg(not(feature = "full_profiling"))]
let expanded = quote! {
let #profile_id = ::thag_profiler::Profile::new(
Some(#name),
None,
#profile_type,
#is_async,
#detailed_memory,
file!(),
#start_line,
#end_line
);
};
#[cfg(feature = "full_profiling")]
let expanded = quote! {
let #profile_id = ::thag_profiler::safe_alloc! {
::thag_profiler::Profile::new(
Some(#name),
None,
#profile_type,
#is_async,
#detailed_memory,
file!(),
#start_line,
#end_line
)
};
};
expanded.into()
}