From f66c1fbde94f03bfa54dc69d1d9f3b1e5c2ae97f Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 23 Jun 2020 17:42:04 -0700 Subject: [PATCH] reorganize configuration into modules --- crates/wasi/src/lib.rs | 27 +- crates/wiggle/wasmtime/macro/src/config.rs | 145 ++++---- crates/wiggle/wasmtime/macro/src/lib.rs | 401 ++++++++++----------- 3 files changed, 291 insertions(+), 282 deletions(-) diff --git a/crates/wasi/src/lib.rs b/crates/wasi/src/lib.rs index beb7b753ff..bfaab7b540 100644 --- a/crates/wasi/src/lib.rs +++ b/crates/wasi/src/lib.rs @@ -15,23 +15,24 @@ wasmtime_wiggle::define_wasmtime_integration!({ ctx: WasiCtx, // This macro will emit a struct to represent the instance, // with this name and docs: - instance: { - name: Wasi, - docs: "An instantiated instance of the wasi exports. + modules: { wasi_snapshot_preview1 => + { name: Wasi, + docs: "An instantiated instance of the wasi exports. -This represents a wasi module which can be used to instantiate other -wasm modules. This structure exports all that various fields of the -wasi instance as fields which can be used to implement your own -instantiation logic, if necessary. Additionally [`Wasi::get_export`] -can be used to do name-based resolution." +This represents a wasi module which can be used to instantiate other wasm +modules. This structure exports all that various fields of the wasi instance +as fields which can be used to implement your own instantiation logic, if +necessary. Additionally [`Wasi::get_export`] can be used to do name-based +resolution.", + // Don't use the wiggle generated code to implement proc_exit, we need + // to hook directly into the runtime there: + function_override: { + proc_exit => wasi_proc_exit + } + }, }, // Error to return when caller module is missing memory export: missing_memory: { wasi_common::wasi::Errno::Inval }, - // Don't use the wiggle generated code to implement proc_exit, we need to hook directly into - // the runtime there: - function_override: { - wasi_snapshot_preview1:proc_exit => wasi_proc_exit - } }); pub fn is_wasi_module(name: &str) -> bool { diff --git a/crates/wiggle/wasmtime/macro/src/config.rs b/crates/wiggle/wasmtime/macro/src/config.rs index 837a7ba4d9..8f2d9bbc0f 100644 --- a/crates/wiggle/wasmtime/macro/src/config.rs +++ b/crates/wiggle/wasmtime/macro/src/config.rs @@ -1,5 +1,6 @@ use { proc_macro2::{Span, TokenStream}, + std::collections::HashMap, syn::{ braced, parse::{Parse, ParseStream}, @@ -14,9 +15,8 @@ pub struct Config { pub target: TargetConf, pub witx: WitxConf, pub ctx: CtxConf, - pub instance: InstanceConf, + pub modules: ModulesConf, pub missing_memory: MissingMemoryConf, - pub function_override: FunctionOverrideConf, } #[derive(Debug, Clone)] @@ -24,9 +24,8 @@ pub enum ConfigField { Target(TargetConf), Witx(WitxConf), Ctx(CtxConf), - Instance(InstanceConf), + Modules(ModulesConf), MissingMemory(MissingMemoryConf), - FunctionOverride(FunctionOverrideConf), } mod kw { @@ -34,7 +33,7 @@ mod kw { syn::custom_keyword!(witx); syn::custom_keyword!(witx_literal); syn::custom_keyword!(ctx); - syn::custom_keyword!(instance); + syn::custom_keyword!(modules); syn::custom_keyword!(name); syn::custom_keyword!(docs); syn::custom_keyword!(missing_memory); @@ -60,18 +59,14 @@ impl Parse for ConfigField { input.parse::()?; input.parse::()?; Ok(ConfigField::Ctx(input.parse()?)) - } else if lookahead.peek(kw::instance) { - input.parse::()?; + } else if lookahead.peek(kw::modules) { + input.parse::()?; input.parse::()?; - Ok(ConfigField::Instance(input.parse()?)) + Ok(ConfigField::Modules(input.parse()?)) } else if lookahead.peek(kw::missing_memory) { input.parse::()?; input.parse::()?; Ok(ConfigField::MissingMemory(input.parse()?)) - } else if lookahead.peek(kw::function_override) { - input.parse::()?; - input.parse::()?; - Ok(ConfigField::FunctionOverride(input.parse()?)) } else { Err(lookahead.error()) } @@ -83,9 +78,8 @@ impl Config { let mut target = None; let mut witx = None; let mut ctx = None; - let mut instance = None; + let mut modules = None; let mut missing_memory = None; - let mut function_override = None; for f in fields { match f { ConfigField::Target(c) => { @@ -106,11 +100,11 @@ impl Config { } ctx = Some(c); } - ConfigField::Instance(c) => { - if instance.is_some() { - return Err(Error::new(err_loc, "duplicate `instance` field")); + ConfigField::Modules(c) => { + if modules.is_some() { + return Err(Error::new(err_loc, "duplicate `modules` field")); } - instance = Some(c); + modules = Some(c); } ConfigField::MissingMemory(c) => { if missing_memory.is_some() { @@ -118,31 +112,15 @@ impl Config { } missing_memory = Some(c); } - ConfigField::FunctionOverride(c) => { - if function_override.is_some() { - return Err(Error::new(err_loc, "duplicate `function_override` field")); - } - function_override = Some(c); - } } } Ok(Config { - target: target - .take() - .ok_or_else(|| Error::new(err_loc, "`target` field required"))?, - witx: witx - .take() - .ok_or_else(|| Error::new(err_loc, "`witx` field required"))?, - ctx: ctx - .take() - .ok_or_else(|| Error::new(err_loc, "`ctx` field required"))?, - instance: instance - .take() - .ok_or_else(|| Error::new(err_loc, "`instance` field required"))?, + target: target.ok_or_else(|| Error::new(err_loc, "`target` field required"))?, + witx: witx.ok_or_else(|| Error::new(err_loc, "`witx` field required"))?, + ctx: ctx.ok_or_else(|| Error::new(err_loc, "`ctx` field required"))?, + modules: modules.ok_or_else(|| Error::new(err_loc, "`modules` field required"))?, missing_memory: missing_memory - .take() .ok_or_else(|| Error::new(err_loc, "`missing_memory` field required"))?, - function_override: function_override.take().unwrap_or_default(), }) } @@ -179,23 +157,28 @@ impl Parse for TargetConf { } } -enum InstanceConfField { +enum ModuleConfField { Name(Ident), Docs(String), + FunctionOverride(FunctionOverrideConf), } -impl Parse for InstanceConfField { +impl Parse for ModuleConfField { fn parse(input: ParseStream) -> Result { let lookahead = input.lookahead1(); if lookahead.peek(kw::name) { input.parse::()?; input.parse::()?; - Ok(InstanceConfField::Name(input.parse()?)) + Ok(ModuleConfField::Name(input.parse()?)) } else if lookahead.peek(kw::docs) { input.parse::()?; input.parse::()?; let docs: syn::LitStr = input.parse()?; - Ok(InstanceConfField::Docs(docs.value())) + Ok(ModuleConfField::Docs(docs.value())) + } else if lookahead.peek(kw::function_override) { + input.parse::()?; + input.parse::()?; + Ok(ModuleConfField::FunctionOverride(input.parse()?)) } else { Err(lookahead.error()) } @@ -203,47 +186,82 @@ impl Parse for InstanceConfField { } #[derive(Debug, Clone)] -pub struct InstanceConf { +pub struct ModuleConf { pub name: Ident, pub docs: Option, + pub function_override: FunctionOverrideConf, } -impl InstanceConf { - fn build(fields: impl Iterator, err_loc: Span) -> Result { +impl ModuleConf { + fn build(fields: impl Iterator, err_loc: Span) -> Result { let mut name = None; let mut docs = None; + let mut function_override = None; for f in fields { match f { - InstanceConfField::Name(c) => { + ModuleConfField::Name(c) => { if name.is_some() { return Err(Error::new(err_loc, "duplicate `name` field")); } name = Some(c); } - InstanceConfField::Docs(c) => { + ModuleConfField::Docs(c) => { if docs.is_some() { return Err(Error::new(err_loc, "duplicate `docs` field")); } docs = Some(c); } + ModuleConfField::FunctionOverride(c) => { + if function_override.is_some() { + return Err(Error::new(err_loc, "duplicate `function_override` field")); + } + function_override = Some(c); + } } } - Ok(InstanceConf { - name: name - .take() - .ok_or_else(|| Error::new(err_loc, "`name` field required"))?, + Ok(ModuleConf { + name: name.ok_or_else(|| Error::new(err_loc, "`name` field required"))?, docs, + function_override: function_override.unwrap_or_default(), }) } } -impl Parse for InstanceConf { +impl Parse for ModuleConf { fn parse(input: ParseStream) -> Result { let contents; let _lbrace = braced!(contents in input); - let fields: Punctuated = - contents.parse_terminated(InstanceConfField::parse)?; - Ok(InstanceConf::build(fields.into_iter(), input.span())?) + let fields: Punctuated = + contents.parse_terminated(ModuleConfField::parse)?; + Ok(ModuleConf::build(fields.into_iter(), input.span())?) + } +} + +#[derive(Debug, Clone)] +pub struct ModulesConf { + pub mods: HashMap, +} + +impl ModulesConf { + pub fn iter(&self) -> impl Iterator { + self.mods.iter() + } +} + +impl Parse for ModulesConf { + fn parse(input: ParseStream) -> Result { + let contents; + let _lbrace = braced!(contents in input); + let fields: Punctuated<(String, ModuleConf), Token![,]> = + contents.parse_terminated(|i| { + let name = i.parse::()?.to_string(); + i.parse::]>()?; + let val = i.parse()?; + Ok((name, val)) + })?; + Ok(ModulesConf { + mods: fields.into_iter().collect(), + }) } } @@ -266,10 +284,10 @@ pub struct FunctionOverrideConf { pub funcs: Vec, } impl FunctionOverrideConf { - pub fn find(&self, module: &str, field: &str) -> Option<&Ident> { + pub fn find(&self, name: &str) -> Option<&Ident> { self.funcs .iter() - .find(|f| f.module == module && f.field == field) + .find(|f| f.name == name) .map(|f| &f.replacement) } } @@ -288,21 +306,14 @@ impl Parse for FunctionOverrideConf { #[derive(Debug, Clone)] pub struct FunctionOverrideField { - pub module: String, - pub field: String, + pub name: String, pub replacement: Ident, } impl Parse for FunctionOverrideField { fn parse(input: ParseStream) -> Result { - let module = input.parse::()?.to_string(); - input.parse::()?; - let field = input.parse::()?.to_string(); + let name = input.parse::()?.to_string(); input.parse::]>()?; let replacement = input.parse::()?; - Ok(FunctionOverrideField { - module, - field, - replacement, - }) + Ok(FunctionOverrideField { name, replacement }) } } diff --git a/crates/wiggle/wasmtime/macro/src/lib.rs b/crates/wiggle/wasmtime/macro/src/lib.rs index 542e166497..ddc97a8b0f 100644 --- a/crates/wiggle/wasmtime/macro/src/lib.rs +++ b/crates/wiggle/wasmtime/macro/src/lib.rs @@ -6,7 +6,7 @@ use wiggle_generate::Names; mod config; -use config::{FunctionOverrideConf, InstanceConf, MissingMemoryConf, TargetConf}; +use config::{MissingMemoryConf, ModuleConf, TargetConf}; #[proc_macro] pub fn define_wasmtime_integration(args: TokenStream) -> TokenStream { @@ -17,15 +17,19 @@ pub fn define_wasmtime_integration(args: TokenStream) -> TokenStream { let doc = config.load_document(); let names = Names::new(&config.ctx.name, quote!(wasmtime_wiggle)); - generate( - &doc, - &names, - &config.target, - &config.instance, - &config.missing_memory, - &config.function_override, - ) - .into() + let modules = config.modules.iter().map(|(name, module_conf)| { + let module = doc + .module(&witx::Id::new(name)) + .unwrap_or_else(|| panic!("witx document did not contain module named '{}'", name)); + generate_module( + &module, + &module_conf, + &names, + &config.target, + &config.missing_memory, + ) + }); + quote!( #(#modules)* ).into() } enum Abi { @@ -35,13 +39,12 @@ enum Abi { F64, } -fn generate( - doc: &witx::Document, +fn generate_module( + module: &witx::Module, + module_conf: &ModuleConf, names: &Names, target_conf: &TargetConf, - instance_conf: &InstanceConf, missing_mem_conf: &MissingMemoryConf, - func_override_conf: &FunctionOverrideConf, ) -> TokenStream2 { let mut fields = Vec::new(); let mut get_exports = Vec::new(); @@ -53,214 +56,208 @@ fn generate( let target_path = &target_conf.path; let missing_mem_err = &missing_mem_conf.err; - for module in doc.modules() { - let module_name = module.name.as_str(); - let module_id = names.module(&module.name); - for func in module.funcs() { - let name = func.name.as_str(); - let name_ident = names.func(&func.name); - fields.push(quote! { pub #name_ident: wasmtime::Func }); - get_exports.push(quote! { #name => Some(&self.#name_ident) }); - ctor_fields.push(name_ident.clone()); - linker_add.push(quote! { - linker.define(#module_name, #name, self.#name_ident.clone())?; - }); - - if let Some(func_override) = func_override_conf.find(module_name, name) { - ctor_externs.push(quote! { - let #name_ident = wasmtime::Func::wrap(store, #func_override); - }); - continue; - } - - let mut shim_arg_decls = Vec::new(); - let mut params = Vec::new(); - let mut hostcall_args = Vec::new(); - - for param in func.params.iter() { - let name = names.func_param(¶m.name); - - // Registers a new parameter to the shim we're making with the - // given `name`, the `abi_ty` wasm type - // - // This will register a whole bunch of things: - // - // * The cranelift type for the parameter - // * Syntax to specify the actual function parameter - // * How to actually pass this argument to the host - // implementation, converting as necessary. - let mut add_param = |name: &Ident, abi_ty: Abi| { - match abi_ty { - Abi::I32 => { - params.push(quote! { types::I32 }); - shim_arg_decls.push(quote! { #name: i32 }); - } - Abi::I64 => { - params.push(quote! { types::I64 }); - shim_arg_decls.push(quote! { #name: i64 }); - } - Abi::F32 => { - params.push(quote! { types::F32 }); - shim_arg_decls.push(quote! { #name: f32 }); - } - Abi::F64 => { - params.push(quote! { types::F64 }); - shim_arg_decls.push(quote! { #name: f64 }); - } - } - hostcall_args.push(quote! { #name as _ }); - }; - - match &*param.tref.type_() { - witx::Type::Int(e) => match e.repr { - witx::IntRepr::U64 => add_param(&name, Abi::I64), - _ => add_param(&name, Abi::I32), - }, - - witx::Type::Enum(e) => match e.repr { - witx::IntRepr::U64 => add_param(&name, Abi::I64), - _ => add_param(&name, Abi::I32), - }, - - witx::Type::Flags(f) => match f.repr { - witx::IntRepr::U64 => add_param(&name, Abi::I64), - _ => add_param(&name, Abi::I32), - }, - - witx::Type::Builtin(witx::BuiltinType::Char8) - | witx::Type::Builtin(witx::BuiltinType::S8) - | witx::Type::Builtin(witx::BuiltinType::U8) - | witx::Type::Builtin(witx::BuiltinType::S16) - | witx::Type::Builtin(witx::BuiltinType::U16) - | witx::Type::Builtin(witx::BuiltinType::S32) - | witx::Type::Builtin(witx::BuiltinType::U32) - | witx::Type::Builtin(witx::BuiltinType::USize) => { - add_param(&name, Abi::I32); - } - - witx::Type::Builtin(witx::BuiltinType::S64) - | witx::Type::Builtin(witx::BuiltinType::U64) => { - add_param(&name, Abi::I64); - } - - witx::Type::Builtin(witx::BuiltinType::F32) => { - add_param(&name, Abi::F32); - } - - witx::Type::Builtin(witx::BuiltinType::F64) => { - add_param(&name, Abi::F64); - } - - // strings/arrays have an extra ABI parameter for the length - // of the array passed. - witx::Type::Builtin(witx::BuiltinType::String) | witx::Type::Array(_) => { - add_param(&name, Abi::I32); - let len = format_ident!("{}_len", name); - add_param(&len, Abi::I32); - } - - witx::Type::ConstPointer(_) - | witx::Type::Handle(_) - | witx::Type::Pointer(_) => { - add_param(&name, Abi::I32); - } - - witx::Type::Struct(_) | witx::Type::Union(_) => { - panic!("unsupported argument type") - } - } - } - - let mut results = func.results.iter(); - let mut ret_ty = quote! { () }; - let mut cvt_ret = quote! {}; - let mut returns = Vec::new(); - let mut handle_early_error = quote! { panic!("error: {:?}", e) }; - - // The first result is returned bare right now... - if let Some(ret) = results.next() { - handle_early_error = quote! { return e.into() }; - match &*ret.tref.type_() { - // Eventually we'll want to add support for more returned - // types, but for now let's just conform to what `*.witx` - // definitions currently use. - witx::Type::Enum(e) => match e.repr { - witx::IntRepr::U16 => { - returns.push(quote! { types::I32 }); - ret_ty = quote! { i32 }; - cvt_ret = quote! { .into() } - } - other => panic!("unsupported ret enum repr {:?}", other), - }, - other => panic!("unsupported first return {:?}", other), - } - } - - // ... and all remaining results are returned via out-poiners - for result in results { - let name = format_ident!("{}", result.name.as_str()); - params.push(quote! { types::I32 }); - shim_arg_decls.push(quote! { #name: i32 }); - hostcall_args.push(quote! { #name }); - } + let module_name = module.name.as_str(); + let module_id = names.module(&module.name); + for func in module.funcs() { + let func_name = func.name.as_str(); + let name_ident = names.func(&func.name); + fields.push(quote! { pub #name_ident: wasmtime::Func }); + get_exports.push(quote! { #func_name => Some(&self.#name_ident) }); + ctor_fields.push(name_ident.clone()); + linker_add.push(quote! { + linker.define(#module_name, #func_name, self.#name_ident.clone())?; + }); + if let Some(func_override) = module_conf.function_override.find(func_name) { ctor_externs.push(quote! { - let my_cx = cx.clone(); - let #name_ident = wasmtime::Func::wrap( - store, - move |caller: wasmtime::Caller<'_> #(,#shim_arg_decls)*| -> #ret_ty { - unsafe { - let mem = match caller.get_export("memory") { - Some(wasmtime::Extern::Memory(m)) => m, - _ => { - log::warn!("callee does not export a memory as \"memory\""); - let e = { #missing_mem_err }; - #handle_early_error - } - }; - // Wiggle does not expose any methods for - // functions to re-enter the WebAssembly module, - // or expose the memory via non-wiggle mechanisms. - // Therefore, creating a new BorrowChecker at the - // root of each function invocation is correct. - let bc = #runtime::BorrowChecker::new(); - let mem = #runtime::WasmtimeGuestMemory::new( mem, bc ); - #target_path::#module_id::#name_ident( - &mut my_cx.borrow_mut(), - &mem, - #(#hostcall_args),* - ) #cvt_ret - } - } - ); + let #name_ident = wasmtime::Func::wrap(store, #func_override); }); + continue; } + + let mut shim_arg_decls = Vec::new(); + let mut params = Vec::new(); + let mut hostcall_args = Vec::new(); + + for param in func.params.iter() { + let name = names.func_param(¶m.name); + + // Registers a new parameter to the shim we're making with the + // given `name`, the `abi_ty` wasm type + // + // This will register a whole bunch of things: + // + // * The cranelift type for the parameter + // * Syntax to specify the actual function parameter + // * How to actually pass this argument to the host + // implementation, converting as necessary. + let mut add_param = |name: &Ident, abi_ty: Abi| { + match abi_ty { + Abi::I32 => { + params.push(quote! { types::I32 }); + shim_arg_decls.push(quote! { #name: i32 }); + } + Abi::I64 => { + params.push(quote! { types::I64 }); + shim_arg_decls.push(quote! { #name: i64 }); + } + Abi::F32 => { + params.push(quote! { types::F32 }); + shim_arg_decls.push(quote! { #name: f32 }); + } + Abi::F64 => { + params.push(quote! { types::F64 }); + shim_arg_decls.push(quote! { #name: f64 }); + } + } + hostcall_args.push(quote! { #name as _ }); + }; + + match &*param.tref.type_() { + witx::Type::Int(e) => match e.repr { + witx::IntRepr::U64 => add_param(&name, Abi::I64), + _ => add_param(&name, Abi::I32), + }, + + witx::Type::Enum(e) => match e.repr { + witx::IntRepr::U64 => add_param(&name, Abi::I64), + _ => add_param(&name, Abi::I32), + }, + + witx::Type::Flags(f) => match f.repr { + witx::IntRepr::U64 => add_param(&name, Abi::I64), + _ => add_param(&name, Abi::I32), + }, + + witx::Type::Builtin(witx::BuiltinType::Char8) + | witx::Type::Builtin(witx::BuiltinType::S8) + | witx::Type::Builtin(witx::BuiltinType::U8) + | witx::Type::Builtin(witx::BuiltinType::S16) + | witx::Type::Builtin(witx::BuiltinType::U16) + | witx::Type::Builtin(witx::BuiltinType::S32) + | witx::Type::Builtin(witx::BuiltinType::U32) + | witx::Type::Builtin(witx::BuiltinType::USize) => { + add_param(&name, Abi::I32); + } + + witx::Type::Builtin(witx::BuiltinType::S64) + | witx::Type::Builtin(witx::BuiltinType::U64) => { + add_param(&name, Abi::I64); + } + + witx::Type::Builtin(witx::BuiltinType::F32) => { + add_param(&name, Abi::F32); + } + + witx::Type::Builtin(witx::BuiltinType::F64) => { + add_param(&name, Abi::F64); + } + + // strings/arrays have an extra ABI parameter for the length + // of the array passed. + witx::Type::Builtin(witx::BuiltinType::String) | witx::Type::Array(_) => { + add_param(&name, Abi::I32); + let len = format_ident!("{}_len", name); + add_param(&len, Abi::I32); + } + + witx::Type::ConstPointer(_) | witx::Type::Handle(_) | witx::Type::Pointer(_) => { + add_param(&name, Abi::I32); + } + + witx::Type::Struct(_) | witx::Type::Union(_) => panic!("unsupported argument type"), + } + } + + let mut results = func.results.iter(); + let mut ret_ty = quote! { () }; + let mut cvt_ret = quote! {}; + let mut returns = Vec::new(); + let mut handle_early_error = quote! { panic!("error: {:?}", e) }; + + // The first result is returned bare right now... + if let Some(ret) = results.next() { + handle_early_error = quote! { return e.into() }; + match &*ret.tref.type_() { + // Eventually we'll want to add support for more returned + // types, but for now let's just conform to what `*.witx` + // definitions currently use. + witx::Type::Enum(e) => match e.repr { + witx::IntRepr::U16 => { + returns.push(quote! { types::I32 }); + ret_ty = quote! { i32 }; + cvt_ret = quote! { .into() } + } + other => panic!("unsupported ret enum repr {:?}", other), + }, + other => panic!("unsupported first return {:?}", other), + } + } + + // ... and all remaining results are returned via out-poiners + for result in results { + let name = format_ident!("{}", result.name.as_str()); + params.push(quote! { types::I32 }); + shim_arg_decls.push(quote! { #name: i32 }); + hostcall_args.push(quote! { #name }); + } + + ctor_externs.push(quote! { + let my_cx = cx.clone(); + let #name_ident = wasmtime::Func::wrap( + store, + move |caller: wasmtime::Caller<'_> #(,#shim_arg_decls)*| -> #ret_ty { + unsafe { + let mem = match caller.get_export("memory") { + Some(wasmtime::Extern::Memory(m)) => m, + _ => { + log::warn!("callee does not export a memory as \"memory\""); + let e = { #missing_mem_err }; + #handle_early_error + } + }; + // Wiggle does not expose any methods for + // functions to re-enter the WebAssembly module, + // or expose the memory via non-wiggle mechanisms. + // Therefore, creating a new BorrowChecker at the + // root of each function invocation is correct. + let bc = #runtime::BorrowChecker::new(); + let mem = #runtime::WasmtimeGuestMemory::new( mem, bc ); + #target_path::#module_id::#name_ident( + &mut my_cx.borrow_mut(), + &mem, + #(#hostcall_args),* + ) #cvt_ret + } + } + ); + }); } - let inst_type = instance_conf.name.clone(); - let inst_docs = if let Some(ref docs) = instance_conf.docs { - quote!( #[doc = #docs] ) - } else { - quote!() - }; + let type_name = module_conf.name.clone(); + let type_docs = module_conf + .docs + .as_ref() + .map(|docs| quote!( #[doc = #docs] )) + .unwrap_or_default(); let constructor_docs = format!( "Creates a new [`{}`] instance. External values are allocated into the `store` provided and configuration of the wasi instance itself should be all contained in the `cx` parameter.", - instance_conf.name.to_string() + module_conf.name.to_string() ); let ctx_type = names.ctx_type(); quote! { - #inst_docs - pub struct #inst_type { + #type_docs + pub struct #type_name { #(#fields,)* } - impl #inst_type { + impl #type_name { #[doc = #constructor_docs] pub fn new(store: &wasmtime::Store, cx: #ctx_type) -> Self { let cx = std::rc::Rc::new(std::cell::RefCell::new(cx));