Path: blob/main/crates/wiggle/generate/src/wasmtime.rs
1693 views
use crate::CodegenSettings;1use crate::config::Asyncness;2use crate::funcs::func_bounds;3use crate::names;4use proc_macro2::{Ident, Span, TokenStream};5use quote::{format_ident, quote};6use std::collections::HashSet;78pub fn link_module(9module: &witx::Module,10target_path: Option<&syn::Path>,11settings: &CodegenSettings,12) -> TokenStream {13let module_ident = names::module(&module.name);1415let send_bound = if settings.async_.contains_async(module) {16quote! { + Send, T: Send }17} else {18quote! {}19};2021let mut bodies = Vec::new();22let mut bounds = HashSet::new();23for f in module.funcs() {24let asyncness = settings.async_.get(module.name.as_str(), f.name.as_str());25bodies.push(generate_func(&module, &f, target_path, asyncness));26let bound = func_bounds(module, &f, settings);27for b in bound {28bounds.insert(b);29}30}3132let ctx_bound = if let Some(target_path) = target_path {33let bounds = bounds34.into_iter()35.map(|b| quote!(#target_path::#module_ident::#b));36quote!( #(#bounds)+* #send_bound )37} else {38let bounds = bounds.into_iter();39quote!( #(#bounds)+* #send_bound )40};4142let func_name = if target_path.is_none() {43format_ident!("add_to_linker")44} else {45format_ident!("add_{}_to_linker", module_ident)46};4748let u = if settings.mutable {49quote!(&mut U)50} else {51quote!(&U)52};53quote! {54/// Adds all instance items to the specified `Linker`.55pub fn #func_name<T, U>(56linker: &mut wiggle::wasmtime_crate::Linker<T>,57get_cx: impl Fn(&mut T) -> #u + Send + Sync + Copy + 'static,58) -> wiggle::anyhow::Result<()>59where60T: 'static,61U: #ctx_bound #send_bound62{63#(#bodies)*64Ok(())65}66}67}6869fn generate_func(70module: &witx::Module,71func: &witx::InterfaceFunc,72target_path: Option<&syn::Path>,73asyncness: Asyncness,74) -> TokenStream {75let module_str = module.name.as_str();76let module_ident = names::module(&module.name);7778let field_str = func.name.as_str();79let field_ident = names::func(&func.name);8081let (params, results) = func.wasm_signature();8283let arg_names = (0..params.len())84.map(|i| Ident::new(&format!("arg{i}"), Span::call_site()))85.collect::<Vec<_>>();86let arg_tys = params87.iter()88.map(|ty| names::wasm_type(*ty))89.collect::<Vec<_>>();90let arg_decls = arg_names91.iter()92.zip(arg_tys.iter())93.map(|(name, ty)| {94quote! { #name: #ty }95})96.collect::<Vec<_>>();9798let ret_ty = match results.len() {990 => quote!(()),1001 => names::wasm_type(results[0]),101_ => unimplemented!(),102};103104let await_ = if asyncness.is_sync() {105quote!()106} else {107quote!(.await)108};109110let abi_func = if let Some(target_path) = target_path {111quote!( #target_path::#module_ident::#field_ident )112} else {113quote!( #field_ident )114};115116let body = quote! {117let export = caller.get_export("memory");118let (mut mem, ctx) = match &export {119Some(wiggle::wasmtime_crate::Extern::Memory(m)) => {120let (mem, ctx) = m.data_and_store_mut(&mut caller);121let ctx = get_cx(ctx);122(wiggle::GuestMemory::Unshared(mem), ctx)123}124Some(wiggle::wasmtime_crate::Extern::SharedMemory(m)) => {125let ctx = get_cx(caller.data_mut());126(wiggle::GuestMemory::Shared(m.data()), ctx)127}128_ => wiggle::anyhow::bail!("missing required memory export"),129};130Ok(<#ret_ty>::from(#abi_func(ctx, &mut mem #(, #arg_names)*) #await_ ?))131};132133match asyncness {134Asyncness::Async => {135let arg_decls = quote! { ( #(#arg_names,)* ) : ( #(#arg_tys,)* ) };136quote! {137linker.func_wrap_async(138#module_str,139#field_str,140move |mut caller: wiggle::wasmtime_crate::Caller<'_, T>, #arg_decls| {141Box::new(async move { #body })142},143)?;144}145}146147Asyncness::Blocking { block_with } => {148quote! {149linker.func_wrap(150#module_str,151#field_str,152move |mut caller: wiggle::wasmtime_crate::Caller<'_, T> #(, #arg_decls)*| -> wiggle::anyhow::Result<#ret_ty> {153let result = async { #body };154#block_with(result)?155},156)?;157}158}159160Asyncness::Sync => {161quote! {162linker.func_wrap(163#module_str,164#field_str,165move |mut caller: wiggle::wasmtime_crate::Caller<'_, T> #(, #arg_decls)*| -> wiggle::anyhow::Result<#ret_ty> {166#body167},168)?;169}170}171}172}173174175