macro_rules! expand_optional_params {
($params: expr,$($field:ident),*) => {
{
let self::Params {
$($field,)*
..
} = $params;
let mut token = TokenStream2::new();
$(if let Some(val) = $field {
token.extend(quote!{$field: #val,});
})*
token
}
};
}
#[inline]
pub(crate) fn parse_traffic(input: &Option<String>) -> proc_macro2::TokenStream {
let mut traffic = proc_macro2::TokenStream::new();
if let Some(val) = input {
traffic.extend(match &val[..] {
"Inbound" => quote::quote! {base::TrafficType::Inbound},
_ => quote::quote! {base::TrafficType::Inbound},
})
} else {
traffic.extend(quote::quote! {base::TrafficType::Inbound})
}
traffic
}
#[inline]
pub(crate) fn parse_args(input: &Option<String>) -> proc_macro2::TokenStream {
match input {
Some(input) => {
let input: proc_macro2::TokenStream = input.parse().unwrap();
quote::quote! {Some(#input)}
}
None => {
quote::quote! {None}
}
}
}
macro_rules! wrap_sentinel {
($name:ident,$params:expr,$func:expr) => {{
let ItemFn {
attrs,
vis,
sig,
block,
} = $func;
let stmts = &block.stmts;
let resource_name = sig.ident.to_string();
let traffic_type = parse_traffic(&$params.traffic_type);
let args = parse_args(&$params.args);
let rule = $name::process_rule(&resource_name, &$params);
let expanded = quote::quote! {
#(#attrs)* #vis #sig {
use sentinel_core::{base, $name, EntryBuilder};
use std::sync::Arc;
$name::append_rule(Arc::new(#rule));
let entry_builder = EntryBuilder::new(String::from(#resource_name))
.with_traffic_type(#traffic_type)
.with_args(#args);
match entry_builder.build() {
Ok(entry) => {
let result = {#(#stmts)*};
entry.exit();
Ok(result)
},
Err(err) => {
Err(err)
}
}
}
};
expanded.into()
}};
}
macro_rules! build {
($name:ident) => {
#[proc_macro_attribute]
pub fn $name(attr: TokenStream, func: TokenStream) -> TokenStream {
use darling::FromMeta;
use syn::ItemFn;
let attr = parse_macro_input!(attr as AttributeArgs);
let params = match $name::Params::from_list(&attr) {
Ok(v) => v,
Err(e) => {
return TokenStream::from(e.write_errors());
}
};
let func = parse_macro_input!(func as ItemFn);
let func = process_func(func);
wrap_sentinel!($name, params, func)
}
};
}
use quote::quote;
use syn::{ItemFn, ReturnType};
pub(crate) fn process_func(mut func: ItemFn) -> ItemFn {
let output = func.sig.output;
let dummy_func = match output {
ReturnType::Default => {
quote! {
fn dummy() -> sentinel_core::Result<()> {}
}
}
ReturnType::Type(_, return_type) => {
quote! {
fn dummy() -> sentinel_core::Result<#return_type> {}
}
}
};
let dummy_func: ItemFn = syn::parse2(dummy_func).unwrap();
func.sig.output = dummy_func.sig.output;
func
}