mod internal;
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Item, ReturnType, Signature};
fn create_plugin_proc_macro_fn(
input: TokenStream,
export_name: &str,
parameter_type: &str,
) -> TokenStream {
let parameter_type: syn::Type =
syn::parse_str(parameter_type).expect("failed to parse ServiceRegistry type");
let input = parse_macro_input!(input as syn::Item);
let syn::ItemFn { sig, block, .. } = match input {
syn::Item::Fn(f) => f,
_ => panic!("only `fn` items allowed"),
};
let (ident, inputs) = match sig {
Signature {
asyncness: Some(_), ..
} => {
panic!("async factories are not yet supported")
}
Signature {
variadic: Some(_), ..
} => {
panic!("variadic factories are not yet supported")
}
Signature {
ident,
output,
inputs,
generics,
..
} => {
if !matches!(output, ReturnType::Default) {
panic!("function must have no output")
}
if !generics.params.is_empty() {
panic!("generic factories are not yet supported")
}
if inputs.len() != 1 {
panic!("only one input parameter is supported")
}
(ident, inputs)
}
};
let inner_fn_name =
syn::Ident::new(&("__inner_".to_string() + &ident.to_string()), ident.span());
quote! {
#[export_name = #export_name]
pub extern "C" fn #ident(registry: #parameter_type) {
#[inline(always)]
fn #inner_fn_name (#inputs) {
picodata_plugin::internal::set_panic_hook();
#block
}
#inner_fn_name(registry)
}
}
.into()
}
#[proc_macro_attribute]
pub fn proc_service_registrar(_attr: TokenStream, input: TokenStream) -> TokenStream {
create_plugin_proc_macro_fn(
input,
"pico_service_registrar",
"&mut picodata_plugin::plugin::interface::ServiceRegistry",
)
}
#[proc_macro_attribute]
pub fn proc_migration_validator(_attr: TokenStream, input: TokenStream) -> TokenStream {
create_plugin_proc_macro_fn(
input,
"pico_migration_validator",
"&mut picodata_plugin::plugin::interface::MigrationValidator",
)
}
#[proc_macro_attribute]
pub fn internal(_args: TokenStream, input: TokenStream) -> TokenStream {
let attribute = internal::InternalAttribute;
match parse_macro_input!(input as Item) {
Item::Type(item_type) => attribute.expand(item_type),
Item::Enum(item_enum) => attribute.expand(item_enum),
Item::Struct(item_struct) => attribute.expand(item_struct),
Item::Fn(item_fn) => attribute.expand(item_fn),
Item::Mod(item_mod) => attribute.expand(item_mod),
Item::Trait(item_trait) => attribute.expand(item_trait),
Item::Const(item_const) => attribute.expand(item_const),
Item::Static(item_static) => attribute.expand(item_static),
Item::Use(item_use) => attribute.expand(item_use),
_ => panic!("unsupported item type"),
}
}