use crate::ast_types;
use crate::new_ident;
use crate::parsed_type::*;
use proc_macro2::TokenStream;
use quote::quote;
impl quote::ToTokens for ast_types::AstExternMod {
fn to_tokens(&self, tokens: &mut TokenStream) {
crate::prepare_global_data!(
ExternMod,
self,
self.namespace,
data,
data_size,
global_static_name,
section_name
);
let wasm_import_module_name = &self.namespace;
let original = &self.original;
let generated_imports = generate_extern_section_items(&self);
let wrapper_functions = generate_wrapper_functions(&self);
let glue_code = quote! {
#[link(wasm_import_module = #wasm_import_module_name)]
#[cfg(target_arch = "wasm32")]
extern "C" {
#(#generated_imports)*
}
#[cfg(not(target_arch = "wasm32"))]
#original
#wrapper_functions
#[cfg(target_arch = "wasm32")]
#[doc(hidden)]
#[allow(clippy::all)]
#[link_section = #section_name]
pub static #global_static_name: [u8; #data_size] = { *#data };
};
tokens.extend(glue_code);
}
}
fn generate_extern_section_items(extern_item: &ast_types::AstExternMod) -> Vec<TokenStream> {
let mut section_items = Vec::with_capacity(extern_item.imports.len());
for import in &extern_item.imports {
let signature = &import.signature;
let fn_return_type = crate::parsed_type::generate_fn_return_type(&signature.output_type);
let link_name = import.link_name.as_ref().unwrap_or(&signature.name);
let import_name = generate_import_name(&signature.name);
let ExternDescriptor {
raw_arg_names,
raw_arg_types,
} = signature.arguments.generate_extern_prolog();
let func = quote! {
#[link_name = #link_name]
fn #import_name(#(#raw_arg_names: #raw_arg_types),*) #fn_return_type;
};
section_items.push(func);
}
section_items
}
#[rustfmt::skip]
fn generate_import_name(import_name: &str) -> syn::Ident {
crate::new_ident!(format!("{}_{}", super::GENERATED_WRAPPER_FUNC_PREFIX, import_name))
}
fn generate_wrapper_functions(extern_item: &ast_types::AstExternMod) -> TokenStream {
let mut token_stream = TokenStream::new();
for import in &extern_item.imports {
let signature = &import.signature;
let visibility = &signature.visibility;
let func_name = new_ident!(&signature.name);
let return_type = signature.output_type.generate_wrapper_return_type();
let import_func_name = generate_import_name(&signature.name);
let WrapperDescriptor {
arg_names,
arg_types,
raw_args,
arg_transforms,
arg_drops,
} = signature.arguments.generate_wrapper_prolog();
let return_expression =
crate::parsed_type::generate_return_expression(&signature.output_type);
let epilog = signature.output_type.generate_wrapper_epilog();
let wrapper_func = quote! {
#[cfg(target_arch = "wasm32")]
#[doc(hidden)]
#[allow(clippy::all)]
#visibility fn #func_name(#(#arg_names: #arg_types), *) #return_type {
unsafe {
#arg_transforms
#return_expression #import_func_name(#(#raw_args), *);
#arg_drops
#epilog
}
}
};
token_stream.extend(wrapper_func);
}
token_stream
}