Implement Wasmtime's new API as designed by RFC 11. This is quite a large commit which has had lots of discussion externally, so for more information it's best to read the RFC thread and the PR thread.
98 lines
3.3 KiB
Rust
98 lines
3.3 KiB
Rust
use proc_macro2::TokenStream;
|
|
use quote::quote;
|
|
|
|
use crate::codegen_settings::CodegenSettings;
|
|
use crate::lifetimes::{anon_lifetime, LifetimeExt};
|
|
use crate::names::Names;
|
|
use witx::Module;
|
|
|
|
pub fn passed_by_reference(ty: &witx::Type) -> bool {
|
|
match ty {
|
|
witx::Type::Pointer(_) | witx::Type::ConstPointer(_) | witx::Type::List(_) => true,
|
|
witx::Type::Record(r) => r.bitflags_repr().is_none(),
|
|
witx::Type::Variant(v) => !v.is_enum(),
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
pub fn define_module_trait(names: &Names, m: &Module, settings: &CodegenSettings) -> TokenStream {
|
|
let traitname = names.trait_name(&m.name);
|
|
let rt = names.runtime_mod();
|
|
let traitmethods = m.funcs().map(|f| {
|
|
// Check if we're returning an entity anotated with a lifetime,
|
|
// in which case, we'll need to annotate the function itself, and
|
|
// hence will need an explicit lifetime (rather than anonymous)
|
|
let (lifetime, is_anonymous) = if f
|
|
.params
|
|
.iter()
|
|
.chain(&f.results)
|
|
.any(|ret| ret.tref.needs_lifetime())
|
|
{
|
|
(quote!('a), false)
|
|
} else {
|
|
(anon_lifetime(), true)
|
|
};
|
|
let funcname = names.func(&f.name);
|
|
let args = f.params.iter().map(|arg| {
|
|
let arg_name = names.func_param(&arg.name);
|
|
let arg_typename = names.type_ref(&arg.tref, lifetime.clone());
|
|
let arg_type = if passed_by_reference(&*arg.tref.type_()) {
|
|
quote!(&#arg_typename)
|
|
} else {
|
|
quote!(#arg_typename)
|
|
};
|
|
quote!(#arg_name: #arg_type)
|
|
});
|
|
|
|
let result = match f.results.len() {
|
|
0 if f.noreturn => quote!(#rt::Trap),
|
|
0 => quote!(()),
|
|
1 => {
|
|
let (ok, err) = match &**f.results[0].tref.type_() {
|
|
witx::Type::Variant(v) => match v.as_expected() {
|
|
Some(p) => p,
|
|
None => unimplemented!("anonymous variant ref {:?}", v),
|
|
},
|
|
_ => unimplemented!(),
|
|
};
|
|
|
|
let ok = match ok {
|
|
Some(ty) => names.type_ref(ty, lifetime.clone()),
|
|
None => quote!(()),
|
|
};
|
|
let err = match err {
|
|
Some(ty) => match settings.errors.for_abi_error(ty) {
|
|
Some(custom) => {
|
|
let tn = custom.typename();
|
|
quote!(super::#tn)
|
|
}
|
|
None => names.type_ref(ty, lifetime.clone()),
|
|
},
|
|
None => quote!(()),
|
|
};
|
|
quote!(Result<#ok, #err>)
|
|
}
|
|
_ => unimplemented!(),
|
|
};
|
|
|
|
let asyncness = if settings.get_async(&m, &f).is_sync() {
|
|
quote!()
|
|
} else {
|
|
quote!(async)
|
|
};
|
|
|
|
if is_anonymous {
|
|
quote!(#asyncness fn #funcname(&mut self, #(#args),*) -> #result; )
|
|
} else {
|
|
quote!(#asyncness fn #funcname<#lifetime>(&mut self, #(#args),*) -> #result;)
|
|
}
|
|
});
|
|
|
|
quote! {
|
|
#[#rt::async_trait]
|
|
pub trait #traitname {
|
|
#(#traitmethods)*
|
|
}
|
|
}
|
|
}
|