diff --git a/crates/wasi/src/lib.rs b/crates/wasi/src/lib.rs index 73e5481fbc..b79e56e484 100644 --- a/crates/wasi/src/lib.rs +++ b/crates/wasi/src/lib.rs @@ -9,7 +9,16 @@ pub use wasi_common::{WasiCtx, WasiCtxBuilder}; wasmtime_wiggle::define_struct_for_wiggle!({ witx: ["../wasi-common/WASI/phases/snapshot/witx/wasi_snapshot_preview1.witx"], ctx: WasiCtx, - instance: Wasi, + instance: { + 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." + } }); 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 c9783925f2..6a414ff11b 100644 --- a/crates/wiggle/wasmtime/macro/src/config.rs +++ b/crates/wiggle/wasmtime/macro/src/config.rs @@ -13,14 +13,14 @@ use { pub struct Config { pub witx: WitxConf, pub ctx: CtxConf, - pub instance_typename: InstanceTypenameConf, + pub instance: InstanceConf, } #[derive(Debug, Clone)] pub enum ConfigField { Witx(WitxConf), Ctx(CtxConf), - InstanceTypename(InstanceTypenameConf), + Instance(InstanceConf), } mod kw { @@ -28,6 +28,8 @@ mod kw { syn::custom_keyword!(witx_literal); syn::custom_keyword!(ctx); syn::custom_keyword!(instance); + syn::custom_keyword!(name); + syn::custom_keyword!(docs); } impl Parse for ConfigField { @@ -48,7 +50,7 @@ impl Parse for ConfigField { } else if lookahead.peek(kw::instance) { input.parse::()?; input.parse::()?; - Ok(ConfigField::InstanceTypename(input.parse()?)) + Ok(ConfigField::Instance(input.parse()?)) } else { Err(lookahead.error()) } @@ -59,7 +61,7 @@ impl Config { pub fn build(fields: impl Iterator, err_loc: Span) -> Result { let mut witx = None; let mut ctx = None; - let mut instance_typename = None; + let mut instance = None; for f in fields { match f { ConfigField::Witx(c) => { @@ -74,11 +76,11 @@ impl Config { } ctx = Some(c); } - ConfigField::InstanceTypename(c) => { - if instance_typename.is_some() { + ConfigField::Instance(c) => { + if instance.is_some() { return Err(Error::new(err_loc, "duplicate `instance` field")); } - instance_typename = Some(c); + instance = Some(c); } } } @@ -89,7 +91,7 @@ impl Config { ctx: ctx .take() .ok_or_else(|| Error::new(err_loc, "`ctx` field required"))?, - instance_typename: instance_typename + instance: instance .take() .ok_or_else(|| Error::new(err_loc, "`instance` field required"))?, }) @@ -115,15 +117,70 @@ impl Parse for Config { } } -#[derive(Debug, Clone)] -pub struct InstanceTypenameConf { - pub name: Ident, +enum InstanceConfField { + Name(Ident), + Docs(String), } -impl Parse for InstanceTypenameConf { +impl Parse for InstanceConfField { fn parse(input: ParseStream) -> Result { - Ok(InstanceTypenameConf { - name: input.parse()?, + let lookahead = input.lookahead1(); + if lookahead.peek(kw::name) { + input.parse::()?; + input.parse::()?; + Ok(InstanceConfField::Name(input.parse()?)) + } else if lookahead.peek(kw::docs) { + input.parse::()?; + input.parse::()?; + let docs: syn::LitStr = input.parse()?; + Ok(InstanceConfField::Docs(docs.value())) + } else { + Err(lookahead.error()) + } + } +} + +#[derive(Debug, Clone)] +pub struct InstanceConf { + pub name: Ident, + pub docs: Option, +} + +impl InstanceConf { + fn build(fields: impl Iterator, err_loc: Span) -> Result { + let mut name = None; + let mut docs = None; + for f in fields { + match f { + InstanceConfField::Name(c) => { + if name.is_some() { + return Err(Error::new(err_loc, "duplicate `name` field")); + } + name = Some(c); + } + InstanceConfField::Docs(c) => { + if docs.is_some() { + return Err(Error::new(err_loc, "duplicate `docs` field")); + } + docs = Some(c); + } + } + } + Ok(InstanceConf { + name: name + .take() + .ok_or_else(|| Error::new(err_loc, "`name` field required"))?, + docs, }) } } + +impl Parse for InstanceConf { + 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())?) + } +} diff --git a/crates/wiggle/wasmtime/macro/src/lib.rs b/crates/wiggle/wasmtime/macro/src/lib.rs index d80626f4b6..35a083e0eb 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::InstanceTypenameConf; +use config::InstanceConf; #[proc_macro] pub fn define_struct_for_wiggle(args: TokenStream) -> TokenStream { @@ -17,7 +17,7 @@ pub fn define_struct_for_wiggle(args: TokenStream) -> TokenStream { let doc = config.load_document(); let names = Names::new(&config.ctx.name, quote!(wasmtime_wiggle)); - generate(&doc, &names, &config.instance_typename).into() + generate(&doc, &names, &config.instance).into() } enum Abi { @@ -27,11 +27,7 @@ enum Abi { F64, } -fn generate( - doc: &witx::Document, - names: &Names, - instance_typename: &InstanceTypenameConf, -) -> TokenStream2 { +fn generate(doc: &witx::Document, names: &Names, instance_conf: &InstanceConf) -> TokenStream2 { let mut fields = Vec::new(); let mut get_exports = Vec::new(); let mut ctor_externs = Vec::new(); @@ -239,27 +235,31 @@ fn generate( } } - let inst_type = instance_typename.name.clone(); + let inst_type = instance_conf.name.clone(); + let inst_docs = if let Some(ref docs) = instance_conf.docs { + quote!( #[doc = #docs] ) + } else { + quote!() + }; + 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() + ); + let ctx_type = names.ctx_type(); quote! { - /// 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 [`#inst_type::get_export`] - /// can be used to do name-based resolution. + #inst_docs pub struct #inst_type { #(#fields,)* } impl #inst_type { - /// Creates a new [`#inst_type`] instance. - /// - /// External values are allocated into the `store` provided and - /// configuration of the wasi instance itself should be all - /// contained in the `cx` parameter. + #[doc = #constructor_docs] pub fn new(store: &wasmtime::Store, cx: #ctx_type) -> Self { let cx = std::rc::Rc::new(std::cell::RefCell::new(cx)); #(#ctor_externs)* @@ -281,7 +281,7 @@ fn generate( } } - /// Adds all wasi items to the specified `Linker`. + /// Adds all instance items to the specified `Linker`. pub fn add_to_linker(&self, linker: &mut wasmtime::Linker) -> anyhow::Result<()> { #(#linker_add)* Ok(())