wiggle: add support for async traits; ABI func is now generic of ctx

* ctx parameter no longer accepted by wiggle::from_witx macro.
* optional async_ parameter specifies which functions are async.
* re-export async_trait::async_trait, so users don't have to take a dep.
This commit is contained in:
Pat Hickey
2021-03-04 17:26:09 -08:00
parent a5d49c07a7
commit f11cd8e7b1
9 changed files with 260 additions and 97 deletions

View File

@@ -1,4 +1,4 @@
use crate::error_transform::ErrorTransform;
use crate::codegen_settings::CodegenSettings;
use crate::lifetimes::anon_lifetime;
use crate::module_trait::passed_by_reference;
use crate::names::Names;
@@ -12,11 +12,10 @@ pub fn define_func(
names: &Names,
module: &witx::Module,
func: &witx::InterfaceFunc,
errxform: &ErrorTransform,
settings: &CodegenSettings,
) -> TokenStream {
let rt = names.runtime_mod();
let ident = names.func(&func.name);
let ctx_type = names.ctx_type();
let (wasm_params, wasm_results) = func.wasm_signature();
let param_names = (0..wasm_params.len())
@@ -37,6 +36,7 @@ pub fn define_func(
};
let mut body = TokenStream::new();
let mut required_impls = vec![names.trait_name(&module.name)];
func.call_interface(
&module.name,
&mut Rust {
@@ -48,16 +48,22 @@ pub fn define_func(
names,
module,
funcname: func.name.as_str(),
errxform,
settings,
required_impls: &mut required_impls,
},
);
let asyncness = if settings.is_async(&module, &func) {
quote!(async)
} else {
quote!()
};
let mod_name = &module.name.as_str();
let func_name = &func.name.as_str();
quote! {
#[allow(unreachable_code)] // deals with warnings in noreturn functions
pub fn #ident(
ctx: &#ctx_type,
pub #asyncness fn #ident(
ctx: &(impl #(#required_impls)+*),
memory: &dyn #rt::GuestMemory,
#(#abi_params),*
) -> Result<#abi_ret, #rt::Trap> {
@@ -85,7 +91,16 @@ struct Rust<'a> {
names: &'a Names,
module: &'a witx::Module,
funcname: &'a str,
errxform: &'a ErrorTransform,
settings: &'a CodegenSettings,
required_impls: &'a mut Vec<Ident>,
}
impl Rust<'_> {
fn required_impl(&mut self, i: Ident) {
if !self.required_impls.contains(&i) {
self.required_impls.push(i);
}
}
}
impl witx::Bindgen for Rust<'_> {
@@ -205,8 +220,16 @@ impl witx::Bindgen for Rust<'_> {
let trait_name = self.names.trait_name(&self.module.name);
let ident = self.names.func(&func.name);
if self.settings.is_async(&self.module, &func) {
self.src.extend(quote! {
let ret = #trait_name::#ident(ctx, #(#args),*).await;
})
} else {
self.src.extend(quote! {
let ret = #trait_name::#ident(ctx, #(#args),*);
})
};
self.src.extend(quote! {
let ret = #trait_name::#ident(ctx, #(#args),*);
#rt::tracing::event!(
#rt::tracing::Level::TRACE,
result = #rt::tracing::field::debug(&ret),
@@ -226,9 +249,10 @@ impl witx::Bindgen for Rust<'_> {
// enum, and *then* we lower to an i32.
Instruction::EnumLower { ty } => {
let val = operands.pop().unwrap();
let val = match self.errxform.for_name(ty) {
let val = match self.settings.errors.for_name(ty) {
Some(custom) => {
let method = self.names.user_error_conversion_method(&custom);
self.required_impl(quote::format_ident!("UserErrorConversion"));
quote!(UserErrorConversion::#method(ctx, #val)?)
}
None => val,