abi_singleton/
lib.rs

1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::{format_ident, quote};
5use spanned::Spanned;
6use syn::*;
7
8fn func_ident(namespace: &str, trait_name: &str, fun_sig_ident: &Ident) -> Ident {
9    format_ident!(
10        "__api_{}_{}_{}",
11        namespace,
12        trait_name.to_lowercase(),
13        fun_sig_ident
14    )
15}
16
17pub fn api_trait(item: TokenStream, namespace: &str) -> TokenStream {
18    let f = parse_macro_input!(item as ItemTrait);
19
20    let trait_name = f.ident.to_string();
21
22    let mut funcs = Vec::new();
23    let mut default_funcs = Vec::new();
24
25    for item in &f.items {
26        if let TraitItem::Fn(func) = item {
27            let ident = func.sig.ident.clone();
28            let inputs = func.sig.inputs.clone();
29            let output = func.sig.output.clone();
30            let safe = func.sig.unsafety;
31
32            let api_name = func_ident(namespace, &trait_name, &ident);
33
34            if let Some(default) = &func.default {
35                default_funcs.push(quote! {
36                    #[unsafe( no_mangle)]
37                    #[linkage="weak"]
38                    unsafe extern "C" fn #api_name (#inputs) #output #default
39
40                });
41            }
42
43            let mut args = Vec::new();
44
45            for arg in &inputs {
46                if let FnArg::Typed(t) = arg {
47                    if let Pat::Ident(i) = t.pat.as_ref() {
48                        let ident = &i.ident;
49                        args.push(quote! { #ident , });
50                    }
51                }
52            }
53            funcs.push(quote! {
54
55                pub #safe fn #ident (#inputs) #output{
56                    unsafe extern "C" {
57                        fn #api_name ( #inputs ) #output;
58                    }
59
60                    unsafe{ #api_name ( #(#args)* ) }
61                }
62            });
63        } else {
64            return parse::Error::new(item.span(), "only func is supported")
65                .to_compile_error()
66                .into();
67        }
68    }
69    let struct_name = format_ident!("{}Impl", trait_name);
70
71    quote! {
72        #f
73        pub struct #struct_name;
74
75        impl #struct_name {
76            #(#funcs)*
77        }
78
79        #(#default_funcs)*
80    }
81    .into()
82}
83
84pub fn api_impl(item: TokenStream, namespace: &str) -> TokenStream {
85    let f = parse_macro_input!(item as ItemImpl);
86
87    let mut funcs = Vec::new();
88
89    let ty = f.self_ty.clone();
90
91    let trait_name = f.trait_.as_ref().unwrap().1.get_ident().unwrap();
92
93    for item in &f.items {
94        if let ImplItem::Fn(func) = item {
95            let ident = func.sig.ident.clone();
96            let inputs = func.sig.inputs.clone();
97            let output = func.sig.output.clone();
98
99            let api_name = func_ident(namespace, &trait_name.to_string(), &func.sig.ident);
100
101            let mut args = Vec::new();
102
103            for arg in &inputs {
104                if let FnArg::Typed(t) = arg {
105                    if let Pat::Ident(i) = t.pat.as_ref() {
106                        let ident = &i.ident;
107                        args.push(quote! { #ident , });
108                    }
109                }
110            }
111
112            funcs.push(quote! {
113                #[unsafe(no_mangle)]
114                unsafe extern "C" fn #api_name (#inputs) #output{
115                    #ty:: #ident ( #(#args)* )
116                }
117            });
118        }
119    }
120
121    quote! {
122        #f
123        #(#funcs)*
124
125    }
126    .into()
127}