use proc_macro::TokenStream;
use quote::quote;
use syn::{
Ident, ItemFn, LitStr, Result, Token,
parse::{Parse, ParseStream},
parse_macro_input,
};
extern crate proc_macro;
struct MonitorArgs {
name: Option<String>,
}
impl Parse for MonitorArgs {
fn parse(input: ParseStream) -> Result<Self> {
let mut name = None;
if input.is_empty() {
return Ok(MonitorArgs { name });
}
if input.peek(syn::LitStr) {
let lit: LitStr = input.parse()?;
name = Some(lit.value());
}
else if input.peek(syn::Ident) {
let key: Ident = input.parse()?;
if key == "name" {
input.parse::<Token![=]>()?; let lit: LitStr = input.parse()?;
name = Some(lit.value());
} else {
return Err(syn::Error::new(
key.span(),
"Unknown argument (expected 'name')",
));
}
}
Ok(MonitorArgs { name })
}
}
#[proc_macro_attribute]
pub fn monitor_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as ItemFn);
let args = parse_macro_input!(attr as MonitorArgs);
let fn_name = &input.sig.ident;
let vis = &input.vis;
let sig = &input.sig;
let block = &input.block;
let attrs = &input.attrs;
let mut output_name = fn_name.to_string();
if let Some(custom_name) = args.name {
output_name = custom_name;
}
if input.sig.asyncness.is_some() {
quote! {
compile_error!("`monitor_fn` macro does not support async functions yet.");
}
.into()
} else {
quote! {
#(#attrs)*
#vis #sig {
{
let core_id = rustmeter_beacon::core_id::get_current_core_id();
use rustmeter_beacon::monitors::VALUE_MONITOR_REGISTRY;
let (local_id, registered_newly) = rustmeter_beacon::get_static_id_by_registry!(
rustmeter_beacon::monitors::CODE_MONITOR_REGISTRY
);
if registered_newly {
let fn_addr = #fn_name as usize;
let payload = rustmeter_beacon::protocol::TypeDefinitionPayload::FunctionMonitor {
monitor_id: local_id as u8,
fn_address: fn_addr as u32,
};
rustmeter_beacon::tracing::write_tracing_event(
rustmeter_beacon::protocol::EventPayload::TypeDefinition(payload)
);
rustmeter_beacon::monitors::defmt_trace_new_function_monitor(#output_name, local_id);
}
let _guard = rustmeter_beacon::monitors::DropGuard::new(|| {
rustmeter_beacon::protocol::raw_writers::write_monitor_end();
});
rustmeter_beacon::protocol::raw_writers::write_monitor_start(local_id as u8);
{ #block }
}
}
}.into()
}
}