player_plugin_macros/
lib.rs1use proc_macro::TokenStream;
4use quote::quote;
5use syn::{ItemFn, parse_macro_input, spanned::Spanned};
6
7#[proc_macro_attribute]
9pub fn export(args: TokenStream, item: TokenStream) -> TokenStream {
10 if !args.is_empty() {
11 return syn::Error::new(
12 proc_macro2::Span::call_site(),
13 "`export` takes no arguments",
14 )
15 .to_compile_error()
16 .into();
17 }
18
19 let factory = parse_macro_input!(item as ItemFn);
20 let signature = &factory.sig;
21 if signature.asyncness.is_some() {
22 return syn::Error::new(signature.span(), "plugin factories cannot be async")
23 .to_compile_error()
24 .into();
25 }
26 if !signature.generics.params.is_empty() || signature.generics.where_clause.is_some() {
27 return syn::Error::new(
28 signature.generics.span(),
29 "plugin factories cannot be generic",
30 )
31 .to_compile_error()
32 .into();
33 }
34 if !signature.inputs.is_empty() {
35 return syn::Error::new(
36 signature.inputs.span(),
37 "plugin factories must take no arguments",
38 )
39 .to_compile_error()
40 .into();
41 }
42
43 let factory_name = &signature.ident;
44 quote! {
45 #factory
46
47 #[doc(hidden)]
48 #[allow(unsafe_code)]
49 #[unsafe(no_mangle)]
50 pub extern "C" fn vesper_plugin_entry()
51 -> *const ::player_plugin::__private::VesperPluginRoot
52 {
53 ::player_plugin::__private::export_plugin(#factory_name)
54 }
55 }
56 .into()
57}