1mod derive;
2
3use proc_macro::TokenStream;
4use proc_macro2::{Ident, Span};
5use quote::quote;
6use syn::{DeriveInput, Error, ItemFn};
7
8#[proc_macro_attribute]
9pub fn arma(_attr: TokenStream, item: TokenStream) -> TokenStream {
12 let ast = syn::parse_macro_input!(item as ItemFn);
13 let init = ast.sig.ident.clone();
14
15 let extern_type = if cfg!(windows) { "stdcall" } else { "C" };
16
17 let ext_init = quote! {
18 if RV_EXTENSION.is_none() {
19 RV_EXTENSION = Some(#init());
20 }
21 };
22
23 #[cfg(all(target_os = "windows", target_arch = "x86"))]
24 let prefix = "safe32_";
25
26 #[cfg(not(all(target_os = "windows", target_arch = "x86")))]
27 let prefix = "";
28
29 macro_rules! fn_ident {
30 ( $name:literal ) => {
31 Ident::new(&format!("{prefix}{}", $name), Span::call_site())
32 };
33 }
34 let versionfn = fn_ident!("RVExtensionVersion");
35 let noargfn = fn_ident!("RVExtension");
36 let argfn = fn_ident!("RVExtensionArgs");
37 let callbackfn = fn_ident!("RVExtensionRegisterCallback");
38 let contextfn = fn_ident!("RVExtensionContext");
39
40 TokenStream::from(quote! {
41 use arma_rs::libc as arma_rs_libc;
42
43 static mut RV_EXTENSION: Option<Extension> = None;
44
45 #[cfg(all(target_os="windows", target_arch="x86"))]
46 arma_rs::link_args::windows! {
47 unsafe {
48 raw("/EXPORT:_RVExtensionVersion@8=_safe32_RVExtensionVersion@8");
49 raw("/EXPORT:_RVExtension@12=_safe32_RVExtension@12");
50 raw("/EXPORT:_RVExtensionArgs@20=_safe32_RVExtensionArgs@20");
51 raw("/EXPORT:_RVExtensionRegisterCallback@4=_safe32_RVExtensionRegisterCallback@4");
52 raw("/EXPORT:_RVExtensionContext@8=_safe32_RVExtensionContext@8");
53 }
54 }
55
56 #[no_mangle]
59 #[doc(hidden)]
60 pub unsafe extern #extern_type fn #versionfn(output: *mut arma_rs_libc::c_char, size: arma_rs_libc::size_t) -> arma_rs_libc::c_int {
61 #ext_init
62 if let Some(ext) = &RV_EXTENSION {
63 arma_rs::write_cstr(ext.version().to_string(), output, size);
64 }
65 0
66 }
67
68 #[no_mangle]
71 #[doc(hidden)]
72 pub unsafe extern #extern_type fn #noargfn(output: *mut arma_rs_libc::c_char, size: arma_rs_libc::size_t, function: *mut arma_rs_libc::c_char) {
73 #ext_init
74 if let Some(ext) = &RV_EXTENSION {
75 if ext.allow_no_args() {
76 ext.handle_call(function, output, size, None, None, true);
77 }
78 }
79 }
80
81 #[no_mangle]
84 #[doc(hidden)]
85 pub unsafe extern #extern_type fn #argfn(output: *mut arma_rs_libc::c_char, size: arma_rs_libc::size_t, function: *mut arma_rs_libc::c_char, args: *mut *mut arma_rs_libc::c_char, arg_count: arma_rs_libc::c_int) -> arma_rs_libc::c_int {
86 #ext_init
87 if let Some(ext) = &RV_EXTENSION {
88 ext.handle_call(function, output, size, Some(args), Some(arg_count), true)
89 } else {
90 0
91 }
92 }
93
94 #[no_mangle]
97 #[doc(hidden)]
98 pub unsafe extern #extern_type fn #callbackfn(callback: arma_rs::Callback) {
99 #ext_init
100 if let Some(ext) = &mut RV_EXTENSION {
101 ext.register_callback(callback);
102 ext.run_callbacks();
103 }
104 }
105
106 #[no_mangle]
109 #[doc(hidden)]
110 pub unsafe extern #extern_type fn #contextfn(args: *mut *mut arma_rs_libc::c_char, arg_count: arma_rs_libc::c_int) {
111 #ext_init
112 if let Some(ext) = &mut RV_EXTENSION {
113 ext.handle_call_context(args, arg_count);
114 }
115 }
116
117 #ast
118 })
119}
120
121#[proc_macro_derive(FromArma, attributes(arma))]
135pub fn derive_from_arma(item: TokenStream) -> TokenStream {
136 let input = syn::parse_macro_input!(item as DeriveInput);
137 derive::generate_from_arma(input)
138 .unwrap_or_else(Error::into_compile_error)
139 .into()
140}
141
142#[proc_macro_derive(IntoArma, attributes(arma))]
154pub fn derive_into_arma(item: TokenStream) -> TokenStream {
155 let input = syn::parse_macro_input!(item as DeriveInput);
156 derive::generate_into_arma(input)
157 .unwrap_or_else(Error::into_compile_error)
158 .into()
159}