Path: blob/main/crates/wit-bindgen/src/lib.rs
3054 views
//! > **⚠️ Warning ⚠️**: this crate is an internal-only crate for the Wasmtime1//! > project and is not intended for general use. APIs are not strictly2//! > reviewed for safety and usage outside of Wasmtime may have bugs. If3//! > you're interested in using this feel free to file an issue on the4//! > Wasmtime repository to start a discussion about doing so, but otherwise5//! > be aware that your usage of this crate is not supported.67use crate::rust::{RustGenerator, TypeMode, to_rust_ident, to_rust_upper_camel_case};8use crate::types::{TypeInfo, Types};9use anyhow::bail;10use heck::*;11use indexmap::{IndexMap, IndexSet};12use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};13use std::fmt::Write as _;14use std::io::{Read, Write};15use std::mem;16use std::process::{Command, Stdio};17use wit_parser::*;1819macro_rules! uwrite {20($dst:expr, $($arg:tt)*) => {21write!($dst, $($arg)*).unwrap()22};23}2425macro_rules! uwriteln {26($dst:expr, $($arg:tt)*) => {27writeln!($dst, $($arg)*).unwrap()28};29}3031mod config;32mod rust;33mod source;34mod types;3536pub use config::{FunctionConfig, FunctionFilter, FunctionFlags};37use source::Source;3839#[derive(Clone)]40enum InterfaceName {41/// This interface was remapped using `with` to some other Rust code.42Remapped {43/// This is the `::`-separated string which is the path to the mapped44/// item relative to the root of the `bindgen!` macro invocation.45///46/// This path currently starts with `__with_name$N` and will then47/// optionally have `::` projections through to the actual item48/// depending on how `with` was configured.49name_at_root: String,5051/// This is currently only used for exports and is the relative path to52/// where this mapped name would be located if `with` were not53/// specified. Basically it's the same as the `Path` variant of this54/// enum if the mapping weren't present.55local_path: Vec<String>,56},5758/// This interface is generated in the module hierarchy specified.59///60/// The path listed here is the path, from the root of the `bindgen!` macro,61/// to where this interface is generated.62Path(Vec<String>),63}6465#[derive(Default)]66struct Wasmtime {67src: Source,68opts: Opts,69/// A list of all interfaces which were imported by this world.70import_interfaces: Vec<ImportInterface>,71import_functions: Vec<Function>,72exports: Exports,73types: Types,74sizes: SizeAlign,75interface_names: HashMap<InterfaceId, InterfaceName>,76interface_last_seen_as_import: HashMap<InterfaceId, bool>,77trappable_errors: IndexMap<TypeId, String>,78// Track the with options that were used. Remapped interfaces provided via `with`79// are required to be used.80used_with_opts: HashSet<String>,81world_link_options: LinkOptionsBuilder,82interface_link_options: HashMap<InterfaceId, LinkOptionsBuilder>,83}8485struct ImportInterface {86id: InterfaceId,87contents: String,88name: InterfaceName,89all_func_flags: FunctionFlags,90}9192#[derive(Default)]93struct Exports {94fields: BTreeMap<String, ExportField>,95modules: Vec<(InterfaceId, String, InterfaceName)>,96funcs: Vec<String>,97}9899struct ExportField {100ty: String,101ty_index: String,102load: String,103get_index: String,104}105106#[derive(Default, Debug, Clone, Copy)]107pub enum Ownership {108/// Generated types will be composed entirely of owning fields, regardless109/// of whether they are used as parameters to guest exports or not.110#[default]111Owning,112113/// Generated types used as parameters to guest exports will be "deeply114/// borrowing", i.e. contain references rather than owned values when115/// applicable.116Borrowing {117/// Whether or not to generate "duplicate" type definitions for a single118/// WIT type if necessary, for example if it's used as both an import119/// and an export, or if it's used both as a parameter to an export and120/// a return value from an export.121duplicate_if_necessary: bool,122},123}124125#[derive(Default, Debug, Clone)]126pub struct Opts {127/// Whether or not `rustfmt` is executed to format generated code.128pub rustfmt: bool,129130/// A list of "trappable errors" which are used to replace the `E` in131/// `result<T, E>` found in WIT.132pub trappable_error_type: Vec<TrappableError>,133134/// Whether to generate owning or borrowing type definitions.135pub ownership: Ownership,136137/// Whether or not to generate code for only the interfaces of this wit file or not.138pub only_interfaces: bool,139140/// Remapping of interface names to rust module names.141/// TODO: is there a better type to use for the value of this map?142pub with: HashMap<String, String>,143144/// Additional derive attributes to add to generated types. If using in a CLI, this flag can be145/// specified multiple times to add multiple attributes.146///147/// These derive attributes will be added to any generated structs or enums148pub additional_derive_attributes: Vec<String>,149150/// Evaluate to a string literal containing the generated code rather than the generated tokens151/// themselves. Mostly useful for Wasmtime internal debugging and development.152pub stringify: bool,153154/// Temporary option to skip `impl<T: Trait> Trait for &mut T` for the155/// `wasmtime-wasi` crate while that's given a chance to update its b156/// indings.157pub skip_mut_forwarding_impls: bool,158159/// Indicates that the `T` in `Store<T>` should be send even if async is not160/// enabled.161///162/// This is helpful when sync bindings depend on generated functions from163/// async bindings as is the case with WASI in-tree.164pub require_store_data_send: bool,165166/// Path to the `wasmtime` crate if it's not the default path.167pub wasmtime_crate: Option<String>,168169/// Whether to use `anyhow::Result` for trappable host-defined function170/// imports.171///172/// By default, `wasmtime::Result` is used instead of `anyhow::Result`.173///174/// When enabled, the generated code requires the `"anyhow"` cargo feature175/// to also be enabled in the `wasmtime` crate.176pub anyhow: bool,177178/// If true, write the generated bindings to a file for better error179/// messages from `rustc`.180///181/// This can also be toggled via the `WASMTIME_DEBUG_BINDGEN` environment182/// variable, but that will affect _all_ `bindgen!` macro invocations (and183/// can sometimes lead to one invocation overwriting another in unpredictable184/// ways), whereas this option lets you specify it on a case-by-case basis.185pub debug: bool,186187/// TODO188pub imports: FunctionConfig,189/// TODO190pub exports: FunctionConfig,191}192193#[derive(Debug, Clone)]194pub struct TrappableError {195/// Full path to the error, such as `wasi:io/streams.error`.196pub wit_path: String,197198/// The name, in Rust, of the error type to generate.199pub rust_type_name: String,200}201202impl Opts {203pub fn generate(&self, resolve: &Resolve, world: WorldId) -> anyhow::Result<String> {204// TODO: Should we refine this test to inspect only types reachable from205// the specified world?206if !cfg!(feature = "component-model-async")207&& resolve208.types209.iter()210.any(|(_, ty)| matches!(ty.kind, TypeDefKind::Future(_) | TypeDefKind::Stream(_)))211{212anyhow::bail!(213"must enable `component-model-async` feature when using WIT files \214containing future, stream, or error-context types"215);216}217218let mut r = Wasmtime::default();219r.sizes.fill(resolve);220r.opts = self.clone();221r.populate_world_and_interface_options(resolve, world);222r.generate(resolve, world)223}224}225226impl Wasmtime {227fn populate_world_and_interface_options(&mut self, resolve: &Resolve, world: WorldId) {228self.world_link_options.add_world(resolve, &world);229230for (_, import) in resolve.worlds[world].imports.iter() {231match import {232WorldItem::Interface { id, .. } => {233let mut o = LinkOptionsBuilder::default();234o.add_interface(resolve, id);235self.interface_link_options.insert(*id, o);236}237WorldItem::Function(_) | WorldItem::Type(_) => {}238}239}240}241fn name_interface(242&mut self,243resolve: &Resolve,244id: InterfaceId,245name: &WorldKey,246is_export: bool,247) -> bool {248let mut path = Vec::new();249if is_export {250path.push("exports".to_string());251}252match name {253WorldKey::Name(name) => {254path.push(name.to_snake_case());255}256WorldKey::Interface(_) => {257let iface = &resolve.interfaces[id];258let pkgname = &resolve.packages[iface.package.unwrap()].name;259path.push(pkgname.namespace.to_snake_case());260path.push(self.name_package_module(resolve, iface.package.unwrap()));261path.push(to_rust_ident(iface.name.as_ref().unwrap()));262}263}264let entry = if let Some(name_at_root) = self.lookup_replacement(resolve, name, None) {265InterfaceName::Remapped {266name_at_root,267local_path: path,268}269} else {270InterfaceName::Path(path)271};272273let remapped = matches!(entry, InterfaceName::Remapped { .. });274self.interface_names.insert(id, entry);275remapped276}277278/// If the package `id` is the only package with its namespace/name combo279/// then pass through the name unmodified. If, however, there are multiple280/// versions of this package then the package module is going to get version281/// information.282fn name_package_module(&self, resolve: &Resolve, id: PackageId) -> String {283let pkg = &resolve.packages[id];284let versions_with_same_name = resolve285.packages286.iter()287.filter_map(|(_, p)| {288if p.name.namespace == pkg.name.namespace && p.name.name == pkg.name.name {289Some(&p.name.version)290} else {291None292}293})294.collect::<Vec<_>>();295let base = pkg.name.name.to_snake_case();296if versions_with_same_name.len() == 1 {297return base;298}299300let version = match &pkg.name.version {301Some(version) => version,302// If this package didn't have a version then don't mangle its name303// and other packages with the same name but with versions present304// will have their names mangled.305None => return base,306};307308// Here there's multiple packages with the same name that differ only in309// version, so the version needs to be mangled into the Rust module name310// that we're generating. This in theory could look at all of311// `versions_with_same_name` and produce a minimal diff, e.g. for 0.1.0312// and 0.2.0 this could generate "foo1" and "foo2", but for now313// a simpler path is chosen to generate "foo0_1_0" and "foo0_2_0".314let version = version315.to_string()316.replace('.', "_")317.replace('-', "_")318.replace('+', "_")319.to_snake_case();320format!("{base}{version}")321}322323fn generate(&mut self, resolve: &Resolve, id: WorldId) -> anyhow::Result<String> {324self.types.analyze(resolve, id);325326self.world_link_options.write_struct(&mut self.src);327328// Resolve the `trappable_error_type` configuration values to `TypeId`329// values. This is done by iterating over each `trappable_error_type`330// and then locating the interface that it corresponds to as well as the331// type within that interface.332//333// Note that `LookupItem::InterfaceNoPop` is used here as the full334// hierarchical behavior of `lookup_keys` isn't used as the interface335// must be named here.336'outer: for (i, te) in self.opts.trappable_error_type.iter().enumerate() {337let error_name = format!("_TrappableError{i}");338for (id, iface) in resolve.interfaces.iter() {339for (key, projection) in lookup_keys(340resolve,341&WorldKey::Interface(id),342LookupItem::InterfaceNoPop,343) {344assert!(projection.is_empty());345346// If `wit_path` looks like `{key}.{type_name}` where347// `type_name` is a type within `iface` then we've found a348// match. Otherwise continue to the next lookup key if there349// is one, and failing that continue to the next interface.350let suffix = match te.wit_path.strip_prefix(&key) {351Some(s) => s,352None => continue,353};354let suffix = match suffix.strip_prefix('.') {355Some(s) => s,356None => continue,357};358if let Some(id) = iface.types.get(suffix) {359uwriteln!(self.src, "type {error_name} = {};", te.rust_type_name);360let prev = self.trappable_errors.insert(*id, error_name);361assert!(prev.is_none());362continue 'outer;363}364}365}366367bail!(368"failed to locate a WIT error type corresponding to the \369`trappable_error_type` name `{}` provided",370te.wit_path371)372}373374// Convert all entries in `with` as relative to the root of where the375// macro itself is invoked. This emits a `pub use` to bring the name376// into scope under an "anonymous name" which then replaces the `with`377// map entry.378let mut with = self.opts.with.iter_mut().collect::<Vec<_>>();379with.sort();380for (i, (_k, v)) in with.into_iter().enumerate() {381let name = format!("__with_name{i}");382uwriteln!(self.src, "#[doc(hidden)]\npub use {v} as {name};");383*v = name;384}385386let world = &resolve.worlds[id];387for (name, import) in world.imports.iter() {388if !self.opts.only_interfaces || matches!(import, WorldItem::Interface { .. }) {389self.import(resolve, name, import);390}391}392393for (name, export) in world.exports.iter() {394if !self.opts.only_interfaces || matches!(export, WorldItem::Interface { .. }) {395self.export(resolve, name, export);396}397}398self.finish(resolve, id)399}400401fn import(&mut self, resolve: &Resolve, name: &WorldKey, item: &WorldItem) {402let mut generator = InterfaceGenerator::new(self, resolve);403match item {404WorldItem::Function(func) => {405self.import_functions.push(func.clone());406}407WorldItem::Interface { id, .. } => {408generator409.generator410.interface_last_seen_as_import411.insert(*id, true);412generator.current_interface = Some((*id, name, false));413let snake = to_rust_ident(&match name {414WorldKey::Name(s) => s.to_snake_case(),415WorldKey::Interface(id) => resolve.interfaces[*id]416.name417.as_ref()418.unwrap()419.to_snake_case(),420});421let module = if generator422.generator423.name_interface(resolve, *id, name, false)424{425// If this interface is remapped then that means that it was426// provided via the `with` key in the bindgen configuration.427// That means that bindings generation is skipped here. To428// accommodate future bindgens depending on this bindgen429// though we still generate a module which reexports the430// original module. This helps maintain the same output431// structure regardless of whether `with` is used.432let name_at_root = match &generator.generator.interface_names[id] {433InterfaceName::Remapped { name_at_root, .. } => name_at_root,434InterfaceName::Path(_) => unreachable!(),435};436let path_to_root = generator.path_to_root();437format!(438"439pub mod {snake} {{440#[allow(unused_imports)]441pub use {path_to_root}{name_at_root}::*;442}}443"444)445} else {446// If this interface is not remapped then it's time to447// actually generate bindings here.448generator.generator.interface_link_options[id].write_struct(&mut generator.src);449generator.types(*id);450let key_name = resolve.name_world_key(name);451generator.generate_add_to_linker(*id, &key_name);452453let module = &generator.src[..];454let wt = generator.generator.wasmtime_path();455456format!(457"458#[allow(clippy::all)]459pub mod {snake} {{460#[allow(unused_imports)]461use {wt}::component::__internal::Box;462463{module}464}}465"466)467};468let all_func_flags = generator.all_func_flags;469self.import_interfaces.push(ImportInterface {470id: *id,471contents: module,472name: self.interface_names[id].clone(),473all_func_flags,474});475476let interface_path = self.import_interface_path(id);477self.interface_link_options[id]478.write_impl_from_world(&mut self.src, &interface_path);479}480WorldItem::Type(ty) => {481let name = match name {482WorldKey::Name(name) => name,483WorldKey::Interface(_) => unreachable!(),484};485generator.define_type(name, *ty);486let body = mem::take(&mut generator.src);487self.src.push_str(&body);488}489};490}491492fn export(&mut self, resolve: &Resolve, name: &WorldKey, item: &WorldItem) {493let wt = self.wasmtime_path();494let mut generator = InterfaceGenerator::new(self, resolve);495let field;496let ty;497let ty_index;498let load;499let get_index;500match item {501WorldItem::Function(func) => {502generator.define_rust_guest_export(resolve, None, func);503let body = mem::take(&mut generator.src).into();504load = generator.extract_typed_function(func).1;505assert!(generator.src.is_empty());506generator.generator.exports.funcs.push(body);507ty_index = format!("{wt}::component::ComponentExportIndex");508field = func_field_name(resolve, func);509ty = format!("{wt}::component::Func");510let sig = generator.typedfunc_sig(func, TypeMode::AllBorrowed("'_"));511let typecheck = format!(512"match item {{513{wt}::component::types::ComponentItem::ComponentFunc(func) => {{514{wt}::error::Context::context(515func.typecheck::<{sig}>(&_instance_type),516\"type-checking export func `{0}`\"517)?;518index519}}520_ => Err({wt}::format_err!(\"export `{0}` is not a function\"))?,521}}",522func.name523);524get_index = format!(525"{{ let (item, index) = _component.get_export(None, \"{}\")526.ok_or_else(|| {wt}::format_err!(\"no export `{0}` found\"))?;527{typecheck}528}}",529func.name530);531}532WorldItem::Type(_) => unreachable!(),533WorldItem::Interface { id, .. } => {534generator535.generator536.interface_last_seen_as_import537.insert(*id, false);538generator.generator.name_interface(resolve, *id, name, true);539generator.current_interface = Some((*id, name, true));540generator.types(*id);541let struct_name = "Guest";542let iface = &resolve.interfaces[*id];543let iface_name = match name {544WorldKey::Name(name) => name,545WorldKey::Interface(_) => iface.name.as_ref().unwrap(),546};547uwriteln!(generator.src, "#[derive(Clone)]");548uwriteln!(generator.src, "pub struct {struct_name} {{");549for (_, func) in iface.functions.iter() {550uwriteln!(551generator.src,552"{}: {wt}::component::Func,",553func_field_name(resolve, func)554);555}556uwriteln!(generator.src, "}}");557558uwriteln!(generator.src, "#[derive(Clone)]");559uwriteln!(generator.src, "pub struct {struct_name}Indices {{");560for (_, func) in iface.functions.iter() {561uwriteln!(562generator.src,563"{}: {wt}::component::ComponentExportIndex,",564func_field_name(resolve, func)565);566}567uwriteln!(generator.src, "}}");568569uwriteln!(generator.src, "impl {struct_name}Indices {{");570let instance_name = resolve.name_world_key(name);571uwrite!(572generator.src,573"574/// Constructor for [`{struct_name}Indices`] which takes a575/// [`Component`]({wt}::component::Component) as input and can be executed576/// before instantiation.577///578/// This constructor can be used to front-load string lookups to find exports579/// within a component.580pub fn new<_T>(581_instance_pre: &{wt}::component::InstancePre<_T>,582) -> {wt}::Result<{struct_name}Indices> {{583let instance = _instance_pre.component().get_export_index(None, \"{instance_name}\")584.ok_or_else(|| {wt}::format_err!(\"no exported instance named `{instance_name}`\"))?;585let mut lookup = move |name| {{586_instance_pre.component().get_export_index(Some(&instance), name).ok_or_else(|| {{587{wt}::format_err!(588\"instance export `{instance_name}` does \\589not have export `{{name}}`\"590)591}})592}};593let _ = &mut lookup;594"595);596let mut fields = Vec::new();597for (_, func) in iface.functions.iter() {598let name = func_field_name(resolve, func);599uwriteln!(generator.src, "let {name} = lookup(\"{}\")?;", func.name);600fields.push(name);601}602uwriteln!(generator.src, "Ok({struct_name}Indices {{");603for name in fields {604uwriteln!(generator.src, "{name},");605}606uwriteln!(generator.src, "}})");607uwriteln!(generator.src, "}}"); // end `fn _new`608609uwrite!(610generator.src,611"612pub fn load(613&self,614mut store: impl {wt}::AsContextMut,615instance: &{wt}::component::Instance,616) -> {wt}::Result<{struct_name}> {{617let _instance = instance;618let _instance_pre = _instance.instance_pre(&store);619let _instance_type = _instance_pre.instance_type();620let mut store = store.as_context_mut();621let _ = &mut store;622"623);624let mut fields = Vec::new();625for (_, func) in iface.functions.iter() {626let (name, getter) = generator.extract_typed_function(func);627uwriteln!(generator.src, "let {name} = {getter};");628fields.push(name);629}630uwriteln!(generator.src, "Ok({struct_name} {{");631for name in fields {632uwriteln!(generator.src, "{name},");633}634uwriteln!(generator.src, "}})");635uwriteln!(generator.src, "}}"); // end `fn new`636uwriteln!(generator.src, "}}"); // end `impl {struct_name}Indices`637638uwriteln!(generator.src, "impl {struct_name} {{");639let mut resource_methods = IndexMap::new();640641for (_, func) in iface.functions.iter() {642match func.kind.resource() {643None => {644generator.define_rust_guest_export(resolve, Some(name), func);645}646Some(id) => {647resource_methods.entry(id).or_insert(Vec::new()).push(func);648}649}650}651652for (id, _) in resource_methods.iter() {653let name = resolve.types[*id].name.as_ref().unwrap();654let snake = name.to_snake_case();655let camel = name.to_upper_camel_case();656uwriteln!(657generator.src,658"pub fn {snake}(&self) -> Guest{camel}<'_> {{659Guest{camel} {{ funcs: self }}660}}"661);662}663664uwriteln!(generator.src, "}}");665666for (id, methods) in resource_methods {667let resource_name = resolve.types[id].name.as_ref().unwrap();668let camel = resource_name.to_upper_camel_case();669uwriteln!(generator.src, "impl Guest{camel}<'_> {{");670for method in methods {671generator.define_rust_guest_export(resolve, Some(name), method);672}673uwriteln!(generator.src, "}}");674}675676let module = &generator.src[..];677let snake = to_rust_ident(iface_name);678679let module = format!(680"681#[allow(clippy::all)]682pub mod {snake} {{683#[allow(unused_imports)]684use {wt}::component::__internal::Box;685686{module}687}}688"689);690let pkgname = match name {691WorldKey::Name(_) => None,692WorldKey::Interface(_) => {693Some(resolve.packages[iface.package.unwrap()].name.clone())694}695};696self.exports697.modules698.push((*id, module, self.interface_names[id].clone()));699700let (path, method_name) = match pkgname {701Some(pkgname) => (702format!(703"exports::{}::{}::{snake}::{struct_name}",704pkgname.namespace.to_snake_case(),705self.name_package_module(resolve, iface.package.unwrap()),706),707format!(708"{}_{}_{snake}",709pkgname.namespace.to_snake_case(),710self.name_package_module(resolve, iface.package.unwrap())711),712),713None => (format!("exports::{snake}::{struct_name}"), snake.clone()),714};715field = format!("interface{}", self.exports.fields.len());716load = format!("self.{field}.load(&mut store, &_instance)?");717self.exports.funcs.push(format!(718"719pub fn {method_name}(&self) -> &{path} {{720&self.{field}721}}722",723));724ty_index = format!("{path}Indices");725ty = path;726get_index = format!("{ty_index}::new(_instance_pre)?");727}728}729let prev = self.exports.fields.insert(730field,731ExportField {732ty,733ty_index,734load,735get_index,736},737);738assert!(prev.is_none());739}740741fn build_world_struct(&mut self, resolve: &Resolve, world: WorldId) {742let wt = self.wasmtime_path();743let world_name = &resolve.worlds[world].name;744let camel = to_rust_upper_camel_case(&world_name);745uwriteln!(746self.src,747"748/// Auto-generated bindings for a pre-instantiated version of a749/// component which implements the world `{world_name}`.750///751/// This structure is created through [`{camel}Pre::new`] which752/// takes a [`InstancePre`]({wt}::component::InstancePre) that753/// has been created through a [`Linker`]({wt}::component::Linker).754///755/// For more information see [`{camel}`] as well.756pub struct {camel}Pre<T: 'static> {{757instance_pre: {wt}::component::InstancePre<T>,758indices: {camel}Indices,759}}760761impl<T: 'static> Clone for {camel}Pre<T> {{762fn clone(&self) -> Self {{763Self {{764instance_pre: self.instance_pre.clone(),765indices: self.indices.clone(),766}}767}}768}}769770impl<_T: 'static> {camel}Pre<_T> {{771/// Creates a new copy of `{camel}Pre` bindings which can then772/// be used to instantiate into a particular store.773///774/// This method may fail if the component behind `instance_pre`775/// does not have the required exports.776pub fn new(instance_pre: {wt}::component::InstancePre<_T>) -> {wt}::Result<Self> {{777let indices = {camel}Indices::new(&instance_pre)?;778Ok(Self {{ instance_pre, indices }})779}}780781pub fn engine(&self) -> &{wt}::Engine {{782self.instance_pre.engine()783}}784785pub fn instance_pre(&self) -> &{wt}::component::InstancePre<_T> {{786&self.instance_pre787}}788789/// Instantiates a new instance of [`{camel}`] within the790/// `store` provided.791///792/// This function will use `self` as the pre-instantiated793/// instance to perform instantiation. Afterwards the preloaded794/// indices in `self` are used to lookup all exports on the795/// resulting instance.796pub fn instantiate(797&self,798mut store: impl {wt}::AsContextMut<Data = _T>,799) -> {wt}::Result<{camel}> {{800let mut store = store.as_context_mut();801let instance = self.instance_pre.instantiate(&mut store)?;802self.indices.load(&mut store, &instance)803}}804}}805"806);807808if cfg!(feature = "async") {809uwriteln!(810self.src,811"812impl<_T: Send + 'static> {camel}Pre<_T> {{813/// Same as [`Self::instantiate`], except with `async`.814pub async fn instantiate_async(815&self,816mut store: impl {wt}::AsContextMut<Data = _T>,817) -> {wt}::Result<{camel}> {{818let mut store = store.as_context_mut();819let instance = self.instance_pre.instantiate_async(&mut store).await?;820self.indices.load(&mut store, &instance)821}}822}}823"824);825}826827uwriteln!(828self.src,829"830/// Auto-generated bindings for index of the exports of831/// `{world_name}`.832///833/// This is an implementation detail of [`{camel}Pre`] and can834/// be constructed if needed as well.835///836/// For more information see [`{camel}`] as well.837#[derive(Clone)]838pub struct {camel}Indices {{"839);840for (name, field) in self.exports.fields.iter() {841uwriteln!(self.src, "{name}: {},", field.ty_index);842}843self.src.push_str("}\n");844845uwriteln!(846self.src,847"848/// Auto-generated bindings for an instance a component which849/// implements the world `{world_name}`.850///851/// This structure can be created through a number of means852/// depending on your requirements and what you have on hand:853///854/// * The most convenient way is to use855/// [`{camel}::instantiate`] which only needs a856/// [`Store`], [`Component`], and [`Linker`].857///858/// * Alternatively you can create a [`{camel}Pre`] ahead of859/// time with a [`Component`] to front-load string lookups860/// of exports once instead of per-instantiation. This861/// method then uses [`{camel}Pre::instantiate`] to862/// create a [`{camel}`].863///864/// * If you've instantiated the instance yourself already865/// then you can use [`{camel}::new`].866///867/// These methods are all equivalent to one another and move868/// around the tradeoff of what work is performed when.869///870/// [`Store`]: {wt}::Store871/// [`Component`]: {wt}::component::Component872/// [`Linker`]: {wt}::component::Linker873pub struct {camel} {{"874);875for (name, field) in self.exports.fields.iter() {876uwriteln!(self.src, "{name}: {},", field.ty);877}878self.src.push_str("}\n");879880let world_trait = self.world_imports_trait(resolve, world);881882uwriteln!(self.src, "const _: () = {{");883884uwriteln!(885self.src,886"impl {camel}Indices {{887/// Creates a new copy of `{camel}Indices` bindings which can then888/// be used to instantiate into a particular store.889///890/// This method may fail if the component does not have the891/// required exports.892pub fn new<_T>(_instance_pre: &{wt}::component::InstancePre<_T>) -> {wt}::Result<Self> {{893let _component = _instance_pre.component();894let _instance_type = _instance_pre.instance_type();895",896);897for (name, field) in self.exports.fields.iter() {898uwriteln!(self.src, "let {name} = {};", field.get_index);899}900uwriteln!(self.src, "Ok({camel}Indices {{");901for (name, _) in self.exports.fields.iter() {902uwriteln!(self.src, "{name},");903}904uwriteln!(self.src, "}})");905uwriteln!(self.src, "}}"); // close `fn new`906907uwriteln!(908self.src,909"910/// Uses the indices stored in `self` to load an instance911/// of [`{camel}`] from the instance provided.912///913/// Note that at this time this method will additionally914/// perform type-checks of all exports.915pub fn load(916&self,917mut store: impl {wt}::AsContextMut,918instance: &{wt}::component::Instance,919) -> {wt}::Result<{camel}> {{920let _ = &mut store;921let _instance = instance;922",923);924for (name, field) in self.exports.fields.iter() {925uwriteln!(self.src, "let {name} = {};", field.load);926}927uwriteln!(self.src, "Ok({camel} {{");928for (name, _) in self.exports.fields.iter() {929uwriteln!(self.src, "{name},");930}931uwriteln!(self.src, "}})");932uwriteln!(self.src, "}}"); // close `fn load`933uwriteln!(self.src, "}}"); // close `impl {camel}Indices`934935uwriteln!(936self.src,937"impl {camel} {{938/// Convenience wrapper around [`{camel}Pre::new`] and939/// [`{camel}Pre::instantiate`].940pub fn instantiate<_T>(941store: impl {wt}::AsContextMut<Data = _T>,942component: &{wt}::component::Component,943linker: &{wt}::component::Linker<_T>,944) -> {wt}::Result<{camel}> {{945let pre = linker.instantiate_pre(component)?;946{camel}Pre::new(pre)?.instantiate(store)947}}948949/// Convenience wrapper around [`{camel}Indices::new`] and950/// [`{camel}Indices::load`].951pub fn new(952mut store: impl {wt}::AsContextMut,953instance: &{wt}::component::Instance,954) -> {wt}::Result<{camel}> {{955let indices = {camel}Indices::new(&instance.instance_pre(&store))?;956indices.load(&mut store, instance)957}}958",959);960961if cfg!(feature = "async") {962uwriteln!(963self.src,964"965/// Convenience wrapper around [`{camel}Pre::new`] and966/// [`{camel}Pre::instantiate_async`].967pub async fn instantiate_async<_T>(968store: impl {wt}::AsContextMut<Data = _T>,969component: &{wt}::component::Component,970linker: &{wt}::component::Linker<_T>,971) -> {wt}::Result<{camel}>972where _T: Send,973{{974let pre = linker.instantiate_pre(component)?;975{camel}Pre::new(pre)?.instantiate_async(store).await976}}977",978);979}980self.world_add_to_linker(resolve, world, world_trait.as_ref());981982for func in self.exports.funcs.iter() {983self.src.push_str(func);984}985986uwriteln!(self.src, "}}"); // close `impl {camel}`987988uwriteln!(self.src, "}};"); // close `const _: () = ...989}990991fn finish(&mut self, resolve: &Resolve, world: WorldId) -> anyhow::Result<String> {992let remapping_keys = self.opts.with.keys().cloned().collect::<HashSet<String>>();993994let mut unused_keys = remapping_keys995.difference(&self.used_with_opts)996.map(|s| s.as_str())997.collect::<Vec<&str>>();998999unused_keys.sort();10001001if !unused_keys.is_empty() {1002anyhow::bail!(1003"interfaces were specified in the `with` config option but are not referenced in the target world: {unused_keys:?}"1004);1005}10061007if !self.opts.only_interfaces {1008self.build_world_struct(resolve, world)1009}10101011self.opts.imports.assert_all_rules_used("imports")?;1012self.opts.exports.assert_all_rules_used("exports")?;10131014let imports = mem::take(&mut self.import_interfaces);1015self.emit_modules(1016imports1017.into_iter()1018.map(|i| (i.id, i.contents, i.name))1019.collect(),1020);10211022let exports = mem::take(&mut self.exports.modules);1023self.emit_modules(exports);10241025let mut src = mem::take(&mut self.src);1026if self.opts.rustfmt {1027let mut child = Command::new("rustfmt")1028.arg("--edition=2018")1029.stdin(Stdio::piped())1030.stdout(Stdio::piped())1031.spawn()1032.expect("failed to spawn `rustfmt`");1033child1034.stdin1035.take()1036.unwrap()1037.write_all(src.as_bytes())1038.unwrap();1039src.as_mut_string().truncate(0);1040child1041.stdout1042.take()1043.unwrap()1044.read_to_string(src.as_mut_string())1045.unwrap();1046let status = child.wait().unwrap();1047assert!(status.success());1048}10491050Ok(src.into())1051}10521053fn emit_modules(&mut self, modules: Vec<(InterfaceId, String, InterfaceName)>) {1054#[derive(Default)]1055struct Module {1056submodules: BTreeMap<String, Module>,1057contents: Vec<String>,1058}1059let mut map = Module::default();1060for (_, module, name) in modules {1061let path = match name {1062InterfaceName::Remapped { local_path, .. } => local_path,1063InterfaceName::Path(path) => path,1064};1065let mut cur = &mut map;1066for name in path[..path.len() - 1].iter() {1067cur = cur1068.submodules1069.entry(name.clone())1070.or_insert(Module::default());1071}1072cur.contents.push(module);1073}10741075emit(&mut self.src, map);10761077fn emit(me: &mut Source, module: Module) {1078for (name, submodule) in module.submodules {1079uwriteln!(me, "pub mod {name} {{");1080emit(me, submodule);1081uwriteln!(me, "}}");1082}1083for submodule in module.contents {1084uwriteln!(me, "{submodule}");1085}1086}1087}10881089/// Attempts to find the `key`, possibly with the resource projection1090/// `item`, within the `with` map provided to bindings configuration.1091fn lookup_replacement(1092&mut self,1093resolve: &Resolve,1094key: &WorldKey,1095item: Option<&str>,1096) -> Option<String> {1097let item = match item {1098Some(item) => LookupItem::Name(item),1099None => LookupItem::None,1100};11011102for (lookup, mut projection) in lookup_keys(resolve, key, item) {1103if let Some(renamed) = self.opts.with.get(&lookup) {1104projection.push(renamed.clone());1105projection.reverse();1106self.used_with_opts.insert(lookup);1107return Some(projection.join("::"));1108}1109}11101111None1112}11131114fn wasmtime_path(&self) -> String {1115self.opts1116.wasmtime_crate1117.clone()1118.unwrap_or("wasmtime".to_string())1119}1120}11211122enum LookupItem<'a> {1123None,1124Name(&'a str),1125InterfaceNoPop,1126}11271128fn lookup_keys(1129resolve: &Resolve,1130key: &WorldKey,1131item: LookupItem<'_>,1132) -> Vec<(String, Vec<String>)> {1133struct Name<'a> {1134prefix: Prefix,1135item: Option<&'a str>,1136}11371138#[derive(Copy, Clone)]1139enum Prefix {1140Namespace(PackageId),1141UnversionedPackage(PackageId),1142VersionedPackage(PackageId),1143UnversionedInterface(InterfaceId),1144VersionedInterface(InterfaceId),1145}11461147let prefix = match key {1148WorldKey::Interface(id) => Prefix::VersionedInterface(*id),11491150// Non-interface-keyed names don't get the lookup logic below,1151// they're relatively uncommon so only lookup the precise key here.1152WorldKey::Name(key) => {1153let to_lookup = match item {1154LookupItem::Name(item) => format!("{key}.{item}"),1155LookupItem::None | LookupItem::InterfaceNoPop => key.to_string(),1156};1157return vec![(to_lookup, Vec::new())];1158}1159};11601161// Here names are iteratively attempted as `key` + `item` is "walked to1162// its root" and each attempt is consulted in `self.opts.with`. This1163// loop will start at the leaf, the most specific path, and then walk to1164// the root, popping items, trying to find a result.1165//1166// Each time a name is "popped" the projection from the next path is1167// pushed onto `projection`. This means that if we actually find a match1168// then `projection` is a collection of namespaces that results in the1169// final replacement name.1170let (interface_required, item) = match item {1171LookupItem::None => (false, None),1172LookupItem::Name(s) => (false, Some(s)),1173LookupItem::InterfaceNoPop => (true, None),1174};1175let mut name = Name { prefix, item };1176let mut projection = Vec::new();1177let mut ret = Vec::new();1178loop {1179let lookup = name.lookup_key(resolve);1180ret.push((lookup, projection.clone()));1181if !name.pop(resolve, &mut projection) {1182break;1183}1184if interface_required {1185match name.prefix {1186Prefix::VersionedInterface(_) | Prefix::UnversionedInterface(_) => {}1187_ => break,1188}1189}1190}11911192return ret;11931194impl<'a> Name<'a> {1195fn lookup_key(&self, resolve: &Resolve) -> String {1196let mut s = self.prefix.lookup_key(resolve);1197if let Some(item) = self.item {1198s.push_str(".");1199s.push_str(item);1200}1201s1202}12031204fn pop(&mut self, resolve: &'a Resolve, projection: &mut Vec<String>) -> bool {1205match (self.item, self.prefix) {1206// If this is a versioned resource name, try the unversioned1207// resource name next.1208(Some(_), Prefix::VersionedInterface(id)) => {1209self.prefix = Prefix::UnversionedInterface(id);1210true1211}1212// If this is an unversioned resource name then time to1213// ignore the resource itself and move on to the next most1214// specific item, versioned interface names.1215(Some(item), Prefix::UnversionedInterface(id)) => {1216self.prefix = Prefix::VersionedInterface(id);1217self.item = None;1218projection.push(item.to_upper_camel_case());1219true1220}1221(Some(_), _) => unreachable!(),1222(None, _) => self.prefix.pop(resolve, projection),1223}1224}1225}12261227impl Prefix {1228fn lookup_key(&self, resolve: &Resolve) -> String {1229match *self {1230Prefix::Namespace(id) => resolve.packages[id].name.namespace.clone(),1231Prefix::UnversionedPackage(id) => {1232let mut name = resolve.packages[id].name.clone();1233name.version = None;1234name.to_string()1235}1236Prefix::VersionedPackage(id) => resolve.packages[id].name.to_string(),1237Prefix::UnversionedInterface(id) => {1238let id = resolve.id_of(id).unwrap();1239match id.find('@') {1240Some(i) => id[..i].to_string(),1241None => id,1242}1243}1244Prefix::VersionedInterface(id) => resolve.id_of(id).unwrap(),1245}1246}12471248fn pop(&mut self, resolve: &Resolve, projection: &mut Vec<String>) -> bool {1249*self = match *self {1250// try the unversioned interface next1251Prefix::VersionedInterface(id) => Prefix::UnversionedInterface(id),1252// try this interface's versioned package next1253Prefix::UnversionedInterface(id) => {1254let iface = &resolve.interfaces[id];1255let name = iface.name.as_ref().unwrap();1256projection.push(to_rust_ident(name));1257Prefix::VersionedPackage(iface.package.unwrap())1258}1259// try the unversioned package next1260Prefix::VersionedPackage(id) => Prefix::UnversionedPackage(id),1261// try this package's namespace next1262Prefix::UnversionedPackage(id) => {1263let name = &resolve.packages[id].name;1264projection.push(to_rust_ident(&name.name));1265Prefix::Namespace(id)1266}1267// nothing left to try any more1268Prefix::Namespace(_) => return false,1269};1270true1271}1272}1273}12741275impl Wasmtime {1276fn has_world_imports_trait(&self, resolve: &Resolve, world: WorldId) -> bool {1277!self.import_functions.is_empty() || get_world_resources(resolve, world).count() > 01278}12791280fn world_imports_trait(&mut self, resolve: &Resolve, world: WorldId) -> Option<GeneratedTrait> {1281if !self.has_world_imports_trait(resolve, world) {1282return None;1283}12841285let world_camel = to_rust_upper_camel_case(&resolve.worlds[world].name);12861287let functions = self.import_functions.clone();1288let mut generator = InterfaceGenerator::new(self, resolve);1289let generated_trait = generator.generate_trait(1290&format!("{world_camel}Imports"),1291&functions1292.iter()1293.filter(|f| f.kind.resource().is_none())1294.collect::<Vec<_>>(),1295&[],1296&get_world_resources(resolve, world).collect::<Vec<_>>(),1297);1298let src = String::from(mem::take(&mut generator.src));1299self.src.push_str(&src);1300Some(generated_trait)1301}13021303fn import_interface_paths(&self) -> Vec<(InterfaceId, String)> {1304self.import_interfaces1305.iter()1306.map(|i| {1307let path = match &i.name {1308InterfaceName::Path(path) => path.join("::"),1309InterfaceName::Remapped { name_at_root, .. } => name_at_root.clone(),1310};1311(i.id, path)1312})1313.collect()1314}13151316fn import_interface_path(&self, id: &InterfaceId) -> String {1317match &self.interface_names[id] {1318InterfaceName::Path(path) => path.join("::"),1319InterfaceName::Remapped { name_at_root, .. } => name_at_root.clone(),1320}1321}13221323fn import_interface_all_func_flags(&self, id: InterfaceId) -> FunctionFlags {1324for i in self.import_interfaces.iter() {1325if id != i.id {1326continue;1327}13281329return i.all_func_flags;1330}1331unreachable!()1332}13331334fn world_host_traits(1335&self,1336world_trait: Option<&GeneratedTrait>,1337) -> (Vec<String>, Vec<String>) {1338let mut without_store = Vec::new();1339let mut without_store_async = false;1340let mut with_store = Vec::new();1341let mut with_store_async = false;1342for (id, path) in self.import_interface_paths() {1343without_store.push(format!("{path}::Host"));1344let flags = self.import_interface_all_func_flags(id);1345without_store_async = without_store_async || flags.contains(FunctionFlags::ASYNC);13461347// Note that the requirement of `HostWithStore` is technically1348// dependent on `FunctionFlags::STORE`, but when `with` is in use we1349// don't necessarily know whether the other bindings generation1350// specified this flag or not. To handle that always assume that a1351// `HostWithStore` bound is needed.1352with_store.push(format!("{path}::HostWithStore"));1353with_store_async = with_store_async || flags.contains(FunctionFlags::ASYNC);1354}1355if let Some(world_trait) = world_trait {1356without_store.push(world_trait.name.clone());1357without_store_async =1358without_store_async || world_trait.all_func_flags.contains(FunctionFlags::ASYNC);13591360if world_trait.with_store_name.is_some() {1361with_store.extend(world_trait.with_store_name.clone());1362with_store_async =1363with_store_async || world_trait.all_func_flags.contains(FunctionFlags::ASYNC);1364}1365}1366if without_store_async {1367without_store.push("Send".to_string());1368}1369if with_store_async {1370with_store.push("Send".to_string());1371}1372(without_store, with_store)1373}13741375fn world_add_to_linker(1376&mut self,1377resolve: &Resolve,1378world: WorldId,1379world_trait: Option<&GeneratedTrait>,1380) {1381let has_world_imports_trait = self.has_world_imports_trait(resolve, world);1382if self.import_interfaces.is_empty() && !has_world_imports_trait {1383return;1384}13851386let (options_param, options_arg) = if self.world_link_options.has_any() {1387("options: &LinkOptions,", ", options")1388} else {1389("", "")1390};13911392let mut all_func_flags = FunctionFlags::empty();1393if let Some(world_trait) = world_trait {1394all_func_flags |= world_trait.all_func_flags;1395}1396for i in self.import_interfaces.iter() {1397all_func_flags |= i.all_func_flags;1398}13991400all_func_flags |= self.opts.imports.default;1401all_func_flags |= self.opts.exports.default;14021403let opt_t_send_bound =1404if all_func_flags.contains(FunctionFlags::ASYNC) || self.opts.require_store_data_send {1405"+ Send"1406} else {1407""1408};14091410let wt = self.wasmtime_path();1411if let Some(world_trait) = world_trait {1412let d_bound = match &world_trait.with_store_name {1413Some(name) => name.clone(),1414None => format!("{wt}::component::HasData"),1415};1416uwrite!(1417self.src,1418"1419pub fn add_to_linker_imports<T, D>(1420linker: &mut {wt}::component::Linker<T>,1421{options_param}1422host_getter: fn(&mut T) -> D::Data<'_>,1423) -> {wt}::Result<()>1424where1425D: {d_bound},1426for<'a> D::Data<'a>: {name},1427T: 'static {opt_t_send_bound}1428{{1429let mut linker = linker.root();1430",1431name = world_trait.name,1432);1433let gate = FeatureGate::open(&mut self.src, &resolve.worlds[world].stability);1434for (ty, _name) in get_world_resources(resolve, world) {1435self.generate_add_resource_to_linker(None, None, "linker", resolve, ty);1436}1437for f in self.import_functions.clone() {1438let mut generator = InterfaceGenerator::new(self, resolve);1439generator.generate_add_function_to_linker(TypeOwner::World(world), &f, "linker");1440let src = String::from(generator.src);1441self.src.push_str(&src);1442self.src.push_str("\n");1443}1444gate.close(&mut self.src);1445uwriteln!(self.src, "Ok(())\n}}");1446}14471448let (sync_bounds, concurrent_bounds) = self.world_host_traits(world_trait);1449let sync_bounds = sync_bounds.join(" + ");1450let concurrent_bounds = concurrent_bounds.join(" + ");1451let d_bounds = if !concurrent_bounds.is_empty() {1452concurrent_bounds1453} else {1454format!("{wt}::component::HasData")1455};14561457uwriteln!(1458self.src,1459"1460pub fn add_to_linker<T, D>(1461linker: &mut {wt}::component::Linker<T>,1462{options_param}1463host_getter: fn(&mut T) -> D::Data<'_>,1464) -> {wt}::Result<()>1465where1466D: {d_bounds},1467for<'a> D::Data<'a>: {sync_bounds},1468T: 'static {opt_t_send_bound}1469{{1470"1471);1472let gate = FeatureGate::open(&mut self.src, &resolve.worlds[world].stability);1473if has_world_imports_trait {1474uwriteln!(1475self.src,1476"Self::add_to_linker_imports::<T, D>(linker {options_arg}, host_getter)?;"1477);1478}1479for (interface_id, path) in self.import_interface_paths() {1480let options_arg = if self.interface_link_options[&interface_id].has_any() {1481", &options.into()"1482} else {1483""1484};14851486let import_stability = resolve.worlds[world]1487.imports1488.iter()1489.filter_map(|(_, i)| match i {1490WorldItem::Interface { id, stability } if *id == interface_id => {1491Some(stability.clone())1492}1493_ => None,1494})1495.next()1496.unwrap_or(Stability::Unknown);14971498let gate = FeatureGate::open(&mut self.src, &import_stability);1499uwriteln!(1500self.src,1501"{path}::add_to_linker::<T, D>(linker {options_arg}, host_getter)?;"1502);1503gate.close(&mut self.src);1504}1505gate.close(&mut self.src);1506uwriteln!(self.src, "Ok(())\n}}");1507}15081509fn generate_add_resource_to_linker(1510&mut self,1511key: Option<&WorldKey>,1512src: Option<&mut Source>,1513inst: &str,1514resolve: &Resolve,1515ty: TypeId,1516) {1517let ty = &resolve.types[ty];1518let name = ty.name.as_ref().unwrap();1519let stability = &ty.stability;1520let wt = self.wasmtime_path();1521let src = src.unwrap_or(&mut self.src);1522let gate = FeatureGate::open(src, stability);1523let camel = name.to_upper_camel_case();15241525let flags = self.opts.imports.resource_drop_flags(resolve, key, name);1526if flags.contains(FunctionFlags::ASYNC) {1527if flags.contains(FunctionFlags::STORE) {1528uwriteln!(1529src,1530"{inst}.resource_concurrent(1531\"{name}\",1532{wt}::component::ResourceType::host::<{camel}>(),1533move |caller: &{wt}::component::Accessor::<T>, rep| {{1534{wt}::component::__internal::Box::pin(async move {{1535let accessor = &caller.with_getter(host_getter);1536Host{camel}WithStore::drop(accessor, {wt}::component::Resource::new_own(rep)).await1537}})1538}},1539)?;"1540)1541} else {1542uwriteln!(1543src,1544"{inst}.resource_async(1545\"{name}\",1546{wt}::component::ResourceType::host::<{camel}>(),1547move |mut store, rep| {{1548{wt}::component::__internal::Box::new(async move {{1549Host{camel}::drop(&mut host_getter(store.data_mut()), {wt}::component::Resource::new_own(rep)).await1550}})1551}},1552)?;"1553)1554}1555} else {1556let (first_arg, trait_suffix) = if flags.contains(FunctionFlags::STORE) {1557(1558format!("{wt}::component::Access::new(store, host_getter)"),1559"WithStore",1560)1561} else {1562("&mut host_getter(store.data_mut())".to_string(), "")1563};1564uwriteln!(1565src,1566"{inst}.resource(1567\"{name}\",1568{wt}::component::ResourceType::host::<{camel}>(),1569move |mut store, rep| -> {wt}::Result<()> {{15701571let resource = {wt}::component::Resource::new_own(rep);1572Host{camel}{trait_suffix}::drop({first_arg}, resource)1573}},1574)?;",1575)1576}1577gate.close(src);1578}1579}15801581struct InterfaceGenerator<'a> {1582src: Source,1583generator: &'a mut Wasmtime,1584resolve: &'a Resolve,1585current_interface: Option<(InterfaceId, &'a WorldKey, bool)>,1586all_func_flags: FunctionFlags,1587}15881589impl<'a> InterfaceGenerator<'a> {1590fn new(generator: &'a mut Wasmtime, resolve: &'a Resolve) -> InterfaceGenerator<'a> {1591InterfaceGenerator {1592src: Source::default(),1593generator,1594resolve,1595current_interface: None,1596all_func_flags: FunctionFlags::empty(),1597}1598}15991600fn types_imported(&self) -> bool {1601match self.current_interface {1602Some((_, _, is_export)) => !is_export,1603None => true,1604}1605}16061607fn types(&mut self, id: InterfaceId) {1608for (name, id) in self.resolve.interfaces[id].types.iter() {1609self.define_type(name, *id);1610}1611}16121613fn define_type(&mut self, name: &str, id: TypeId) {1614let ty = &self.resolve.types[id];1615match &ty.kind {1616TypeDefKind::Record(record) => self.type_record(id, name, record, &ty.docs),1617TypeDefKind::Flags(flags) => self.type_flags(id, name, flags, &ty.docs),1618TypeDefKind::Tuple(tuple) => self.type_tuple(id, name, tuple, &ty.docs),1619TypeDefKind::Enum(enum_) => self.type_enum(id, name, enum_, &ty.docs),1620TypeDefKind::Variant(variant) => self.type_variant(id, name, variant, &ty.docs),1621TypeDefKind::Option(t) => self.type_option(id, name, t, &ty.docs),1622TypeDefKind::Result(r) => self.type_result(id, name, r, &ty.docs),1623TypeDefKind::List(t) => self.type_list(id, name, t, &ty.docs),1624TypeDefKind::Type(t) => self.type_alias(id, name, t, &ty.docs),1625TypeDefKind::Future(t) => self.type_future(id, name, t.as_ref(), &ty.docs),1626TypeDefKind::Stream(t) => self.type_stream(id, name, t.as_ref(), &ty.docs),1627TypeDefKind::Handle(handle) => self.type_handle(id, name, handle, &ty.docs),1628TypeDefKind::Resource => self.type_resource(id, name, ty, &ty.docs),1629TypeDefKind::Unknown => unreachable!(),1630TypeDefKind::FixedSizeList(..) => todo!(),1631TypeDefKind::Map(..) => todo!(),1632}1633}16341635fn type_handle(&mut self, id: TypeId, name: &str, handle: &Handle, docs: &Docs) {1636self.rustdoc(docs);1637let name = name.to_upper_camel_case();1638uwriteln!(self.src, "pub type {name} = ");1639self.print_handle(handle);1640self.push_str(";\n");1641self.assert_type(id, &name);1642}16431644fn type_resource(&mut self, id: TypeId, name: &str, _resource: &TypeDef, docs: &Docs) {1645let camel = name.to_upper_camel_case();1646let wt = self.generator.wasmtime_path();16471648if self.types_imported() {1649self.rustdoc(docs);16501651let replacement = match self.current_interface {1652Some((_, key, _)) => {1653self.generator1654.lookup_replacement(self.resolve, key, Some(name))1655}1656None => {1657self.generator.used_with_opts.insert(name.into());1658self.generator.opts.with.get(name).cloned()1659}1660};1661match replacement {1662Some(path) => {1663uwriteln!(1664self.src,1665"pub use {}{path} as {camel};",1666self.path_to_root()1667);1668}1669None => {1670uwriteln!(self.src, "pub enum {camel} {{}}");1671}1672}16731674// Generate resource trait16751676let functions = get_resource_functions(self.resolve, id);1677let trait_ = self.generate_trait(1678&format!("Host{camel}"),1679&functions,1680&[ExtraTraitMethod::ResourceDrop { name }],1681&[],1682);1683self.all_func_flags |= trait_.all_func_flags;1684} else {1685self.rustdoc(docs);1686uwriteln!(1687self.src,1688"1689pub type {camel} = {wt}::component::ResourceAny;16901691pub struct Guest{camel}<'a> {{1692funcs: &'a Guest,1693}}1694"1695);1696}1697}16981699fn type_record(&mut self, id: TypeId, _name: &str, record: &Record, docs: &Docs) {1700let info = self.info(id);1701let wt = self.generator.wasmtime_path();17021703// We use a BTree set to make sure we don't have any duplicates and we have a stable order1704let additional_derives: BTreeSet<String> = self1705.generator1706.opts1707.additional_derive_attributes1708.iter()1709.cloned()1710.collect();17111712for (name, mode) in self.modes_of(id) {1713let lt = self.lifetime_for(&info, mode);1714self.rustdoc(docs);17151716let mut derives = additional_derives.clone();17171718uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]");1719if lt.is_none() {1720uwriteln!(self.src, "#[derive({wt}::component::Lift)]");1721}1722uwriteln!(self.src, "#[derive({wt}::component::Lower)]");1723self.push_str("#[component(record)]\n");1724if let Some(path) = &self.generator.opts.wasmtime_crate {1725uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n");1726}17271728if info.is_copy() {1729derives.extend(["Copy", "Clone"].into_iter().map(|s| s.to_string()));1730} else if info.is_clone() {1731derives.insert("Clone".to_string());1732}17331734if !derives.is_empty() {1735self.push_str("#[derive(");1736self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", "));1737self.push_str(")]\n")1738}17391740self.push_str(&format!("pub struct {name}"));1741self.print_generics(lt);1742self.push_str(" {\n");1743for field in record.fields.iter() {1744self.rustdoc(&field.docs);1745self.push_str(&format!("#[component(name = \"{}\")]\n", field.name));1746self.push_str("pub ");1747self.push_str(&to_rust_ident(&field.name));1748self.push_str(": ");1749self.print_ty(&field.ty, mode);1750self.push_str(",\n");1751}1752self.push_str("}\n");17531754self.push_str("impl");1755self.print_generics(lt);1756self.push_str(" core::fmt::Debug for ");1757self.push_str(&name);1758self.print_generics(lt);1759self.push_str(" {\n");1760self.push_str(1761"fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n",1762);1763self.push_str(&format!("f.debug_struct(\"{name}\")"));1764for field in record.fields.iter() {1765self.push_str(&format!(1766".field(\"{}\", &self.{})",1767field.name,1768to_rust_ident(&field.name)1769));1770}1771self.push_str(".finish()\n");1772self.push_str("}\n");1773self.push_str("}\n");17741775if info.error {1776self.push_str("impl");1777self.print_generics(lt);1778self.push_str(" core::fmt::Display for ");1779self.push_str(&name);1780self.print_generics(lt);1781self.push_str(" {\n");1782self.push_str(1783"fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n",1784);1785self.push_str("write!(f, \"{:?}\", self)\n");1786self.push_str("}\n");1787self.push_str("}\n");17881789self.push_str("impl core::error::Error for ");1790self.push_str(&name);1791self.push_str("{}\n");1792}1793self.assert_type(id, &name);1794}1795}17961797fn type_tuple(&mut self, id: TypeId, _name: &str, tuple: &Tuple, docs: &Docs) {1798let info = self.info(id);1799for (name, mode) in self.modes_of(id) {1800let lt = self.lifetime_for(&info, mode);1801self.rustdoc(docs);1802self.push_str(&format!("pub type {name}"));1803self.print_generics(lt);1804self.push_str(" = (");1805for ty in tuple.types.iter() {1806self.print_ty(ty, mode);1807self.push_str(",");1808}1809self.push_str(");\n");1810self.assert_type(id, &name);1811}1812}18131814fn type_flags(&mut self, id: TypeId, name: &str, flags: &Flags, docs: &Docs) {1815self.rustdoc(docs);1816let wt = self.generator.wasmtime_path();1817let rust_name = to_rust_upper_camel_case(name);1818uwriteln!(self.src, "{wt}::component::flags!(\n");1819self.src.push_str(&format!("{rust_name} {{\n"));1820for flag in flags.flags.iter() {1821// TODO wasmtime-component-macro doesn't support docs for flags rn1822uwrite!(1823self.src,1824"#[component(name=\"{}\")] const {};\n",1825flag.name,1826flag.name.to_shouty_snake_case()1827);1828}1829self.src.push_str("}\n");1830self.src.push_str(");\n\n");1831self.assert_type(id, &rust_name);1832}18331834fn type_variant(&mut self, id: TypeId, _name: &str, variant: &Variant, docs: &Docs) {1835self.print_rust_enum(1836id,1837variant.cases.iter().map(|c| {1838(1839c.name.to_upper_camel_case(),1840Some(c.name.clone()),1841&c.docs,1842c.ty.as_ref(),1843)1844}),1845docs,1846"variant",1847);1848}18491850fn type_option(&mut self, id: TypeId, _name: &str, payload: &Type, docs: &Docs) {1851let info = self.info(id);18521853for (name, mode) in self.modes_of(id) {1854self.rustdoc(docs);1855let lt = self.lifetime_for(&info, mode);1856self.push_str(&format!("pub type {name}"));1857self.print_generics(lt);1858self.push_str("= Option<");1859self.print_ty(payload, mode);1860self.push_str(">;\n");1861self.assert_type(id, &name);1862}1863}18641865// Emit a double-check that the wit-parser-understood size of a type agrees1866// with the Wasmtime-understood size of a type.1867fn assert_type(&mut self, id: TypeId, name: &str) {1868self.push_str("const _: () = {\n");1869let wt = self.generator.wasmtime_path();1870uwriteln!(1871self.src,1872"assert!({} == <{name} as {wt}::component::ComponentType>::SIZE32);",1873self.generator.sizes.size(&Type::Id(id)).size_wasm32(),1874);1875uwriteln!(1876self.src,1877"assert!({} == <{name} as {wt}::component::ComponentType>::ALIGN32);",1878self.generator.sizes.align(&Type::Id(id)).align_wasm32(),1879);1880self.push_str("};\n");1881}18821883fn print_rust_enum<'b>(1884&mut self,1885id: TypeId,1886cases: impl IntoIterator<Item = (String, Option<String>, &'b Docs, Option<&'b Type>)> + Clone,1887docs: &Docs,1888derive_component: &str,1889) where1890Self: Sized,1891{1892let info = self.info(id);1893let wt = self.generator.wasmtime_path();18941895// We use a BTree set to make sure we don't have any duplicates and we have a stable order1896let additional_derives: BTreeSet<String> = self1897.generator1898.opts1899.additional_derive_attributes1900.iter()1901.cloned()1902.collect();19031904for (name, mode) in self.modes_of(id) {1905let name = to_rust_upper_camel_case(&name);19061907let mut derives = additional_derives.clone();19081909self.rustdoc(docs);1910let lt = self.lifetime_for(&info, mode);1911uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]");1912if lt.is_none() {1913uwriteln!(self.src, "#[derive({wt}::component::Lift)]");1914}1915uwriteln!(self.src, "#[derive({wt}::component::Lower)]");1916self.push_str(&format!("#[component({derive_component})]\n"));1917if let Some(path) = &self.generator.opts.wasmtime_crate {1918uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n");1919}1920if info.is_copy() {1921derives.extend(["Copy", "Clone"].into_iter().map(|s| s.to_string()));1922} else if info.is_clone() {1923derives.insert("Clone".to_string());1924}19251926if !derives.is_empty() {1927self.push_str("#[derive(");1928self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", "));1929self.push_str(")]\n")1930}19311932self.push_str(&format!("pub enum {name}"));1933self.print_generics(lt);1934self.push_str("{\n");1935for (case_name, component_name, docs, payload) in cases.clone() {1936self.rustdoc(docs);1937if let Some(n) = component_name {1938self.push_str(&format!("#[component(name = \"{n}\")] "));1939}1940self.push_str(&case_name);1941if let Some(ty) = payload {1942self.push_str("(");1943self.print_ty(ty, mode);1944self.push_str(")")1945}1946self.push_str(",\n");1947}1948self.push_str("}\n");19491950self.print_rust_enum_debug(1951id,1952mode,1953&name,1954cases1955.clone()1956.into_iter()1957.map(|(name, _attr, _docs, ty)| (name, ty)),1958);19591960if info.error {1961self.push_str("impl");1962self.print_generics(lt);1963self.push_str(" core::fmt::Display for ");1964self.push_str(&name);1965self.print_generics(lt);1966self.push_str(" {\n");1967self.push_str(1968"fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n",1969);1970self.push_str("write!(f, \"{:?}\", self)\n");1971self.push_str("}\n");1972self.push_str("}\n");19731974self.push_str("impl");1975self.print_generics(lt);1976self.push_str(" core::error::Error for ");1977self.push_str(&name);1978self.print_generics(lt);1979self.push_str(" {}\n");1980}19811982self.assert_type(id, &name);1983}1984}19851986fn print_rust_enum_debug<'b>(1987&mut self,1988id: TypeId,1989mode: TypeMode,1990name: &str,1991cases: impl IntoIterator<Item = (String, Option<&'b Type>)>,1992) where1993Self: Sized,1994{1995let info = self.info(id);1996let lt = self.lifetime_for(&info, mode);1997self.push_str("impl");1998self.print_generics(lt);1999self.push_str(" core::fmt::Debug for ");2000self.push_str(name);2001self.print_generics(lt);2002self.push_str(" {\n");2003self.push_str("fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n");2004self.push_str("match self {\n");2005for (case_name, payload) in cases {2006self.push_str(name);2007self.push_str("::");2008self.push_str(&case_name);2009if payload.is_some() {2010self.push_str("(e)");2011}2012self.push_str(" => {\n");2013self.push_str(&format!("f.debug_tuple(\"{name}::{case_name}\")"));2014if payload.is_some() {2015self.push_str(".field(e)");2016}2017self.push_str(".finish()\n");2018self.push_str("}\n");2019}2020self.push_str("}\n");2021self.push_str("}\n");2022self.push_str("}\n");2023}20242025fn type_result(&mut self, id: TypeId, _name: &str, result: &Result_, docs: &Docs) {2026let info = self.info(id);20272028for (name, mode) in self.modes_of(id) {2029self.rustdoc(docs);2030let lt = self.lifetime_for(&info, mode);2031self.push_str(&format!("pub type {name}"));2032self.print_generics(lt);2033self.push_str("= Result<");2034self.print_optional_ty(result.ok.as_ref(), mode);2035self.push_str(",");2036self.print_optional_ty(result.err.as_ref(), mode);2037self.push_str(">;\n");2038self.assert_type(id, &name);2039}2040}20412042fn type_enum(&mut self, id: TypeId, name: &str, enum_: &Enum, docs: &Docs) {2043let info = self.info(id);2044let wt = self.generator.wasmtime_path();20452046// We use a BTree set to make sure we don't have any duplicates and have a stable order2047let mut derives: BTreeSet<String> = self2048.generator2049.opts2050.additional_derive_attributes2051.iter()2052.cloned()2053.collect();20542055derives.extend(2056["Clone", "Copy", "PartialEq", "Eq"]2057.into_iter()2058.map(|s| s.to_string()),2059);20602061let name = to_rust_upper_camel_case(name);2062self.rustdoc(docs);2063uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]");2064uwriteln!(self.src, "#[derive({wt}::component::Lift)]");2065uwriteln!(self.src, "#[derive({wt}::component::Lower)]");2066self.push_str("#[component(enum)]\n");2067if let Some(path) = &self.generator.opts.wasmtime_crate {2068uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n");2069}20702071self.push_str("#[derive(");2072self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", "));2073self.push_str(")]\n");20742075let repr = match enum_.cases.len().ilog2() {20760..=7 => "u8",20778..=15 => "u16",2078_ => "u32",2079};2080uwriteln!(self.src, "#[repr({repr})]");20812082self.push_str(&format!("pub enum {name} {{\n"));2083for case in enum_.cases.iter() {2084self.rustdoc(&case.docs);2085self.push_str(&format!("#[component(name = \"{}\")]", case.name));2086self.push_str(&case.name.to_upper_camel_case());2087self.push_str(",\n");2088}2089self.push_str("}\n");20902091// Auto-synthesize an implementation of the standard `Error` trait for2092// error-looking types based on their name.2093if info.error {2094self.push_str("impl ");2095self.push_str(&name);2096self.push_str("{\n");20972098self.push_str("pub fn name(&self) -> &'static str {\n");2099self.push_str("match self {\n");2100for case in enum_.cases.iter() {2101self.push_str(&name);2102self.push_str("::");2103self.push_str(&case.name.to_upper_camel_case());2104self.push_str(" => \"");2105self.push_str(case.name.as_str());2106self.push_str("\",\n");2107}2108self.push_str("}\n");2109self.push_str("}\n");21102111self.push_str("pub fn message(&self) -> &'static str {\n");2112self.push_str("match self {\n");2113for case in enum_.cases.iter() {2114self.push_str(&name);2115self.push_str("::");2116self.push_str(&case.name.to_upper_camel_case());2117self.push_str(" => \"");2118if let Some(contents) = &case.docs.contents {2119self.push_str(contents.trim());2120}2121self.push_str("\",\n");2122}2123self.push_str("}\n");2124self.push_str("}\n");21252126self.push_str("}\n");21272128self.push_str("impl core::fmt::Debug for ");2129self.push_str(&name);2130self.push_str(2131"{\nfn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n",2132);2133self.push_str("f.debug_struct(\"");2134self.push_str(&name);2135self.push_str("\")\n");2136self.push_str(".field(\"code\", &(*self as i32))\n");2137self.push_str(".field(\"name\", &self.name())\n");2138self.push_str(".field(\"message\", &self.message())\n");2139self.push_str(".finish()\n");2140self.push_str("}\n");2141self.push_str("}\n");21422143self.push_str("impl core::fmt::Display for ");2144self.push_str(&name);2145self.push_str(2146"{\nfn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n",2147);2148self.push_str("write!(f, \"{} (error {})\", self.name(), *self as i32)");2149self.push_str("}\n");2150self.push_str("}\n");2151self.push_str("\n");2152self.push_str("impl core::error::Error for ");2153self.push_str(&name);2154self.push_str("{}\n");2155} else {2156self.print_rust_enum_debug(2157id,2158TypeMode::Owned,2159&name,2160enum_2161.cases2162.iter()2163.map(|c| (c.name.to_upper_camel_case(), None)),2164)2165}2166self.assert_type(id, &name);2167}21682169fn type_alias(&mut self, id: TypeId, _name: &str, ty: &Type, docs: &Docs) {2170let info = self.info(id);2171for (name, mode) in self.modes_of(id) {2172self.rustdoc(docs);2173self.push_str(&format!("pub type {name}"));2174let lt = self.lifetime_for(&info, mode);2175self.print_generics(lt);2176self.push_str(" = ");2177self.print_ty(ty, mode);2178self.push_str(";\n");2179let def_id = resolve_type_definition_id(self.resolve, id);2180if !matches!(self.resolve().types[def_id].kind, TypeDefKind::Resource) {2181self.assert_type(id, &name);2182}2183}2184}21852186fn type_list(&mut self, id: TypeId, _name: &str, ty: &Type, docs: &Docs) {2187let info = self.info(id);2188for (name, mode) in self.modes_of(id) {2189let lt = self.lifetime_for(&info, mode);2190self.rustdoc(docs);2191self.push_str(&format!("pub type {name}"));2192self.print_generics(lt);2193self.push_str(" = ");2194self.print_list(ty, mode);2195self.push_str(";\n");2196self.assert_type(id, &name);2197}2198}21992200fn type_stream(&mut self, id: TypeId, name: &str, ty: Option<&Type>, docs: &Docs) {2201self.rustdoc(docs);2202self.push_str(&format!("pub type {name}"));2203self.print_generics(None);2204self.push_str(" = ");2205self.print_stream(ty);2206self.push_str(";\n");2207self.assert_type(id, &name);2208}22092210fn type_future(&mut self, id: TypeId, name: &str, ty: Option<&Type>, docs: &Docs) {2211self.rustdoc(docs);2212self.push_str(&format!("pub type {name}"));2213self.print_generics(None);2214self.push_str(" = ");2215self.print_future(ty);2216self.push_str(";\n");2217self.assert_type(id, &name);2218}22192220fn print_result_ty(&mut self, result: Option<Type>, mode: TypeMode) {2221match result {2222Some(ty) => self.print_ty(&ty, mode),2223None => self.push_str("()"),2224}2225}22262227fn special_case_trappable_error(2228&mut self,2229func: &Function,2230) -> Option<(&'a Result_, TypeId, String)> {2231let result = func.result?;22322233// We fill in a special trappable error type in the case when a function has just one2234// result, which is itself a `result<a, e>`, and the `e` is *not* a primitive2235// (i.e. defined in std) type, and matches the typename given by the user.2236let id = match result {2237Type::Id(id) => id,2238_ => return None,2239};2240let result = match &self.resolve.types[id].kind {2241TypeDefKind::Result(r) => r,2242_ => return None,2243};2244let error_typeid = match result.err? {2245Type::Id(id) => resolve_type_definition_id(&self.resolve, id),2246_ => return None,2247};22482249let name = self.generator.trappable_errors.get(&error_typeid)?;22502251let mut path = self.path_to_root();2252uwrite!(path, "{name}");2253Some((result, error_typeid, path))2254}22552256fn generate_add_to_linker(&mut self, id: InterfaceId, name: &str) {2257let iface = &self.resolve.interfaces[id];2258let owner = TypeOwner::Interface(id);2259let wt = self.generator.wasmtime_path();22602261let mut required_conversion_traits = IndexSet::new();2262let extra_functions = {2263let mut functions = Vec::new();2264let mut errors_converted = IndexMap::new();2265let mut my_error_types = iface2266.types2267.iter()2268.filter(|(_, id)| self.generator.trappable_errors.contains_key(*id))2269.map(|(_, id)| *id)2270.collect::<Vec<_>>();2271my_error_types.extend(2272iface2273.functions2274.iter()2275.filter_map(|(_, func)| self.special_case_trappable_error(func))2276.map(|(_, id, _)| id),2277);2278for err_id in my_error_types {2279let err = &self.resolve.types[resolve_type_definition_id(self.resolve, err_id)];2280let err_name = err.name.as_ref().unwrap();2281let owner = match err.owner {2282TypeOwner::Interface(i) => i,2283_ => unimplemented!(),2284};2285match self.path_to_interface(owner) {2286Some(path) => {2287required_conversion_traits.insert(format!("{path}::Host"));2288}2289None => {2290if errors_converted.insert(err_name, err_id).is_none() {2291functions.push(ExtraTraitMethod::ErrorConvert {2292name: err_name,2293id: err_id,2294})2295}2296}2297}2298}2299functions2300};23012302// Generate the `pub trait` which represents the host functionality for2303// this import which additionally inherits from all resource traits2304// for this interface defined by `type_resource`.2305let generated_trait = self.generate_trait(2306"Host",2307&iface2308.functions2309.iter()2310.filter_map(|(_, f)| {2311if f.kind.resource().is_none() {2312Some(f)2313} else {2314None2315}2316})2317.collect::<Vec<_>>(),2318&extra_functions,2319&get_resources(self.resolve, id).collect::<Vec<_>>(),2320);23212322let opt_t_send_bound = if generated_trait2323.all_func_flags2324.contains(FunctionFlags::ASYNC)2325{2326"+ Send"2327} else {2328""2329};23302331let mut sync_bounds = "Host".to_string();23322333for ty in required_conversion_traits {2334uwrite!(sync_bounds, " + {ty}");2335}23362337let options_param = if self.generator.interface_link_options[&id].has_any() {2338"options: &LinkOptions,"2339} else {2340""2341};23422343uwriteln!(2344self.src,2345"2346pub fn add_to_linker<T, D>(2347linker: &mut {wt}::component::Linker<T>,2348{options_param}2349host_getter: fn(&mut T) -> D::Data<'_>,2350) -> {wt}::Result<()>2351where2352D: HostWithStore,2353for<'a> D::Data<'a>: {sync_bounds},2354T: 'static {opt_t_send_bound},2355{{2356"2357);23582359let gate = FeatureGate::open(&mut self.src, &iface.stability);2360uwriteln!(self.src, "let mut inst = linker.instance(\"{name}\")?;");23612362for (ty, _name) in get_resources(self.resolve, id) {2363self.generator.generate_add_resource_to_linker(2364self.current_interface.map(|p| p.1),2365Some(&mut self.src),2366"inst",2367self.resolve,2368ty,2369);2370}23712372for (_, func) in iface.functions.iter() {2373self.generate_add_function_to_linker(owner, func, "inst");2374}2375gate.close(&mut self.src);2376uwriteln!(self.src, "Ok(())");2377uwriteln!(self.src, "}}");2378}23792380fn import_resource_drop_flags(&mut self, name: &str) -> FunctionFlags {2381self.generator.opts.imports.resource_drop_flags(2382self.resolve,2383self.current_interface.map(|p| p.1),2384name,2385)2386}23872388fn generate_add_function_to_linker(&mut self, owner: TypeOwner, func: &Function, linker: &str) {2389let flags = self.generator.opts.imports.flags(2390self.resolve,2391self.current_interface.map(|p| p.1),2392func,2393);2394self.all_func_flags |= flags;2395let gate = FeatureGate::open(&mut self.src, &func.stability);2396uwrite!(2397self.src,2398"{linker}.{}(\"{}\", ",2399if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {2400"func_wrap_concurrent"2401} else if flags.contains(FunctionFlags::ASYNC) {2402"func_wrap_async"2403} else {2404"func_wrap"2405},2406func.name2407);2408self.generate_guest_import_closure(owner, func, flags);2409uwriteln!(self.src, ")?;");2410gate.close(&mut self.src);2411}24122413fn generate_guest_import_closure(2414&mut self,2415owner: TypeOwner,2416func: &Function,2417flags: FunctionFlags,2418) {2419// Generate the closure that's passed to a `Linker`, the final piece of2420// codegen here.24212422let wt = self.generator.wasmtime_path();2423if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {2424uwrite!(self.src, "move |caller: &{wt}::component::Accessor::<T>, (");2425} else {2426uwrite!(2427self.src,2428"move |mut caller: {wt}::StoreContextMut<'_, T>, ("2429);2430}2431for (i, _param) in func.params.iter().enumerate() {2432uwrite!(self.src, "arg{},", i);2433}2434self.src.push_str(") : (");24352436for (_, ty) in func.params.iter() {2437// Lift is required to be implied for this type, so we can't use2438// a borrowed type:2439self.print_ty(ty, TypeMode::Owned);2440self.src.push_str(", ");2441}2442self.src.push_str(")| {\n");24432444if flags.contains(FunctionFlags::TRACING) {2445if flags.contains(FunctionFlags::ASYNC) {2446self.src.push_str("use tracing::Instrument;\n");2447}24482449uwrite!(2450self.src,2451"2452let span = tracing::span!(2453tracing::Level::TRACE,2454\"wit-bindgen import\",2455module = \"{}\",2456function = \"{}\",2457);2458",2459match owner {2460TypeOwner::Interface(id) => self.resolve.interfaces[id]2461.name2462.as_deref()2463.unwrap_or("<no module>"),2464TypeOwner::World(id) => &self.resolve.worlds[id].name,2465TypeOwner::None => "<no owner>",2466},2467func.name,2468);2469}24702471if flags.contains(FunctionFlags::ASYNC) {2472let ctor = if flags.contains(FunctionFlags::STORE) {2473"pin"2474} else {2475"new"2476};2477uwriteln!(2478self.src,2479"{wt}::component::__internal::Box::{ctor}(async move {{"2480);2481} else {2482// Only directly enter the span if the function is sync. Otherwise2483// we use tracing::Instrument to ensure that the span is not entered2484// across an await point.2485if flags.contains(FunctionFlags::TRACING) {2486self.push_str("let _enter = span.enter();\n");2487}2488}24892490if flags.contains(FunctionFlags::TRACING) {2491let mut event_fields = func2492.params2493.iter()2494.enumerate()2495.map(|(i, (name, ty))| {2496let name = to_rust_ident(&name);2497formatting_for_arg(&name, i, *ty, &self.resolve, flags)2498})2499.collect::<Vec<String>>();2500event_fields.push(format!("\"call\""));2501uwrite!(2502self.src,2503"tracing::event!(tracing::Level::TRACE, {});\n",2504event_fields.join(", ")2505);2506}25072508if flags.contains(FunctionFlags::STORE) {2509if flags.contains(FunctionFlags::ASYNC) {2510uwriteln!(self.src, "let host = &caller.with_getter(host_getter);");2511} else {2512uwriteln!(2513self.src,2514"let access_cx = {wt}::AsContextMut::as_context_mut(&mut caller);"2515);2516uwriteln!(2517self.src,2518"let host = {wt}::component::Access::new(access_cx, host_getter);"2519);2520}2521} else {2522self.src2523.push_str("let host = &mut host_getter(caller.data_mut());\n");2524}2525let func_name = rust_function_name(func);2526let host_trait = match func.kind.resource() {2527None => match owner {2528TypeOwner::World(id) => format!(2529"{}Imports",2530rust::to_rust_upper_camel_case(&self.resolve.worlds[id].name)2531),2532_ => "Host".to_string(),2533},2534Some(id) => {2535let resource = self.resolve.types[id]2536.name2537.as_ref()2538.unwrap()2539.to_upper_camel_case();2540format!("Host{resource}")2541}2542};25432544if flags.contains(FunctionFlags::STORE) {2545uwrite!(2546self.src,2547"let r = <D as {host_trait}WithStore>::{func_name}(host, "2548);2549} else {2550uwrite!(self.src, "let r = {host_trait}::{func_name}(host, ");2551}25522553for (i, _) in func.params.iter().enumerate() {2554uwrite!(self.src, "arg{},", i);2555}25562557self.src.push_str(if flags.contains(FunctionFlags::ASYNC) {2558").await;\n"2559} else {2560");\n"2561});25622563if flags.contains(FunctionFlags::TRACING) {2564uwrite!(2565self.src,2566"tracing::event!(tracing::Level::TRACE, {}, \"return\");",2567formatting_for_results(func.result, &self.resolve, flags)2568);2569}25702571if !flags.contains(FunctionFlags::TRAPPABLE) {2572if func.result.is_some() {2573uwrite!(self.src, "Ok((r,))\n");2574} else {2575uwrite!(self.src, "Ok(r)\n");2576}2577} else if let Some((_, err, _)) = self.special_case_trappable_error(func) {2578let err = &self.resolve.types[resolve_type_definition_id(self.resolve, err)];2579let err_name = err.name.as_ref().unwrap();2580let owner = match err.owner {2581TypeOwner::Interface(i) => i,2582_ => unimplemented!(),2583};2584let convert_trait = match self.path_to_interface(owner) {2585Some(path) => format!("{path}::Host"),2586None => format!("Host"),2587};2588let convert = format!("{}::convert_{}", convert_trait, err_name.to_snake_case());2589let convert = if flags.contains(FunctionFlags::STORE) {2590if flags.contains(FunctionFlags::ASYNC) {2591format!("caller.with(|mut host| {convert}(&mut host_getter(host.get()), e))?")2592} else {2593format!("{convert}(&mut host_getter(caller.data_mut()), e)?")2594}2595} else {2596format!("{convert}(host, e)?")2597};2598uwrite!(2599self.src,2600"Ok((match r {{2601Ok(a) => Ok(a),2602Err(e) => Err({convert}),2603}},))"2604);2605} else if func.result.is_some() {2606if self.generator.opts.anyhow {2607uwrite!(2608self.src,2609"Ok(({wt}::ToWasmtimeResult::to_wasmtime_result(r)?,))\n"2610);2611} else {2612uwrite!(self.src, "Ok((r?,))\n");2613}2614} else {2615uwrite!(self.src, "r\n");2616}26172618if flags.contains(FunctionFlags::ASYNC) {2619if flags.contains(FunctionFlags::TRACING) {2620self.src.push_str("}.instrument(span))\n");2621} else {2622self.src.push_str("})\n");2623}2624}26252626self.src.push_str("}\n");2627}26282629fn generate_function_trait_sig(&mut self, func: &Function, flags: FunctionFlags) {2630let wt = self.generator.wasmtime_path();2631self.rustdoc(&func.docs);26322633self.push_str("fn ");2634self.push_str(&rust_function_name(func));2635if flags.contains(FunctionFlags::STORE | FunctionFlags::ASYNC) {2636uwrite!(2637self.src,2638"<T: Send>(accessor: &{wt}::component::Accessor<T, Self>, "2639);2640} else if flags.contains(FunctionFlags::STORE) {2641uwrite!(self.src, "<T>(host: {wt}::component::Access<T, Self>, ");2642} else {2643self.push_str("(&mut self, ");2644}2645self.generate_function_params(func);2646self.push_str(")");2647self.push_str(" -> ");26482649if flags.contains(FunctionFlags::ASYNC) {2650uwrite!(self.src, "impl ::core::future::Future<Output = ");2651}26522653self.all_func_flags |= flags;2654self.generate_function_result(func, flags);26552656if flags.contains(FunctionFlags::ASYNC) {2657self.push_str("> + Send");2658}2659}26602661fn generate_function_params(&mut self, func: &Function) {2662for (name, param) in func.params.iter() {2663let name = to_rust_ident(name);2664self.push_str(&name);2665self.push_str(": ");2666self.print_ty(param, TypeMode::Owned);2667self.push_str(",");2668}2669}26702671fn push_wasmtime_or_anyhow_result(&mut self) {2672let wt = self.generator.wasmtime_path();2673uwrite!(self.src, "{wt}::");2674if self.generator.opts.anyhow {2675self.push_str("anyhow::");2676}2677self.push_str("Result");2678}26792680fn generate_function_result(&mut self, func: &Function, flags: FunctionFlags) {2681if !flags.contains(FunctionFlags::TRAPPABLE) {2682self.print_result_ty(func.result, TypeMode::Owned);2683} else if let Some((r, _id, error_typename)) = self.special_case_trappable_error(func) {2684// Functions which have a single result `result<ok,err>` get special2685// cased to use the host_wasmtime_rust::Error<err>, making it possible2686// for them to trap or use `?` to propagate their errors2687self.push_str("Result<");2688if let Some(ok) = r.ok {2689self.print_ty(&ok, TypeMode::Owned);2690} else {2691self.push_str("()");2692}2693self.push_str(",");2694self.push_str(&error_typename);2695self.push_str(">");2696} else {2697// All other functions get their return values wrapped in an wasmtime::Result.2698// Returning the anyhow::Error case can be used to trap.2699self.push_wasmtime_or_anyhow_result();2700self.push_str("<");2701self.print_result_ty(func.result, TypeMode::Owned);2702self.push_str(">");2703}2704}27052706fn extract_typed_function(&mut self, func: &Function) -> (String, String) {2707let snake = func_field_name(self.resolve, func);2708let sig = self.typedfunc_sig(func, TypeMode::AllBorrowed("'_"));2709let extract =2710format!("*_instance.get_typed_func::<{sig}>(&mut store, &self.{snake})?.func()");2711(snake, extract)2712}27132714fn define_rust_guest_export(2715&mut self,2716resolve: &Resolve,2717ns: Option<&WorldKey>,2718func: &Function,2719) {2720let flags = self.generator.opts.exports.flags(resolve, ns, func);2721let (async_, async__, await_) = if flags.contains(FunctionFlags::ASYNC) {2722("async", "_async", ".await")2723} else {2724("", "", "")2725};27262727self.rustdoc(&func.docs);2728let wt = self.generator.wasmtime_path();27292730uwrite!(2731self.src,2732"pub {async_} fn call_{}",2733func.item_name().to_snake_case(),2734);2735if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {2736uwrite!(2737self.src,2738"<_T, _D>(&self, accessor: &{wt}::component::Accessor<_T, _D>, ",2739);2740} else {2741uwrite!(self.src, "<S: {wt}::AsContextMut>(&self, mut store: S, ",);2742}27432744let task_exit =2745flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE | FunctionFlags::TASK_EXIT);27462747let param_mode = if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {2748TypeMode::Owned2749} else {2750TypeMode::AllBorrowed("'_")2751};27522753for (i, param) in func.params.iter().enumerate() {2754uwrite!(self.src, "arg{}: ", i);2755self.print_ty(¶m.1, param_mode);2756self.push_str(",");2757}27582759uwrite!(self.src, ") -> {wt}::Result<");2760if task_exit {2761self.src.push_str("(");2762}2763self.print_result_ty(func.result, TypeMode::Owned);2764if task_exit {2765uwrite!(self.src, ", {wt}::component::TaskExit)");2766}2767uwrite!(self.src, ">");27682769if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {2770uwrite!(self.src, " where _T: Send, _D: {wt}::component::HasData");2771} else if flags.contains(FunctionFlags::ASYNC) {2772uwrite!(self.src, " where <S as {wt}::AsContext>::Data: Send");2773}2774uwrite!(self.src, "{{\n");27752776if flags.contains(FunctionFlags::TRACING) {2777if flags.contains(FunctionFlags::ASYNC) {2778self.src.push_str("use tracing::Instrument;\n");2779}27802781let ns = match ns {2782Some(key) => resolve.name_world_key(key),2783None => "default".to_string(),2784};2785self.src.push_str(&format!(2786"2787let span = tracing::span!(2788tracing::Level::TRACE,2789\"wit-bindgen export\",2790module = \"{ns}\",2791function = \"{}\",2792);2793",2794func.name,2795));27962797if !flags.contains(FunctionFlags::ASYNC) {2798self.src.push_str(2799"2800let _enter = span.enter();2801",2802);2803}2804}28052806self.src.push_str("let callee = unsafe {\n");2807uwrite!(2808self.src,2809"{wt}::component::TypedFunc::<{}>",2810self.typedfunc_sig(func, param_mode)2811);2812let projection_to_func = if func.kind.resource().is_some() {2813".funcs"2814} else {2815""2816};2817uwriteln!(2818self.src,2819"::new_unchecked(self{projection_to_func}.{})",2820func_field_name(self.resolve, func),2821);2822self.src.push_str("};\n");28232824self.src.push_str("let (");2825if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {2826self.src.push_str("(");2827}2828if func.result.is_some() {2829uwrite!(self.src, "ret0,");2830}28312832if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {2833let task_exit = if task_exit { "task_exit" } else { "_" };2834uwrite!(2835self.src,2836"), {task_exit}) = callee.call_concurrent(accessor, ("2837);2838} else {2839uwrite!(2840self.src,2841") = callee.call{async__}(store.as_context_mut(), ("2842);2843};28442845for (i, _) in func.params.iter().enumerate() {2846uwrite!(self.src, "arg{}, ", i);2847}28482849let instrument = if flags.contains(FunctionFlags::ASYNC | FunctionFlags::TRACING) {2850".instrument(span.clone())"2851} else {2852""2853};2854uwriteln!(self.src, ")){instrument}{await_}?;");28552856self.src.push_str("Ok(");2857if task_exit {2858self.src.push_str("(");2859}2860if func.result.is_some() {2861self.src.push_str("ret0");2862} else {2863self.src.push_str("()");2864}2865if task_exit {2866self.src.push_str(", task_exit)");2867}2868self.src.push_str(")\n");28692870// End function body2871self.src.push_str("}\n");2872}28732874fn rustdoc(&mut self, docs: &Docs) {2875let docs = match &docs.contents {2876Some(docs) => docs,2877None => return,2878};2879for line in docs.trim().lines() {2880self.push_str("/// ");2881self.push_str(line);2882self.push_str("\n");2883}2884}28852886fn path_to_root(&self) -> String {2887let mut path_to_root = String::new();2888if let Some((_, key, is_export)) = self.current_interface {2889match key {2890WorldKey::Name(_) => {2891path_to_root.push_str("super::");2892}2893WorldKey::Interface(_) => {2894path_to_root.push_str("super::super::super::");2895}2896}2897if is_export {2898path_to_root.push_str("super::");2899}2900}2901path_to_root2902}29032904fn partition_concurrent_funcs<'b>(2905&mut self,2906funcs: impl IntoIterator<Item = &'b Function>,2907) -> FunctionPartitioning<'b> {2908let key = self.current_interface.map(|p| p.1);2909let (with_store, without_store) = funcs2910.into_iter()2911.map(|func| {2912let flags = self.generator.opts.imports.flags(self.resolve, key, func);2913(func, flags)2914})2915.partition(|(_, flags)| flags.contains(FunctionFlags::STORE));2916FunctionPartitioning {2917with_store,2918without_store,2919}2920}29212922fn generate_trait(2923&mut self,2924trait_name: &str,2925functions: &[&Function],2926extra_functions: &[ExtraTraitMethod<'_>],2927resources: &[(TypeId, &str)],2928) -> GeneratedTrait {2929let mut ret = GeneratedTrait::default();2930let wt = self.generator.wasmtime_path();2931let partition = self.partition_concurrent_funcs(functions.iter().copied());29322933for (_, flags) in partition.with_store.iter().chain(&partition.without_store) {2934ret.all_func_flags |= *flags;2935}29362937let mut with_store_supertraits = vec![format!("{wt}::component::HasData")];2938let mut without_store_supertraits = vec![];2939for (id, name) in resources {2940let camel = name.to_upper_camel_case();2941without_store_supertraits.push(format!("Host{camel}"));2942let funcs = self.partition_concurrent_funcs(get_resource_functions(self.resolve, *id));2943for (_, flags) in funcs.with_store.iter().chain(&funcs.without_store) {2944ret.all_func_flags |= *flags;2945}2946ret.all_func_flags |= self.import_resource_drop_flags(name);2947with_store_supertraits.push(format!("Host{camel}WithStore"));2948}2949if ret.all_func_flags.contains(FunctionFlags::ASYNC) {2950with_store_supertraits.push("Send".to_string());2951without_store_supertraits.push("Send".to_string());2952}29532954uwriteln!(2955self.src,2956"pub trait {trait_name}WithStore: {} {{",2957with_store_supertraits.join(" + "),2958);2959ret.with_store_name = Some(format!("{trait_name}WithStore"));29602961let mut extra_with_store_function = false;2962for extra in extra_functions {2963match extra {2964ExtraTraitMethod::ResourceDrop { name } => {2965let flags = self.import_resource_drop_flags(name);2966if !flags.contains(FunctionFlags::STORE) {2967continue;2968}2969let camel = name.to_upper_camel_case();29702971if flags.contains(FunctionFlags::ASYNC) {2972uwrite!(2973self.src,2974"2975fn drop<T>(accessor: &{wt}::component::Accessor<T, Self>, rep: {wt}::component::Resource<{camel}>)2976-> impl ::core::future::Future<Output =2977"2978);2979self.push_wasmtime_or_anyhow_result();2980self.push_str("<()>> + Send where Self: Sized;");2981} else {2982uwrite!(2983self.src,2984"2985fn drop<T>(accessor: {wt}::component::Access<T, Self>, rep: {wt}::component::Resource<{camel}>)2986->2987"2988);2989self.push_wasmtime_or_anyhow_result();2990self.push_str("<()>;");2991}29922993extra_with_store_function = true;2994}2995ExtraTraitMethod::ErrorConvert { .. } => {}2996}2997}29982999for (func, flags) in partition.with_store.iter() {3000self.generate_function_trait_sig(func, *flags);3001self.push_str(";\n");3002}3003uwriteln!(self.src, "}}");30043005// If `*WithStore` is empty, generate a blanket impl for the trait since3006// it's otherwise not necessary to implement it manually.3007if partition.with_store.is_empty() && !extra_with_store_function {3008uwriteln!(self.src, "impl<_T: ?Sized> {trait_name}WithStore for _T");3009uwriteln!(3010self.src,3011" where _T: {}",3012with_store_supertraits.join(" + ")3013);30143015uwriteln!(self.src, "{{}}");3016}30173018uwriteln!(3019self.src,3020"pub trait {trait_name}: {} {{",3021without_store_supertraits.join(" + ")3022);3023ret.name = trait_name.to_string();3024for (func, flags) in partition.without_store.iter() {3025self.generate_function_trait_sig(func, *flags);3026self.push_str(";\n");3027}30283029for extra in extra_functions {3030match extra {3031ExtraTraitMethod::ResourceDrop { name } => {3032let flags = self.import_resource_drop_flags(name);3033ret.all_func_flags |= flags;3034if flags.contains(FunctionFlags::STORE) {3035continue;3036}3037let camel = name.to_upper_camel_case();3038uwrite!(3039self.src,3040"fn drop(&mut self, rep: {wt}::component::Resource<{camel}>) -> "3041);3042if flags.contains(FunctionFlags::ASYNC) {3043uwrite!(self.src, "impl ::core::future::Future<Output =");3044}3045self.push_wasmtime_or_anyhow_result();3046self.push_str("<()>");3047if flags.contains(FunctionFlags::ASYNC) {3048uwrite!(self.src, "> + Send");3049}3050uwrite!(self.src, ";");3051}3052ExtraTraitMethod::ErrorConvert { name, id } => {3053let root = self.path_to_root();3054let custom_name = &self.generator.trappable_errors[id];3055let snake = name.to_snake_case();3056let camel = name.to_upper_camel_case();3057uwrite!(3058self.src,3059"3060fn convert_{snake}(&mut self, err: {root}{custom_name}) ->3061"3062);3063self.push_wasmtime_or_anyhow_result();3064uwrite!(self.src, "<{camel}>;");3065}3066}3067}30683069uwriteln!(self.src, "}}");30703071if self.generator.opts.skip_mut_forwarding_impls {3072return ret;3073}30743075// Generate impl HostResource for &mut HostResource3076let maybe_send = if ret.all_func_flags.contains(FunctionFlags::ASYNC) {3077"+ Send"3078} else {3079""3080};3081uwriteln!(3082self.src,3083"impl <_T: {trait_name} + ?Sized {maybe_send}> {trait_name} for &mut _T {{"3084);3085for (func, flags) in partition.without_store.iter() {3086self.generate_function_trait_sig(func, *flags);3087uwriteln!(self.src, "{{");3088if flags.contains(FunctionFlags::ASYNC) {3089uwriteln!(self.src, "async move {{");3090}3091uwrite!(3092self.src,3093"{trait_name}::{}(*self,",3094rust_function_name(func)3095);3096for (name, _) in func.params.iter() {3097uwrite!(self.src, "{},", to_rust_ident(name));3098}3099uwrite!(self.src, ")");3100if flags.contains(FunctionFlags::ASYNC) {3101uwrite!(self.src, ".await\n}}");3102}3103uwriteln!(self.src, "}}");3104}3105for extra in extra_functions {3106match extra {3107ExtraTraitMethod::ResourceDrop { name } => {3108let flags = self.import_resource_drop_flags(name);3109if flags.contains(FunctionFlags::STORE) {3110continue;3111}3112let camel = name.to_upper_camel_case();3113let mut await_ = "";3114if flags.contains(FunctionFlags::ASYNC) {3115self.src.push_str("async ");3116await_ = ".await";3117}3118uwrite!(3119self.src,3120"fn drop(&mut self, rep: {wt}::component::Resource<{camel}>) -> ",3121);3122self.push_wasmtime_or_anyhow_result();3123uwriteln!(3124self.src,3125"<()> {{3126{trait_name}::drop(*self, rep){await_}3127}}3128",3129);3130}3131ExtraTraitMethod::ErrorConvert { name, id } => {3132let root = self.path_to_root();3133let custom_name = &self.generator.trappable_errors[id];3134let snake = name.to_snake_case();3135let camel = name.to_upper_camel_case();3136uwrite!(3137self.src,3138"fn convert_{snake}(&mut self, err: {root}{custom_name}) -> ",3139);3140self.push_wasmtime_or_anyhow_result();3141uwriteln!(3142self.src,3143"<{camel}> {{3144{trait_name}::convert_{snake}(*self, err)3145}}3146",3147);3148}3149}3150}3151uwriteln!(self.src, "}}");31523153ret3154}3155}31563157enum ExtraTraitMethod<'a> {3158ResourceDrop { name: &'a str },3159ErrorConvert { name: &'a str, id: TypeId },3160}31613162struct FunctionPartitioning<'a> {3163without_store: Vec<(&'a Function, FunctionFlags)>,3164with_store: Vec<(&'a Function, FunctionFlags)>,3165}31663167#[derive(Default)]3168struct GeneratedTrait {3169name: String,3170with_store_name: Option<String>,3171all_func_flags: FunctionFlags,3172}31733174impl<'a> RustGenerator<'a> for InterfaceGenerator<'a> {3175fn resolve(&self) -> &'a Resolve {3176self.resolve3177}31783179fn ownership(&self) -> Ownership {3180self.generator.opts.ownership3181}31823183fn path_to_interface(&self, interface: InterfaceId) -> Option<String> {3184if let Some((cur, _, _)) = self.current_interface {3185if cur == interface {3186return None;3187}3188}3189let mut path_to_root = self.path_to_root();3190match &self.generator.interface_names[&interface] {3191InterfaceName::Remapped { name_at_root, .. } => path_to_root.push_str(name_at_root),3192InterfaceName::Path(path) => {3193for (i, name) in path.iter().enumerate() {3194if i > 0 {3195path_to_root.push_str("::");3196}3197path_to_root.push_str(name);3198}3199}3200}3201Some(path_to_root)3202}32033204fn push_str(&mut self, s: &str) {3205self.src.push_str(s);3206}32073208fn info(&self, ty: TypeId) -> TypeInfo {3209self.generator.types.get(ty)3210}32113212fn is_imported_interface(&self, interface: InterfaceId) -> bool {3213self.generator.interface_last_seen_as_import[&interface]3214}32153216fn wasmtime_path(&self) -> String {3217self.generator.wasmtime_path()3218}3219}32203221#[derive(Default)]3222struct LinkOptionsBuilder {3223unstable_features: BTreeSet<String>,3224}3225impl LinkOptionsBuilder {3226fn has_any(&self) -> bool {3227!self.unstable_features.is_empty()3228}3229fn add_world(&mut self, resolve: &Resolve, id: &WorldId) {3230let world = &resolve.worlds[*id];32313232self.add_stability(&world.stability);32333234for (_, import) in world.imports.iter() {3235match import {3236WorldItem::Interface { id, stability } => {3237self.add_stability(stability);3238self.add_interface(resolve, id);3239}3240WorldItem::Function(f) => {3241self.add_stability(&f.stability);3242}3243WorldItem::Type(t) => {3244self.add_type(resolve, t);3245}3246}3247}3248}3249fn add_interface(&mut self, resolve: &Resolve, id: &InterfaceId) {3250let interface = &resolve.interfaces[*id];32513252self.add_stability(&interface.stability);32533254for (_, t) in interface.types.iter() {3255self.add_type(resolve, t);3256}3257for (_, f) in interface.functions.iter() {3258self.add_stability(&f.stability);3259}3260}3261fn add_type(&mut self, resolve: &Resolve, id: &TypeId) {3262let t = &resolve.types[*id];3263self.add_stability(&t.stability);3264}3265fn add_stability(&mut self, stability: &Stability) {3266match stability {3267Stability::Unstable { feature, .. } => {3268self.unstable_features.insert(feature.clone());3269}3270Stability::Stable { .. } | Stability::Unknown => {}3271}3272}3273fn write_struct(&self, src: &mut Source) {3274if !self.has_any() {3275return;3276}32773278let mut unstable_features = self.unstable_features.iter().cloned().collect::<Vec<_>>();3279unstable_features.sort();32803281uwriteln!(3282src,3283"3284/// Link-time configurations.3285#[derive(Clone, Debug, Default)]3286pub struct LinkOptions {{3287"3288);32893290for feature in unstable_features.iter() {3291let feature_rust_name = feature.to_snake_case();3292uwriteln!(src, "{feature_rust_name}: bool,");3293}32943295uwriteln!(src, "}}");3296uwriteln!(src, "impl LinkOptions {{");32973298for feature in unstable_features.iter() {3299let feature_rust_name = feature.to_snake_case();3300uwriteln!(3301src,3302"3303/// Enable members marked as `@unstable(feature = {feature})`3304pub fn {feature_rust_name}(&mut self, enabled: bool) -> &mut Self {{3305self.{feature_rust_name} = enabled;3306self3307}}3308"3309);3310}33113312uwriteln!(src, "}}");3313}3314fn write_impl_from_world(&self, src: &mut Source, path: &str) {3315if !self.has_any() {3316return;3317}33183319let mut unstable_features = self.unstable_features.iter().cloned().collect::<Vec<_>>();3320unstable_features.sort();33213322uwriteln!(3323src,3324"3325impl core::convert::From<LinkOptions> for {path}::LinkOptions {{3326fn from(src: LinkOptions) -> Self {{3327(&src).into()3328}}3329}}33303331impl core::convert::From<&LinkOptions> for {path}::LinkOptions {{3332fn from(src: &LinkOptions) -> Self {{3333let mut dest = Self::default();3334"3335);33363337for feature in unstable_features.iter() {3338let feature_rust_name = feature.to_snake_case();3339uwriteln!(src, "dest.{feature_rust_name}(src.{feature_rust_name});");3340}33413342uwriteln!(3343src,3344"3345dest3346}}3347}}3348"3349);3350}3351}33523353struct FeatureGate {3354close: bool,3355}3356impl FeatureGate {3357fn open(src: &mut Source, stability: &Stability) -> FeatureGate {3358let close = if let Stability::Unstable { feature, .. } = stability {3359let feature_rust_name = feature.to_snake_case();3360uwrite!(src, "if options.{feature_rust_name} {{");3361true3362} else {3363false3364};3365Self { close }3366}33673368fn close(self, src: &mut Source) {3369if self.close {3370uwriteln!(src, "}}");3371}3372}3373}33743375/// Produce a string for tracing a function argument.3376fn formatting_for_arg(3377name: &str,3378index: usize,3379ty: Type,3380resolve: &Resolve,3381flags: FunctionFlags,3382) -> String {3383if !flags.contains(FunctionFlags::VERBOSE_TRACING) && type_contains_lists(ty, resolve) {3384return format!("{name} = tracing::field::debug(\"...\")");3385}33863387// Normal tracing.3388format!("{name} = tracing::field::debug(&arg{index})")3389}33903391/// Produce a string for tracing function results.3392fn formatting_for_results(result: Option<Type>, resolve: &Resolve, flags: FunctionFlags) -> String {3393let contains_lists = match result {3394Some(ty) => type_contains_lists(ty, resolve),3395None => false,3396};33973398if !flags.contains(FunctionFlags::VERBOSE_TRACING) && contains_lists {3399return format!("result = tracing::field::debug(\"...\")");3400}34013402// Normal tracing.3403format!("result = tracing::field::debug(&r)")3404}34053406/// Test whether the given type contains lists.3407///3408/// Here, a `string` is not considered a list.3409fn type_contains_lists(ty: Type, resolve: &Resolve) -> bool {3410match ty {3411Type::Id(id) => match &resolve.types[id].kind {3412TypeDefKind::Resource3413| TypeDefKind::Unknown3414| TypeDefKind::Flags(_)3415| TypeDefKind::Handle(_)3416| TypeDefKind::Enum(_)3417| TypeDefKind::Stream(_)3418| TypeDefKind::Future(_) => false,3419TypeDefKind::Option(ty) => type_contains_lists(*ty, resolve),3420TypeDefKind::Result(Result_ { ok, err }) => {3421option_type_contains_lists(*ok, resolve)3422|| option_type_contains_lists(*err, resolve)3423}3424TypeDefKind::Record(record) => record3425.fields3426.iter()3427.any(|field| type_contains_lists(field.ty, resolve)),3428TypeDefKind::Tuple(tuple) => tuple3429.types3430.iter()3431.any(|ty| type_contains_lists(*ty, resolve)),3432TypeDefKind::Variant(variant) => variant3433.cases3434.iter()3435.any(|case| option_type_contains_lists(case.ty, resolve)),3436TypeDefKind::Type(ty) => type_contains_lists(*ty, resolve),3437TypeDefKind::List(_) => true,3438TypeDefKind::FixedSizeList(..) => todo!(),3439TypeDefKind::Map(..) => todo!(),3440},34413442// Technically strings are lists too, but we ignore that here because3443// they're usually short.3444_ => false,3445}3446}34473448fn option_type_contains_lists(ty: Option<Type>, resolve: &Resolve) -> bool {3449match ty {3450Some(ty) => type_contains_lists(ty, resolve),3451None => false,3452}3453}34543455/// When an interface `use`s a type from another interface, it creates a new TypeId3456/// referring to the definition TypeId. Chase this chain of references down to3457/// a TypeId for type's definition.3458fn resolve_type_definition_id(resolve: &Resolve, mut id: TypeId) -> TypeId {3459loop {3460match resolve.types[id].kind {3461TypeDefKind::Type(Type::Id(def_id)) => id = def_id,3462_ => return id,3463}3464}3465}34663467fn rust_function_name(func: &Function) -> String {3468match func.kind {3469FunctionKind::Constructor(_) => "new".to_string(),3470FunctionKind::Method(_)3471| FunctionKind::Static(_)3472| FunctionKind::AsyncMethod(_)3473| FunctionKind::AsyncStatic(_)3474| FunctionKind::Freestanding3475| FunctionKind::AsyncFreestanding => to_rust_ident(func.item_name()),3476}3477}34783479fn func_field_name(resolve: &Resolve, func: &Function) -> String {3480let mut name = String::new();3481match func.kind {3482FunctionKind::Method(id) | FunctionKind::AsyncMethod(id) => {3483name.push_str("method-");3484name.push_str(resolve.types[id].name.as_ref().unwrap());3485name.push_str("-");3486}3487FunctionKind::Static(id) | FunctionKind::AsyncStatic(id) => {3488name.push_str("static-");3489name.push_str(resolve.types[id].name.as_ref().unwrap());3490name.push_str("-");3491}3492FunctionKind::Constructor(id) => {3493name.push_str("constructor-");3494name.push_str(resolve.types[id].name.as_ref().unwrap());3495name.push_str("-");3496}3497FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {}3498}3499name.push_str(func.item_name());3500name.to_snake_case()3501}35023503fn get_resources<'a>(3504resolve: &'a Resolve,3505id: InterfaceId,3506) -> impl Iterator<Item = (TypeId, &'a str)> + 'a {3507resolve.interfaces[id]3508.types3509.iter()3510.filter_map(move |(name, ty)| match &resolve.types[*ty].kind {3511TypeDefKind::Resource => Some((*ty, name.as_str())),3512_ => None,3513})3514}35153516fn get_resource_functions<'a>(resolve: &'a Resolve, resource_id: TypeId) -> Vec<&'a Function> {3517let resource = &resolve.types[resource_id];3518match resource.owner {3519TypeOwner::World(id) => resolve.worlds[id]3520.imports3521.values()3522.filter_map(|item| match item {3523WorldItem::Function(f) => Some(f),3524_ => None,3525})3526.filter(|f| f.kind.resource() == Some(resource_id))3527.collect(),3528TypeOwner::Interface(id) => resolve.interfaces[id]3529.functions3530.values()3531.filter(|f| f.kind.resource() == Some(resource_id))3532.collect::<Vec<_>>(),3533TypeOwner::None => {3534panic!("A resource must be owned by a world or interface");3535}3536}3537}35383539fn get_world_resources<'a>(3540resolve: &'a Resolve,3541id: WorldId,3542) -> impl Iterator<Item = (TypeId, &'a str)> + 'a {3543resolve.worlds[id]3544.imports3545.iter()3546.filter_map(move |(name, item)| match item {3547WorldItem::Type(id) => match resolve.types[*id].kind {3548TypeDefKind::Resource => Some(match name {3549WorldKey::Name(s) => (*id, s.as_str()),3550WorldKey::Interface(_) => unreachable!(),3551}),3552_ => None,3553},3554_ => None,3555})3556}355735583559