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}