Path: blob/main/crates/wit-bindgen/src/lib.rs
1693 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/// If true, write the generated bindings to a file for better error170/// messages from `rustc`.171///172/// This can also be toggled via the `WASMTIME_DEBUG_BINDGEN` environment173/// variable, but that will affect _all_ `bindgen!` macro invocations (and174/// can sometimes lead to one invocation overwriting another in unpredictable175/// ways), whereas this option lets you specify it on a case-by-case basis.176pub debug: bool,177178/// TODO179pub imports: FunctionConfig,180/// TODO181pub exports: FunctionConfig,182}183184#[derive(Debug, Clone)]185pub struct TrappableError {186/// Full path to the error, such as `wasi:io/streams/error`.187pub wit_path: String,188189/// The name, in Rust, of the error type to generate.190pub rust_type_name: String,191}192193impl Opts {194pub fn generate(&self, resolve: &Resolve, world: WorldId) -> anyhow::Result<String> {195// TODO: Should we refine this test to inspect only types reachable from196// the specified world?197if !cfg!(feature = "component-model-async")198&& resolve199.types200.iter()201.any(|(_, ty)| matches!(ty.kind, TypeDefKind::Future(_) | TypeDefKind::Stream(_)))202{203anyhow::bail!(204"must enable `component-model-async` feature when using WIT files \205containing future, stream, or error-context types"206);207}208209let mut r = Wasmtime::default();210r.sizes.fill(resolve);211r.opts = self.clone();212r.populate_world_and_interface_options(resolve, world);213r.generate(resolve, world)214}215}216217impl Wasmtime {218fn populate_world_and_interface_options(&mut self, resolve: &Resolve, world: WorldId) {219self.world_link_options.add_world(resolve, &world);220221for (_, import) in resolve.worlds[world].imports.iter() {222match import {223WorldItem::Interface { id, .. } => {224let mut o = LinkOptionsBuilder::default();225o.add_interface(resolve, id);226self.interface_link_options.insert(*id, o);227}228WorldItem::Function(_) | WorldItem::Type(_) => {}229}230}231}232fn name_interface(233&mut self,234resolve: &Resolve,235id: InterfaceId,236name: &WorldKey,237is_export: bool,238) -> bool {239let mut path = Vec::new();240if is_export {241path.push("exports".to_string());242}243match name {244WorldKey::Name(name) => {245path.push(name.to_snake_case());246}247WorldKey::Interface(_) => {248let iface = &resolve.interfaces[id];249let pkgname = &resolve.packages[iface.package.unwrap()].name;250path.push(pkgname.namespace.to_snake_case());251path.push(self.name_package_module(resolve, iface.package.unwrap()));252path.push(to_rust_ident(iface.name.as_ref().unwrap()));253}254}255let entry = if let Some(name_at_root) = self.lookup_replacement(resolve, name, None) {256InterfaceName::Remapped {257name_at_root,258local_path: path,259}260} else {261InterfaceName::Path(path)262};263264let remapped = matches!(entry, InterfaceName::Remapped { .. });265self.interface_names.insert(id, entry);266remapped267}268269/// If the package `id` is the only package with its namespace/name combo270/// then pass through the name unmodified. If, however, there are multiple271/// versions of this package then the package module is going to get version272/// information.273fn name_package_module(&self, resolve: &Resolve, id: PackageId) -> String {274let pkg = &resolve.packages[id];275let versions_with_same_name = resolve276.packages277.iter()278.filter_map(|(_, p)| {279if p.name.namespace == pkg.name.namespace && p.name.name == pkg.name.name {280Some(&p.name.version)281} else {282None283}284})285.collect::<Vec<_>>();286let base = pkg.name.name.to_snake_case();287if versions_with_same_name.len() == 1 {288return base;289}290291let version = match &pkg.name.version {292Some(version) => version,293// If this package didn't have a version then don't mangle its name294// and other packages with the same name but with versions present295// will have their names mangled.296None => return base,297};298299// Here there's multiple packages with the same name that differ only in300// version, so the version needs to be mangled into the Rust module name301// that we're generating. This in theory could look at all of302// `versions_with_same_name` and produce a minimal diff, e.g. for 0.1.0303// and 0.2.0 this could generate "foo1" and "foo2", but for now304// a simpler path is chosen to generate "foo0_1_0" and "foo0_2_0".305let version = version306.to_string()307.replace('.', "_")308.replace('-', "_")309.replace('+', "_")310.to_snake_case();311format!("{base}{version}")312}313314fn generate(&mut self, resolve: &Resolve, id: WorldId) -> anyhow::Result<String> {315self.types.analyze(resolve, id);316317self.world_link_options.write_struct(&mut self.src);318319// Resolve the `trappable_error_type` configuration values to `TypeId`320// values. This is done by iterating over each `trappable_error_type`321// and then locating the interface that it corresponds to as well as the322// type within that interface.323//324// Note that `LookupItem::InterfaceNoPop` is used here as the full325// hierarchical behavior of `lookup_keys` isn't used as the interface326// must be named here.327'outer: for (i, te) in self.opts.trappable_error_type.iter().enumerate() {328let error_name = format!("_TrappableError{i}");329for (id, iface) in resolve.interfaces.iter() {330for (key, projection) in lookup_keys(331resolve,332&WorldKey::Interface(id),333LookupItem::InterfaceNoPop,334) {335assert!(projection.is_empty());336337// If `wit_path` looks like `{key}/{type_name}` where338// `type_name` is a type within `iface` then we've found a339// match. Otherwise continue to the next lookup key if there340// is one, and failing that continue to the next interface.341let suffix = match te.wit_path.strip_prefix(&key) {342Some(s) => s,343None => continue,344};345let suffix = match suffix.strip_prefix('/') {346Some(s) => s,347None => continue,348};349if let Some(id) = iface.types.get(suffix) {350uwriteln!(self.src, "type {error_name} = {};", te.rust_type_name);351let prev = self.trappable_errors.insert(*id, error_name);352assert!(prev.is_none());353continue 'outer;354}355}356}357358bail!(359"failed to locate a WIT error type corresponding to the \360`trappable_error_type` name `{}` provided",361te.wit_path362)363}364365// Convert all entries in `with` as relative to the root of where the366// macro itself is invoked. This emits a `pub use` to bring the name367// into scope under an "anonymous name" which then replaces the `with`368// map entry.369let mut with = self.opts.with.iter_mut().collect::<Vec<_>>();370with.sort();371for (i, (_k, v)) in with.into_iter().enumerate() {372let name = format!("__with_name{i}");373uwriteln!(self.src, "#[doc(hidden)]\npub use {v} as {name};");374*v = name;375}376377let world = &resolve.worlds[id];378for (name, import) in world.imports.iter() {379if !self.opts.only_interfaces || matches!(import, WorldItem::Interface { .. }) {380self.import(resolve, name, import);381}382}383384for (name, export) in world.exports.iter() {385if !self.opts.only_interfaces || matches!(export, WorldItem::Interface { .. }) {386self.export(resolve, name, export);387}388}389self.finish(resolve, id)390}391392fn import(&mut self, resolve: &Resolve, name: &WorldKey, item: &WorldItem) {393let mut generator = InterfaceGenerator::new(self, resolve);394match item {395WorldItem::Function(func) => {396self.import_functions.push(func.clone());397}398WorldItem::Interface { id, .. } => {399generator400.generator401.interface_last_seen_as_import402.insert(*id, true);403generator.current_interface = Some((*id, name, false));404let snake = to_rust_ident(&match name {405WorldKey::Name(s) => s.to_snake_case(),406WorldKey::Interface(id) => resolve.interfaces[*id]407.name408.as_ref()409.unwrap()410.to_snake_case(),411});412let module = if generator413.generator414.name_interface(resolve, *id, name, false)415{416// If this interface is remapped then that means that it was417// provided via the `with` key in the bindgen configuration.418// That means that bindings generation is skipped here. To419// accommodate future bindgens depending on this bindgen420// though we still generate a module which reexports the421// original module. This helps maintain the same output422// structure regardless of whether `with` is used.423let name_at_root = match &generator.generator.interface_names[id] {424InterfaceName::Remapped { name_at_root, .. } => name_at_root,425InterfaceName::Path(_) => unreachable!(),426};427let path_to_root = generator.path_to_root();428format!(429"430pub mod {snake} {{431#[allow(unused_imports)]432pub use {path_to_root}{name_at_root}::*;433}}434"435)436} else {437// If this interface is not remapped then it's time to438// actually generate bindings here.439generator.generator.interface_link_options[id].write_struct(&mut generator.src);440generator.types(*id);441let key_name = resolve.name_world_key(name);442generator.generate_add_to_linker(*id, &key_name);443444let module = &generator.src[..];445let wt = generator.generator.wasmtime_path();446447format!(448"449#[allow(clippy::all)]450pub mod {snake} {{451#[allow(unused_imports)]452use {wt}::component::__internal::{{anyhow, Box}};453454{module}455}}456"457)458};459let all_func_flags = generator.all_func_flags;460self.import_interfaces.push(ImportInterface {461id: *id,462contents: module,463name: self.interface_names[id].clone(),464all_func_flags,465});466467let interface_path = self.import_interface_path(id);468self.interface_link_options[id]469.write_impl_from_world(&mut self.src, &interface_path);470}471WorldItem::Type(ty) => {472let name = match name {473WorldKey::Name(name) => name,474WorldKey::Interface(_) => unreachable!(),475};476generator.define_type(name, *ty);477let body = mem::take(&mut generator.src);478self.src.push_str(&body);479}480};481}482483fn export(&mut self, resolve: &Resolve, name: &WorldKey, item: &WorldItem) {484let wt = self.wasmtime_path();485let mut generator = InterfaceGenerator::new(self, resolve);486let field;487let ty;488let ty_index;489let load;490let get_index;491match item {492WorldItem::Function(func) => {493generator.define_rust_guest_export(resolve, None, func);494let body = mem::take(&mut generator.src).into();495load = generator.extract_typed_function(func).1;496assert!(generator.src.is_empty());497generator.generator.exports.funcs.push(body);498ty_index = format!("{wt}::component::ComponentExportIndex");499field = func_field_name(resolve, func);500ty = format!("{wt}::component::Func");501let sig = generator.typedfunc_sig(func, TypeMode::AllBorrowed("'_"));502let typecheck = format!(503"match item {{504{wt}::component::types::ComponentItem::ComponentFunc(func) => {{505anyhow::Context::context(506func.typecheck::<{sig}>(&_instance_type),507\"type-checking export func `{0}`\"508)?;509index510}}511_ => Err(anyhow::anyhow!(\"export `{0}` is not a function\"))?,512}}",513func.name514);515get_index = format!(516"{{ let (item, index) = _component.get_export(None, \"{}\")517.ok_or_else(|| anyhow::anyhow!(\"no export `{0}` found\"))?;518{typecheck}519}}",520func.name521);522}523WorldItem::Type(_) => unreachable!(),524WorldItem::Interface { id, .. } => {525generator526.generator527.interface_last_seen_as_import528.insert(*id, false);529generator.generator.name_interface(resolve, *id, name, true);530generator.current_interface = Some((*id, name, true));531generator.types(*id);532let struct_name = "Guest";533let iface = &resolve.interfaces[*id];534let iface_name = match name {535WorldKey::Name(name) => name,536WorldKey::Interface(_) => iface.name.as_ref().unwrap(),537};538uwriteln!(generator.src, "pub struct {struct_name} {{");539for (_, func) in iface.functions.iter() {540uwriteln!(541generator.src,542"{}: {wt}::component::Func,",543func_field_name(resolve, func)544);545}546uwriteln!(generator.src, "}}");547548uwriteln!(generator.src, "#[derive(Clone)]");549uwriteln!(generator.src, "pub struct {struct_name}Indices {{");550for (_, func) in iface.functions.iter() {551uwriteln!(552generator.src,553"{}: {wt}::component::ComponentExportIndex,",554func_field_name(resolve, func)555);556}557uwriteln!(generator.src, "}}");558559uwriteln!(generator.src, "impl {struct_name}Indices {{");560let instance_name = resolve.name_world_key(name);561uwrite!(562generator.src,563"564/// Constructor for [`{struct_name}Indices`] which takes a565/// [`Component`]({wt}::component::Component) as input and can be executed566/// before instantiation.567///568/// This constructor can be used to front-load string lookups to find exports569/// within a component.570pub fn new<_T>(571_instance_pre: &{wt}::component::InstancePre<_T>,572) -> {wt}::Result<{struct_name}Indices> {{573let instance = _instance_pre.component().get_export_index(None, \"{instance_name}\")574.ok_or_else(|| anyhow::anyhow!(\"no exported instance named `{instance_name}`\"))?;575let mut lookup = move |name| {{576_instance_pre.component().get_export_index(Some(&instance), name).ok_or_else(|| {{577anyhow::anyhow!(578\"instance export `{instance_name}` does \\579not have export `{{name}}`\"580)581}})582}};583let _ = &mut lookup;584"585);586let mut fields = Vec::new();587for (_, func) in iface.functions.iter() {588let name = func_field_name(resolve, func);589uwriteln!(generator.src, "let {name} = lookup(\"{}\")?;", func.name);590fields.push(name);591}592uwriteln!(generator.src, "Ok({struct_name}Indices {{");593for name in fields {594uwriteln!(generator.src, "{name},");595}596uwriteln!(generator.src, "}})");597uwriteln!(generator.src, "}}"); // end `fn _new`598599uwrite!(600generator.src,601"602pub fn load(603&self,604mut store: impl {wt}::AsContextMut,605instance: &{wt}::component::Instance,606) -> {wt}::Result<{struct_name}> {{607let _instance = instance;608let _instance_pre = _instance.instance_pre(&store);609let _instance_type = _instance_pre.instance_type();610let mut store = store.as_context_mut();611let _ = &mut store;612"613);614let mut fields = Vec::new();615for (_, func) in iface.functions.iter() {616let (name, getter) = generator.extract_typed_function(func);617uwriteln!(generator.src, "let {name} = {getter};");618fields.push(name);619}620uwriteln!(generator.src, "Ok({struct_name} {{");621for name in fields {622uwriteln!(generator.src, "{name},");623}624uwriteln!(generator.src, "}})");625uwriteln!(generator.src, "}}"); // end `fn new`626uwriteln!(generator.src, "}}"); // end `impl {struct_name}Indices`627628uwriteln!(generator.src, "impl {struct_name} {{");629let mut resource_methods = IndexMap::new();630631for (_, func) in iface.functions.iter() {632match func.kind.resource() {633None => {634generator.define_rust_guest_export(resolve, Some(name), func);635}636Some(id) => {637resource_methods.entry(id).or_insert(Vec::new()).push(func);638}639}640}641642for (id, _) in resource_methods.iter() {643let name = resolve.types[*id].name.as_ref().unwrap();644let snake = name.to_snake_case();645let camel = name.to_upper_camel_case();646uwriteln!(647generator.src,648"pub fn {snake}(&self) -> Guest{camel}<'_> {{649Guest{camel} {{ funcs: self }}650}}"651);652}653654uwriteln!(generator.src, "}}");655656for (id, methods) in resource_methods {657let resource_name = resolve.types[id].name.as_ref().unwrap();658let camel = resource_name.to_upper_camel_case();659uwriteln!(generator.src, "impl Guest{camel}<'_> {{");660for method in methods {661generator.define_rust_guest_export(resolve, Some(name), method);662}663uwriteln!(generator.src, "}}");664}665666let module = &generator.src[..];667let snake = to_rust_ident(iface_name);668669let module = format!(670"671#[allow(clippy::all)]672pub mod {snake} {{673#[allow(unused_imports)]674use {wt}::component::__internal::{{anyhow, Box}};675676{module}677}}678"679);680let pkgname = match name {681WorldKey::Name(_) => None,682WorldKey::Interface(_) => {683Some(resolve.packages[iface.package.unwrap()].name.clone())684}685};686self.exports687.modules688.push((*id, module, self.interface_names[id].clone()));689690let (path, method_name) = match pkgname {691Some(pkgname) => (692format!(693"exports::{}::{}::{snake}::{struct_name}",694pkgname.namespace.to_snake_case(),695self.name_package_module(resolve, iface.package.unwrap()),696),697format!(698"{}_{}_{snake}",699pkgname.namespace.to_snake_case(),700self.name_package_module(resolve, iface.package.unwrap())701),702),703None => (format!("exports::{snake}::{struct_name}"), snake.clone()),704};705field = format!("interface{}", self.exports.fields.len());706load = format!("self.{field}.load(&mut store, &_instance)?");707self.exports.funcs.push(format!(708"709pub fn {method_name}(&self) -> &{path} {{710&self.{field}711}}712",713));714ty_index = format!("{path}Indices");715ty = path;716get_index = format!("{ty_index}::new(_instance_pre)?");717}718}719let prev = self.exports.fields.insert(720field,721ExportField {722ty,723ty_index,724load,725get_index,726},727);728assert!(prev.is_none());729}730731fn build_world_struct(&mut self, resolve: &Resolve, world: WorldId) {732let wt = self.wasmtime_path();733let world_name = &resolve.worlds[world].name;734let camel = to_rust_upper_camel_case(&world_name);735uwriteln!(736self.src,737"738/// Auto-generated bindings for a pre-instantiated version of a739/// component which implements the world `{world_name}`.740///741/// This structure is created through [`{camel}Pre::new`] which742/// takes a [`InstancePre`]({wt}::component::InstancePre) that743/// has been created through a [`Linker`]({wt}::component::Linker).744///745/// For more information see [`{camel}`] as well.746pub struct {camel}Pre<T: 'static> {{747instance_pre: {wt}::component::InstancePre<T>,748indices: {camel}Indices,749}}750751impl<T: 'static> Clone for {camel}Pre<T> {{752fn clone(&self) -> Self {{753Self {{754instance_pre: self.instance_pre.clone(),755indices: self.indices.clone(),756}}757}}758}}759760impl<_T: 'static> {camel}Pre<_T> {{761/// Creates a new copy of `{camel}Pre` bindings which can then762/// be used to instantiate into a particular store.763///764/// This method may fail if the component behind `instance_pre`765/// does not have the required exports.766pub fn new(instance_pre: {wt}::component::InstancePre<_T>) -> {wt}::Result<Self> {{767let indices = {camel}Indices::new(&instance_pre)?;768Ok(Self {{ instance_pre, indices }})769}}770771pub fn engine(&self) -> &{wt}::Engine {{772self.instance_pre.engine()773}}774775pub fn instance_pre(&self) -> &{wt}::component::InstancePre<_T> {{776&self.instance_pre777}}778779/// Instantiates a new instance of [`{camel}`] within the780/// `store` provided.781///782/// This function will use `self` as the pre-instantiated783/// instance to perform instantiation. Afterwards the preloaded784/// indices in `self` are used to lookup all exports on the785/// resulting instance.786pub fn instantiate(787&self,788mut store: impl {wt}::AsContextMut<Data = _T>,789) -> {wt}::Result<{camel}> {{790let mut store = store.as_context_mut();791let instance = self.instance_pre.instantiate(&mut store)?;792self.indices.load(&mut store, &instance)793}}794}}795"796);797798if cfg!(feature = "async") {799uwriteln!(800self.src,801"802impl<_T: Send + 'static> {camel}Pre<_T> {{803/// Same as [`Self::instantiate`], except with `async`.804pub async fn instantiate_async(805&self,806mut store: impl {wt}::AsContextMut<Data = _T>,807) -> {wt}::Result<{camel}> {{808let mut store = store.as_context_mut();809let instance = self.instance_pre.instantiate_async(&mut store).await?;810self.indices.load(&mut store, &instance)811}}812}}813"814);815}816817uwriteln!(818self.src,819"820/// Auto-generated bindings for index of the exports of821/// `{world_name}`.822///823/// This is an implementation detail of [`{camel}Pre`] and can824/// be constructed if needed as well.825///826/// For more information see [`{camel}`] as well.827#[derive(Clone)]828pub struct {camel}Indices {{"829);830for (name, field) in self.exports.fields.iter() {831uwriteln!(self.src, "{name}: {},", field.ty_index);832}833self.src.push_str("}\n");834835uwriteln!(836self.src,837"838/// Auto-generated bindings for an instance a component which839/// implements the world `{world_name}`.840///841/// This structure can be created through a number of means842/// depending on your requirements and what you have on hand:843///844/// * The most convenient way is to use845/// [`{camel}::instantiate`] which only needs a846/// [`Store`], [`Component`], and [`Linker`].847///848/// * Alternatively you can create a [`{camel}Pre`] ahead of849/// time with a [`Component`] to front-load string lookups850/// of exports once instead of per-instantiation. This851/// method then uses [`{camel}Pre::instantiate`] to852/// create a [`{camel}`].853///854/// * If you've instantiated the instance yourself already855/// then you can use [`{camel}::new`].856///857/// These methods are all equivalent to one another and move858/// around the tradeoff of what work is performed when.859///860/// [`Store`]: {wt}::Store861/// [`Component`]: {wt}::component::Component862/// [`Linker`]: {wt}::component::Linker863pub struct {camel} {{"864);865for (name, field) in self.exports.fields.iter() {866uwriteln!(self.src, "{name}: {},", field.ty);867}868self.src.push_str("}\n");869870let world_trait = self.world_imports_trait(resolve, world);871872uwriteln!(self.src, "const _: () = {{");873uwriteln!(874self.src,875"876#[allow(unused_imports)]877use {wt}::component::__internal::anyhow;878"879);880881uwriteln!(882self.src,883"impl {camel}Indices {{884/// Creates a new copy of `{camel}Indices` bindings which can then885/// be used to instantiate into a particular store.886///887/// This method may fail if the component does not have the888/// required exports.889pub fn new<_T>(_instance_pre: &{wt}::component::InstancePre<_T>) -> {wt}::Result<Self> {{890let _component = _instance_pre.component();891let _instance_type = _instance_pre.instance_type();892",893);894for (name, field) in self.exports.fields.iter() {895uwriteln!(self.src, "let {name} = {};", field.get_index);896}897uwriteln!(self.src, "Ok({camel}Indices {{");898for (name, _) in self.exports.fields.iter() {899uwriteln!(self.src, "{name},");900}901uwriteln!(self.src, "}})");902uwriteln!(self.src, "}}"); // close `fn new`903904uwriteln!(905self.src,906"907/// Uses the indices stored in `self` to load an instance908/// of [`{camel}`] from the instance provided.909///910/// Note that at this time this method will additionally911/// perform type-checks of all exports.912pub fn load(913&self,914mut store: impl {wt}::AsContextMut,915instance: &{wt}::component::Instance,916) -> {wt}::Result<{camel}> {{917let _ = &mut store;918let _instance = instance;919",920);921for (name, field) in self.exports.fields.iter() {922uwriteln!(self.src, "let {name} = {};", field.load);923}924uwriteln!(self.src, "Ok({camel} {{");925for (name, _) in self.exports.fields.iter() {926uwriteln!(self.src, "{name},");927}928uwriteln!(self.src, "}})");929uwriteln!(self.src, "}}"); // close `fn load`930uwriteln!(self.src, "}}"); // close `impl {camel}Indices`931932uwriteln!(933self.src,934"impl {camel} {{935/// Convenience wrapper around [`{camel}Pre::new`] and936/// [`{camel}Pre::instantiate`].937pub fn instantiate<_T>(938store: impl {wt}::AsContextMut<Data = _T>,939component: &{wt}::component::Component,940linker: &{wt}::component::Linker<_T>,941) -> {wt}::Result<{camel}> {{942let pre = linker.instantiate_pre(component)?;943{camel}Pre::new(pre)?.instantiate(store)944}}945946/// Convenience wrapper around [`{camel}Indices::new`] and947/// [`{camel}Indices::load`].948pub fn new(949mut store: impl {wt}::AsContextMut,950instance: &{wt}::component::Instance,951) -> {wt}::Result<{camel}> {{952let indices = {camel}Indices::new(&instance.instance_pre(&store))?;953indices.load(&mut store, instance)954}}955",956);957958if cfg!(feature = "async") {959uwriteln!(960self.src,961"962/// Convenience wrapper around [`{camel}Pre::new`] and963/// [`{camel}Pre::instantiate_async`].964pub async fn instantiate_async<_T>(965store: impl {wt}::AsContextMut<Data = _T>,966component: &{wt}::component::Component,967linker: &{wt}::component::Linker<_T>,968) -> {wt}::Result<{camel}>969where _T: Send,970{{971let pre = linker.instantiate_pre(component)?;972{camel}Pre::new(pre)?.instantiate_async(store).await973}}974",975);976}977self.world_add_to_linker(resolve, world, world_trait.as_ref());978979for func in self.exports.funcs.iter() {980self.src.push_str(func);981}982983uwriteln!(self.src, "}}"); // close `impl {camel}`984985uwriteln!(self.src, "}};"); // close `const _: () = ...986}987988fn finish(&mut self, resolve: &Resolve, world: WorldId) -> anyhow::Result<String> {989let remapping_keys = self.opts.with.keys().cloned().collect::<HashSet<String>>();990991let mut unused_keys = remapping_keys992.difference(&self.used_with_opts)993.map(|s| s.as_str())994.collect::<Vec<&str>>();995996unused_keys.sort();997998if !unused_keys.is_empty() {999anyhow::bail!(1000"interfaces were specified in the `with` config option but are not referenced in the target world: {unused_keys:?}"1001);1002}10031004if !self.opts.only_interfaces {1005self.build_world_struct(resolve, world)1006}10071008self.opts.imports.assert_all_rules_used("imports")?;1009self.opts.exports.assert_all_rules_used("exports")?;10101011let imports = mem::take(&mut self.import_interfaces);1012self.emit_modules(1013imports1014.into_iter()1015.map(|i| (i.id, i.contents, i.name))1016.collect(),1017);10181019let exports = mem::take(&mut self.exports.modules);1020self.emit_modules(exports);10211022let mut src = mem::take(&mut self.src);1023if self.opts.rustfmt {1024let mut child = Command::new("rustfmt")1025.arg("--edition=2018")1026.stdin(Stdio::piped())1027.stdout(Stdio::piped())1028.spawn()1029.expect("failed to spawn `rustfmt`");1030child1031.stdin1032.take()1033.unwrap()1034.write_all(src.as_bytes())1035.unwrap();1036src.as_mut_string().truncate(0);1037child1038.stdout1039.take()1040.unwrap()1041.read_to_string(src.as_mut_string())1042.unwrap();1043let status = child.wait().unwrap();1044assert!(status.success());1045}10461047Ok(src.into())1048}10491050fn emit_modules(&mut self, modules: Vec<(InterfaceId, String, InterfaceName)>) {1051#[derive(Default)]1052struct Module {1053submodules: BTreeMap<String, Module>,1054contents: Vec<String>,1055}1056let mut map = Module::default();1057for (_, module, name) in modules {1058let path = match name {1059InterfaceName::Remapped { local_path, .. } => local_path,1060InterfaceName::Path(path) => path,1061};1062let mut cur = &mut map;1063for name in path[..path.len() - 1].iter() {1064cur = cur1065.submodules1066.entry(name.clone())1067.or_insert(Module::default());1068}1069cur.contents.push(module);1070}10711072emit(&mut self.src, map);10731074fn emit(me: &mut Source, module: Module) {1075for (name, submodule) in module.submodules {1076uwriteln!(me, "pub mod {name} {{");1077emit(me, submodule);1078uwriteln!(me, "}}");1079}1080for submodule in module.contents {1081uwriteln!(me, "{submodule}");1082}1083}1084}10851086/// Attempts to find the `key`, possibly with the resource projection1087/// `item`, within the `with` map provided to bindings configuration.1088fn lookup_replacement(1089&mut self,1090resolve: &Resolve,1091key: &WorldKey,1092item: Option<&str>,1093) -> Option<String> {1094let item = match item {1095Some(item) => LookupItem::Name(item),1096None => LookupItem::None,1097};10981099for (lookup, mut projection) in lookup_keys(resolve, key, item) {1100if let Some(renamed) = self.opts.with.get(&lookup) {1101projection.push(renamed.clone());1102projection.reverse();1103self.used_with_opts.insert(lookup);1104return Some(projection.join("::"));1105}1106}11071108None1109}11101111fn wasmtime_path(&self) -> String {1112self.opts1113.wasmtime_crate1114.clone()1115.unwrap_or("wasmtime".to_string())1116}1117}11181119enum LookupItem<'a> {1120None,1121Name(&'a str),1122InterfaceNoPop,1123}11241125fn lookup_keys(1126resolve: &Resolve,1127key: &WorldKey,1128item: LookupItem<'_>,1129) -> Vec<(String, Vec<String>)> {1130struct Name<'a> {1131prefix: Prefix,1132item: Option<&'a str>,1133}11341135#[derive(Copy, Clone)]1136enum Prefix {1137Namespace(PackageId),1138UnversionedPackage(PackageId),1139VersionedPackage(PackageId),1140UnversionedInterface(InterfaceId),1141VersionedInterface(InterfaceId),1142}11431144let prefix = match key {1145WorldKey::Interface(id) => Prefix::VersionedInterface(*id),11461147// Non-interface-keyed names don't get the lookup logic below,1148// they're relatively uncommon so only lookup the precise key here.1149WorldKey::Name(key) => {1150let to_lookup = match item {1151LookupItem::Name(item) => format!("{key}/{item}"),1152LookupItem::None | LookupItem::InterfaceNoPop => key.to_string(),1153};1154return vec![(to_lookup, Vec::new())];1155}1156};11571158// Here names are iteratively attempted as `key` + `item` is "walked to1159// its root" and each attempt is consulted in `self.opts.with`. This1160// loop will start at the leaf, the most specific path, and then walk to1161// the root, popping items, trying to find a result.1162//1163// Each time a name is "popped" the projection from the next path is1164// pushed onto `projection`. This means that if we actually find a match1165// then `projection` is a collection of namespaces that results in the1166// final replacement name.1167let (interface_required, item) = match item {1168LookupItem::None => (false, None),1169LookupItem::Name(s) => (false, Some(s)),1170LookupItem::InterfaceNoPop => (true, None),1171};1172let mut name = Name { prefix, item };1173let mut projection = Vec::new();1174let mut ret = Vec::new();1175loop {1176let lookup = name.lookup_key(resolve);1177ret.push((lookup, projection.clone()));1178if !name.pop(resolve, &mut projection) {1179break;1180}1181if interface_required {1182match name.prefix {1183Prefix::VersionedInterface(_) | Prefix::UnversionedInterface(_) => {}1184_ => break,1185}1186}1187}11881189return ret;11901191impl<'a> Name<'a> {1192fn lookup_key(&self, resolve: &Resolve) -> String {1193let mut s = self.prefix.lookup_key(resolve);1194if let Some(item) = self.item {1195s.push_str("/");1196s.push_str(item);1197}1198s1199}12001201fn pop(&mut self, resolve: &'a Resolve, projection: &mut Vec<String>) -> bool {1202match (self.item, self.prefix) {1203// If this is a versioned resource name, try the unversioned1204// resource name next.1205(Some(_), Prefix::VersionedInterface(id)) => {1206self.prefix = Prefix::UnversionedInterface(id);1207true1208}1209// If this is an unversioned resource name then time to1210// ignore the resource itself and move on to the next most1211// specific item, versioned interface names.1212(Some(item), Prefix::UnversionedInterface(id)) => {1213self.prefix = Prefix::VersionedInterface(id);1214self.item = None;1215projection.push(item.to_upper_camel_case());1216true1217}1218(Some(_), _) => unreachable!(),1219(None, _) => self.prefix.pop(resolve, projection),1220}1221}1222}12231224impl Prefix {1225fn lookup_key(&self, resolve: &Resolve) -> String {1226match *self {1227Prefix::Namespace(id) => resolve.packages[id].name.namespace.clone(),1228Prefix::UnversionedPackage(id) => {1229let mut name = resolve.packages[id].name.clone();1230name.version = None;1231name.to_string()1232}1233Prefix::VersionedPackage(id) => resolve.packages[id].name.to_string(),1234Prefix::UnversionedInterface(id) => {1235let id = resolve.id_of(id).unwrap();1236match id.find('@') {1237Some(i) => id[..i].to_string(),1238None => id,1239}1240}1241Prefix::VersionedInterface(id) => resolve.id_of(id).unwrap(),1242}1243}12441245fn pop(&mut self, resolve: &Resolve, projection: &mut Vec<String>) -> bool {1246*self = match *self {1247// try the unversioned interface next1248Prefix::VersionedInterface(id) => Prefix::UnversionedInterface(id),1249// try this interface's versioned package next1250Prefix::UnversionedInterface(id) => {1251let iface = &resolve.interfaces[id];1252let name = iface.name.as_ref().unwrap();1253projection.push(to_rust_ident(name));1254Prefix::VersionedPackage(iface.package.unwrap())1255}1256// try the unversioned package next1257Prefix::VersionedPackage(id) => Prefix::UnversionedPackage(id),1258// try this package's namespace next1259Prefix::UnversionedPackage(id) => {1260let name = &resolve.packages[id].name;1261projection.push(to_rust_ident(&name.name));1262Prefix::Namespace(id)1263}1264// nothing left to try any more1265Prefix::Namespace(_) => return false,1266};1267true1268}1269}1270}12711272impl Wasmtime {1273fn has_world_imports_trait(&self, resolve: &Resolve, world: WorldId) -> bool {1274!self.import_functions.is_empty() || get_world_resources(resolve, world).count() > 01275}12761277fn world_imports_trait(&mut self, resolve: &Resolve, world: WorldId) -> Option<GeneratedTrait> {1278if !self.has_world_imports_trait(resolve, world) {1279return None;1280}12811282let world_camel = to_rust_upper_camel_case(&resolve.worlds[world].name);12831284let functions = self.import_functions.clone();1285let mut generator = InterfaceGenerator::new(self, resolve);1286let generated_trait = generator.generate_trait(1287&format!("{world_camel}Imports"),1288&functions1289.iter()1290.filter(|f| f.kind.resource().is_none())1291.collect::<Vec<_>>(),1292&[],1293&get_world_resources(resolve, world).collect::<Vec<_>>(),1294);1295let src = String::from(mem::take(&mut generator.src));1296self.src.push_str(&src);1297Some(generated_trait)1298}12991300fn import_interface_paths(&self) -> Vec<(InterfaceId, String)> {1301self.import_interfaces1302.iter()1303.map(|i| {1304let path = match &i.name {1305InterfaceName::Path(path) => path.join("::"),1306InterfaceName::Remapped { name_at_root, .. } => name_at_root.clone(),1307};1308(i.id, path)1309})1310.collect()1311}13121313fn import_interface_path(&self, id: &InterfaceId) -> String {1314match &self.interface_names[id] {1315InterfaceName::Path(path) => path.join("::"),1316InterfaceName::Remapped { name_at_root, .. } => name_at_root.clone(),1317}1318}13191320fn import_interface_all_func_flags(&self, id: InterfaceId) -> FunctionFlags {1321for i in self.import_interfaces.iter() {1322if id != i.id {1323continue;1324}13251326return i.all_func_flags;1327}1328unreachable!()1329}13301331fn world_host_traits(1332&self,1333world_trait: Option<&GeneratedTrait>,1334) -> (Vec<String>, Vec<String>) {1335let mut without_store = Vec::new();1336let mut without_store_async = false;1337let mut with_store = Vec::new();1338let mut with_store_async = false;1339for (id, path) in self.import_interface_paths() {1340without_store.push(format!("{path}::Host"));1341let flags = self.import_interface_all_func_flags(id);1342without_store_async = without_store_async || flags.contains(FunctionFlags::ASYNC);13431344// Note that the requirement of `HostWithStore` is technically1345// dependent on `FunctionFlags::STORE`, but when `with` is in use we1346// don't necessarily know whether the other bindings generation1347// specified this flag or not. To handle that always assume that a1348// `HostWithStore` bound is needed.1349with_store.push(format!("{path}::HostWithStore"));1350with_store_async = with_store_async || flags.contains(FunctionFlags::ASYNC);1351}1352if let Some(world_trait) = world_trait {1353without_store.push(world_trait.name.clone());1354without_store_async =1355without_store_async || world_trait.all_func_flags.contains(FunctionFlags::ASYNC);13561357if world_trait.with_store_name.is_some() {1358with_store.extend(world_trait.with_store_name.clone());1359with_store_async =1360with_store_async || world_trait.all_func_flags.contains(FunctionFlags::ASYNC);1361}1362}1363if without_store_async {1364without_store.push("Send".to_string());1365}1366if with_store_async {1367with_store.push("Send".to_string());1368}1369(without_store, with_store)1370}13711372fn world_add_to_linker(1373&mut self,1374resolve: &Resolve,1375world: WorldId,1376world_trait: Option<&GeneratedTrait>,1377) {1378let has_world_imports_trait = self.has_world_imports_trait(resolve, world);1379if self.import_interfaces.is_empty() && !has_world_imports_trait {1380return;1381}13821383let (options_param, options_arg) = if self.world_link_options.has_any() {1384("options: &LinkOptions,", ", options")1385} else {1386("", "")1387};13881389let mut all_func_flags = FunctionFlags::empty();1390if let Some(world_trait) = world_trait {1391all_func_flags |= world_trait.all_func_flags;1392}1393for i in self.import_interfaces.iter() {1394all_func_flags |= i.all_func_flags;1395}13961397let opt_t_send_bound =1398if all_func_flags.contains(FunctionFlags::ASYNC) || self.opts.require_store_data_send {1399"+ Send"1400} else {1401""1402};14031404let wt = self.wasmtime_path();1405if let Some(world_trait) = world_trait {1406let d_bound = match &world_trait.with_store_name {1407Some(name) => name.clone(),1408None => format!("{wt}::component::HasData"),1409};1410uwrite!(1411self.src,1412"1413pub fn add_to_linker_imports<T, D>(1414linker: &mut {wt}::component::Linker<T>,1415{options_param}1416host_getter: fn(&mut T) -> D::Data<'_>,1417) -> {wt}::Result<()>1418where1419D: {d_bound},1420for<'a> D::Data<'a>: {name},1421T: 'static {opt_t_send_bound}1422{{1423let mut linker = linker.root();1424",1425name = world_trait.name,1426);1427let gate = FeatureGate::open(&mut self.src, &resolve.worlds[world].stability);1428for (ty, _name) in get_world_resources(resolve, world) {1429self.generate_add_resource_to_linker(None, None, "linker", resolve, ty);1430}1431for f in self.import_functions.clone() {1432let mut generator = InterfaceGenerator::new(self, resolve);1433generator.generate_add_function_to_linker(TypeOwner::World(world), &f, "linker");1434let src = String::from(generator.src);1435self.src.push_str(&src);1436self.src.push_str("\n");1437}1438gate.close(&mut self.src);1439uwriteln!(self.src, "Ok(())\n}}");1440}14411442let (sync_bounds, concurrent_bounds) = self.world_host_traits(world_trait);1443let sync_bounds = sync_bounds.join(" + ");1444let concurrent_bounds = concurrent_bounds.join(" + ");1445let d_bounds = if !concurrent_bounds.is_empty() {1446concurrent_bounds1447} else {1448format!("{wt}::component::HasData")1449};14501451uwriteln!(1452self.src,1453"1454pub fn add_to_linker<T, D>(1455linker: &mut {wt}::component::Linker<T>,1456{options_param}1457host_getter: fn(&mut T) -> D::Data<'_>,1458) -> {wt}::Result<()>1459where1460D: {d_bounds},1461for<'a> D::Data<'a>: {sync_bounds},1462T: 'static {opt_t_send_bound}1463{{1464"1465);1466let gate = FeatureGate::open(&mut self.src, &resolve.worlds[world].stability);1467if has_world_imports_trait {1468uwriteln!(1469self.src,1470"Self::add_to_linker_imports::<T, D>(linker {options_arg}, host_getter)?;"1471);1472}1473for (interface_id, path) in self.import_interface_paths() {1474let options_arg = if self.interface_link_options[&interface_id].has_any() {1475", &options.into()"1476} else {1477""1478};14791480let import_stability = resolve.worlds[world]1481.imports1482.iter()1483.filter_map(|(_, i)| match i {1484WorldItem::Interface { id, stability } if *id == interface_id => {1485Some(stability.clone())1486}1487_ => None,1488})1489.next()1490.unwrap_or(Stability::Unknown);14911492let gate = FeatureGate::open(&mut self.src, &import_stability);1493uwriteln!(1494self.src,1495"{path}::add_to_linker::<T, D>(linker {options_arg}, host_getter)?;"1496);1497gate.close(&mut self.src);1498}1499gate.close(&mut self.src);1500uwriteln!(self.src, "Ok(())\n}}");1501}15021503fn generate_add_resource_to_linker(1504&mut self,1505key: Option<&WorldKey>,1506src: Option<&mut Source>,1507inst: &str,1508resolve: &Resolve,1509ty: TypeId,1510) {1511let ty = &resolve.types[ty];1512let name = ty.name.as_ref().unwrap();1513let stability = &ty.stability;1514let wt = self.wasmtime_path();1515let src = src.unwrap_or(&mut self.src);1516let gate = FeatureGate::open(src, stability);1517let camel = name.to_upper_camel_case();15181519let flags = self.opts.imports.resource_drop_flags(resolve, key, name);1520if flags.contains(FunctionFlags::ASYNC) {1521if flags.contains(FunctionFlags::STORE) {1522uwriteln!(1523src,1524"{inst}.resource_concurrent(1525\"{name}\",1526{wt}::component::ResourceType::host::<{camel}>(),1527move |caller: &{wt}::component::Accessor::<T>, rep| {{1528{wt}::component::__internal::Box::pin(async move {{1529let accessor = &caller.with_getter(host_getter);1530Host{camel}WithStore::drop(accessor, {wt}::component::Resource::new_own(rep)).await1531}})1532}},1533)?;"1534)1535} else {1536uwriteln!(1537src,1538"{inst}.resource_async(1539\"{name}\",1540{wt}::component::ResourceType::host::<{camel}>(),1541move |mut store, rep| {{1542{wt}::component::__internal::Box::new(async move {{1543Host{camel}::drop(&mut host_getter(store.data_mut()), {wt}::component::Resource::new_own(rep)).await1544}})1545}},1546)?;"1547)1548}1549} else {1550let (first_arg, trait_suffix) = if flags.contains(FunctionFlags::STORE) {1551(1552format!("{wt}::component::Access::new(store, host_getter)"),1553"WithStore",1554)1555} else {1556("&mut host_getter(store.data_mut())".to_string(), "")1557};1558uwriteln!(1559src,1560"{inst}.resource(1561\"{name}\",1562{wt}::component::ResourceType::host::<{camel}>(),1563move |mut store, rep| -> {wt}::Result<()> {{15641565let resource = {wt}::component::Resource::new_own(rep);1566Host{camel}{trait_suffix}::drop({first_arg}, resource)1567}},1568)?;",1569)1570}1571gate.close(src);1572}1573}15741575struct InterfaceGenerator<'a> {1576src: Source,1577generator: &'a mut Wasmtime,1578resolve: &'a Resolve,1579current_interface: Option<(InterfaceId, &'a WorldKey, bool)>,1580all_func_flags: FunctionFlags,1581}15821583impl<'a> InterfaceGenerator<'a> {1584fn new(generator: &'a mut Wasmtime, resolve: &'a Resolve) -> InterfaceGenerator<'a> {1585InterfaceGenerator {1586src: Source::default(),1587generator,1588resolve,1589current_interface: None,1590all_func_flags: FunctionFlags::empty(),1591}1592}15931594fn types_imported(&self) -> bool {1595match self.current_interface {1596Some((_, _, is_export)) => !is_export,1597None => true,1598}1599}16001601fn types(&mut self, id: InterfaceId) {1602for (name, id) in self.resolve.interfaces[id].types.iter() {1603self.define_type(name, *id);1604}1605}16061607fn define_type(&mut self, name: &str, id: TypeId) {1608let ty = &self.resolve.types[id];1609match &ty.kind {1610TypeDefKind::Record(record) => self.type_record(id, name, record, &ty.docs),1611TypeDefKind::Flags(flags) => self.type_flags(id, name, flags, &ty.docs),1612TypeDefKind::Tuple(tuple) => self.type_tuple(id, name, tuple, &ty.docs),1613TypeDefKind::Enum(enum_) => self.type_enum(id, name, enum_, &ty.docs),1614TypeDefKind::Variant(variant) => self.type_variant(id, name, variant, &ty.docs),1615TypeDefKind::Option(t) => self.type_option(id, name, t, &ty.docs),1616TypeDefKind::Result(r) => self.type_result(id, name, r, &ty.docs),1617TypeDefKind::List(t) => self.type_list(id, name, t, &ty.docs),1618TypeDefKind::Type(t) => self.type_alias(id, name, t, &ty.docs),1619TypeDefKind::Future(t) => self.type_future(id, name, t.as_ref(), &ty.docs),1620TypeDefKind::Stream(t) => self.type_stream(id, name, t.as_ref(), &ty.docs),1621TypeDefKind::Handle(handle) => self.type_handle(id, name, handle, &ty.docs),1622TypeDefKind::Resource => self.type_resource(id, name, ty, &ty.docs),1623TypeDefKind::Unknown => unreachable!(),1624TypeDefKind::FixedSizeList(..) => todo!(),1625}1626}16271628fn type_handle(&mut self, id: TypeId, name: &str, handle: &Handle, docs: &Docs) {1629self.rustdoc(docs);1630let name = name.to_upper_camel_case();1631uwriteln!(self.src, "pub type {name} = ");1632self.print_handle(handle);1633self.push_str(";\n");1634self.assert_type(id, &name);1635}16361637fn type_resource(&mut self, id: TypeId, name: &str, _resource: &TypeDef, docs: &Docs) {1638let camel = name.to_upper_camel_case();1639let wt = self.generator.wasmtime_path();16401641if self.types_imported() {1642self.rustdoc(docs);16431644let replacement = match self.current_interface {1645Some((_, key, _)) => {1646self.generator1647.lookup_replacement(self.resolve, key, Some(name))1648}1649None => {1650self.generator.used_with_opts.insert(name.into());1651self.generator.opts.with.get(name).cloned()1652}1653};1654match replacement {1655Some(path) => {1656uwriteln!(1657self.src,1658"pub use {}{path} as {camel};",1659self.path_to_root()1660);1661}1662None => {1663uwriteln!(self.src, "pub enum {camel} {{}}");1664}1665}16661667// Generate resource trait16681669let functions = get_resource_functions(self.resolve, id);1670let trait_ = self.generate_trait(1671&format!("Host{camel}"),1672&functions,1673&[ExtraTraitMethod::ResourceDrop { name }],1674&[],1675);1676self.all_func_flags |= trait_.all_func_flags;1677} else {1678self.rustdoc(docs);1679uwriteln!(1680self.src,1681"1682pub type {camel} = {wt}::component::ResourceAny;16831684pub struct Guest{camel}<'a> {{1685funcs: &'a Guest,1686}}1687"1688);1689}1690}16911692fn type_record(&mut self, id: TypeId, _name: &str, record: &Record, docs: &Docs) {1693let info = self.info(id);1694let wt = self.generator.wasmtime_path();16951696// We use a BTree set to make sure we don't have any duplicates and we have a stable order1697let additional_derives: BTreeSet<String> = self1698.generator1699.opts1700.additional_derive_attributes1701.iter()1702.cloned()1703.collect();17041705for (name, mode) in self.modes_of(id) {1706let lt = self.lifetime_for(&info, mode);1707self.rustdoc(docs);17081709let mut derives = additional_derives.clone();17101711uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]");1712if lt.is_none() {1713uwriteln!(self.src, "#[derive({wt}::component::Lift)]");1714}1715uwriteln!(self.src, "#[derive({wt}::component::Lower)]");1716self.push_str("#[component(record)]\n");1717if let Some(path) = &self.generator.opts.wasmtime_crate {1718uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n");1719}17201721if info.is_copy() {1722derives.extend(["Copy", "Clone"].into_iter().map(|s| s.to_string()));1723} else if info.is_clone() {1724derives.insert("Clone".to_string());1725}17261727if !derives.is_empty() {1728self.push_str("#[derive(");1729self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", "));1730self.push_str(")]\n")1731}17321733self.push_str(&format!("pub struct {name}"));1734self.print_generics(lt);1735self.push_str(" {\n");1736for field in record.fields.iter() {1737self.rustdoc(&field.docs);1738self.push_str(&format!("#[component(name = \"{}\")]\n", field.name));1739self.push_str("pub ");1740self.push_str(&to_rust_ident(&field.name));1741self.push_str(": ");1742self.print_ty(&field.ty, mode);1743self.push_str(",\n");1744}1745self.push_str("}\n");17461747self.push_str("impl");1748self.print_generics(lt);1749self.push_str(" core::fmt::Debug for ");1750self.push_str(&name);1751self.print_generics(lt);1752self.push_str(" {\n");1753self.push_str(1754"fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n",1755);1756self.push_str(&format!("f.debug_struct(\"{name}\")"));1757for field in record.fields.iter() {1758self.push_str(&format!(1759".field(\"{}\", &self.{})",1760field.name,1761to_rust_ident(&field.name)1762));1763}1764self.push_str(".finish()\n");1765self.push_str("}\n");1766self.push_str("}\n");17671768if info.error {1769self.push_str("impl");1770self.print_generics(lt);1771self.push_str(" core::fmt::Display for ");1772self.push_str(&name);1773self.print_generics(lt);1774self.push_str(" {\n");1775self.push_str(1776"fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n",1777);1778self.push_str("write!(f, \"{:?}\", self)\n");1779self.push_str("}\n");1780self.push_str("}\n");17811782self.push_str("impl core::error::Error for ");1783self.push_str(&name);1784self.push_str("{}\n");1785}1786self.assert_type(id, &name);1787}1788}17891790fn type_tuple(&mut self, id: TypeId, _name: &str, tuple: &Tuple, docs: &Docs) {1791let info = self.info(id);1792for (name, mode) in self.modes_of(id) {1793let lt = self.lifetime_for(&info, mode);1794self.rustdoc(docs);1795self.push_str(&format!("pub type {name}"));1796self.print_generics(lt);1797self.push_str(" = (");1798for ty in tuple.types.iter() {1799self.print_ty(ty, mode);1800self.push_str(",");1801}1802self.push_str(");\n");1803self.assert_type(id, &name);1804}1805}18061807fn type_flags(&mut self, id: TypeId, name: &str, flags: &Flags, docs: &Docs) {1808self.rustdoc(docs);1809let wt = self.generator.wasmtime_path();1810let rust_name = to_rust_upper_camel_case(name);1811uwriteln!(self.src, "{wt}::component::flags!(\n");1812self.src.push_str(&format!("{rust_name} {{\n"));1813for flag in flags.flags.iter() {1814// TODO wasmtime-component-macro doesn't support docs for flags rn1815uwrite!(1816self.src,1817"#[component(name=\"{}\")] const {};\n",1818flag.name,1819flag.name.to_shouty_snake_case()1820);1821}1822self.src.push_str("}\n");1823self.src.push_str(");\n\n");1824self.assert_type(id, &rust_name);1825}18261827fn type_variant(&mut self, id: TypeId, _name: &str, variant: &Variant, docs: &Docs) {1828self.print_rust_enum(1829id,1830variant.cases.iter().map(|c| {1831(1832c.name.to_upper_camel_case(),1833Some(c.name.clone()),1834&c.docs,1835c.ty.as_ref(),1836)1837}),1838docs,1839"variant",1840);1841}18421843fn type_option(&mut self, id: TypeId, _name: &str, payload: &Type, docs: &Docs) {1844let info = self.info(id);18451846for (name, mode) in self.modes_of(id) {1847self.rustdoc(docs);1848let lt = self.lifetime_for(&info, mode);1849self.push_str(&format!("pub type {name}"));1850self.print_generics(lt);1851self.push_str("= Option<");1852self.print_ty(payload, mode);1853self.push_str(">;\n");1854self.assert_type(id, &name);1855}1856}18571858// Emit a double-check that the wit-parser-understood size of a type agrees1859// with the Wasmtime-understood size of a type.1860fn assert_type(&mut self, id: TypeId, name: &str) {1861self.push_str("const _: () = {\n");1862let wt = self.generator.wasmtime_path();1863uwriteln!(1864self.src,1865"assert!({} == <{name} as {wt}::component::ComponentType>::SIZE32);",1866self.generator.sizes.size(&Type::Id(id)).size_wasm32(),1867);1868uwriteln!(1869self.src,1870"assert!({} == <{name} as {wt}::component::ComponentType>::ALIGN32);",1871self.generator.sizes.align(&Type::Id(id)).align_wasm32(),1872);1873self.push_str("};\n");1874}18751876fn print_rust_enum<'b>(1877&mut self,1878id: TypeId,1879cases: impl IntoIterator<Item = (String, Option<String>, &'b Docs, Option<&'b Type>)> + Clone,1880docs: &Docs,1881derive_component: &str,1882) where1883Self: Sized,1884{1885let info = self.info(id);1886let wt = self.generator.wasmtime_path();18871888// We use a BTree set to make sure we don't have any duplicates and we have a stable order1889let additional_derives: BTreeSet<String> = self1890.generator1891.opts1892.additional_derive_attributes1893.iter()1894.cloned()1895.collect();18961897for (name, mode) in self.modes_of(id) {1898let name = to_rust_upper_camel_case(&name);18991900let mut derives = additional_derives.clone();19011902self.rustdoc(docs);1903let lt = self.lifetime_for(&info, mode);1904uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]");1905if lt.is_none() {1906uwriteln!(self.src, "#[derive({wt}::component::Lift)]");1907}1908uwriteln!(self.src, "#[derive({wt}::component::Lower)]");1909self.push_str(&format!("#[component({derive_component})]\n"));1910if let Some(path) = &self.generator.opts.wasmtime_crate {1911uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n");1912}1913if info.is_copy() {1914derives.extend(["Copy", "Clone"].into_iter().map(|s| s.to_string()));1915} else if info.is_clone() {1916derives.insert("Clone".to_string());1917}19181919if !derives.is_empty() {1920self.push_str("#[derive(");1921self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", "));1922self.push_str(")]\n")1923}19241925self.push_str(&format!("pub enum {name}"));1926self.print_generics(lt);1927self.push_str("{\n");1928for (case_name, component_name, docs, payload) in cases.clone() {1929self.rustdoc(docs);1930if let Some(n) = component_name {1931self.push_str(&format!("#[component(name = \"{n}\")] "));1932}1933self.push_str(&case_name);1934if let Some(ty) = payload {1935self.push_str("(");1936self.print_ty(ty, mode);1937self.push_str(")")1938}1939self.push_str(",\n");1940}1941self.push_str("}\n");19421943self.print_rust_enum_debug(1944id,1945mode,1946&name,1947cases1948.clone()1949.into_iter()1950.map(|(name, _attr, _docs, ty)| (name, ty)),1951);19521953if info.error {1954self.push_str("impl");1955self.print_generics(lt);1956self.push_str(" core::fmt::Display for ");1957self.push_str(&name);1958self.print_generics(lt);1959self.push_str(" {\n");1960self.push_str(1961"fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n",1962);1963self.push_str("write!(f, \"{:?}\", self)\n");1964self.push_str("}\n");1965self.push_str("}\n");19661967self.push_str("impl");1968self.print_generics(lt);1969self.push_str(" core::error::Error for ");1970self.push_str(&name);1971self.print_generics(lt);1972self.push_str(" {}\n");1973}19741975self.assert_type(id, &name);1976}1977}19781979fn print_rust_enum_debug<'b>(1980&mut self,1981id: TypeId,1982mode: TypeMode,1983name: &str,1984cases: impl IntoIterator<Item = (String, Option<&'b Type>)>,1985) where1986Self: Sized,1987{1988let info = self.info(id);1989let lt = self.lifetime_for(&info, mode);1990self.push_str("impl");1991self.print_generics(lt);1992self.push_str(" core::fmt::Debug for ");1993self.push_str(name);1994self.print_generics(lt);1995self.push_str(" {\n");1996self.push_str("fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n");1997self.push_str("match self {\n");1998for (case_name, payload) in cases {1999self.push_str(name);2000self.push_str("::");2001self.push_str(&case_name);2002if payload.is_some() {2003self.push_str("(e)");2004}2005self.push_str(" => {\n");2006self.push_str(&format!("f.debug_tuple(\"{name}::{case_name}\")"));2007if payload.is_some() {2008self.push_str(".field(e)");2009}2010self.push_str(".finish()\n");2011self.push_str("}\n");2012}2013self.push_str("}\n");2014self.push_str("}\n");2015self.push_str("}\n");2016}20172018fn type_result(&mut self, id: TypeId, _name: &str, result: &Result_, docs: &Docs) {2019let info = self.info(id);20202021for (name, mode) in self.modes_of(id) {2022self.rustdoc(docs);2023let lt = self.lifetime_for(&info, mode);2024self.push_str(&format!("pub type {name}"));2025self.print_generics(lt);2026self.push_str("= Result<");2027self.print_optional_ty(result.ok.as_ref(), mode);2028self.push_str(",");2029self.print_optional_ty(result.err.as_ref(), mode);2030self.push_str(">;\n");2031self.assert_type(id, &name);2032}2033}20342035fn type_enum(&mut self, id: TypeId, name: &str, enum_: &Enum, docs: &Docs) {2036let info = self.info(id);2037let wt = self.generator.wasmtime_path();20382039// We use a BTree set to make sure we don't have any duplicates and have a stable order2040let mut derives: BTreeSet<String> = self2041.generator2042.opts2043.additional_derive_attributes2044.iter()2045.cloned()2046.collect();20472048derives.extend(2049["Clone", "Copy", "PartialEq", "Eq"]2050.into_iter()2051.map(|s| s.to_string()),2052);20532054let name = to_rust_upper_camel_case(name);2055self.rustdoc(docs);2056uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]");2057uwriteln!(self.src, "#[derive({wt}::component::Lift)]");2058uwriteln!(self.src, "#[derive({wt}::component::Lower)]");2059self.push_str("#[component(enum)]\n");2060if let Some(path) = &self.generator.opts.wasmtime_crate {2061uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n");2062}20632064self.push_str("#[derive(");2065self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", "));2066self.push_str(")]\n");20672068let repr = match enum_.cases.len().ilog2() {20690..=7 => "u8",20708..=15 => "u16",2071_ => "u32",2072};2073uwriteln!(self.src, "#[repr({repr})]");20742075self.push_str(&format!("pub enum {name} {{\n"));2076for case in enum_.cases.iter() {2077self.rustdoc(&case.docs);2078self.push_str(&format!("#[component(name = \"{}\")]", case.name));2079self.push_str(&case.name.to_upper_camel_case());2080self.push_str(",\n");2081}2082self.push_str("}\n");20832084// Auto-synthesize an implementation of the standard `Error` trait for2085// error-looking types based on their name.2086if info.error {2087self.push_str("impl ");2088self.push_str(&name);2089self.push_str("{\n");20902091self.push_str("pub fn name(&self) -> &'static str {\n");2092self.push_str("match self {\n");2093for case in enum_.cases.iter() {2094self.push_str(&name);2095self.push_str("::");2096self.push_str(&case.name.to_upper_camel_case());2097self.push_str(" => \"");2098self.push_str(case.name.as_str());2099self.push_str("\",\n");2100}2101self.push_str("}\n");2102self.push_str("}\n");21032104self.push_str("pub fn message(&self) -> &'static str {\n");2105self.push_str("match self {\n");2106for case in enum_.cases.iter() {2107self.push_str(&name);2108self.push_str("::");2109self.push_str(&case.name.to_upper_camel_case());2110self.push_str(" => \"");2111if let Some(contents) = &case.docs.contents {2112self.push_str(contents.trim());2113}2114self.push_str("\",\n");2115}2116self.push_str("}\n");2117self.push_str("}\n");21182119self.push_str("}\n");21202121self.push_str("impl core::fmt::Debug for ");2122self.push_str(&name);2123self.push_str(2124"{\nfn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n",2125);2126self.push_str("f.debug_struct(\"");2127self.push_str(&name);2128self.push_str("\")\n");2129self.push_str(".field(\"code\", &(*self as i32))\n");2130self.push_str(".field(\"name\", &self.name())\n");2131self.push_str(".field(\"message\", &self.message())\n");2132self.push_str(".finish()\n");2133self.push_str("}\n");2134self.push_str("}\n");21352136self.push_str("impl core::fmt::Display for ");2137self.push_str(&name);2138self.push_str(2139"{\nfn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n",2140);2141self.push_str("write!(f, \"{} (error {})\", self.name(), *self as i32)");2142self.push_str("}\n");2143self.push_str("}\n");2144self.push_str("\n");2145self.push_str("impl core::error::Error for ");2146self.push_str(&name);2147self.push_str("{}\n");2148} else {2149self.print_rust_enum_debug(2150id,2151TypeMode::Owned,2152&name,2153enum_2154.cases2155.iter()2156.map(|c| (c.name.to_upper_camel_case(), None)),2157)2158}2159self.assert_type(id, &name);2160}21612162fn type_alias(&mut self, id: TypeId, _name: &str, ty: &Type, docs: &Docs) {2163let info = self.info(id);2164for (name, mode) in self.modes_of(id) {2165self.rustdoc(docs);2166self.push_str(&format!("pub type {name}"));2167let lt = self.lifetime_for(&info, mode);2168self.print_generics(lt);2169self.push_str(" = ");2170self.print_ty(ty, mode);2171self.push_str(";\n");2172let def_id = resolve_type_definition_id(self.resolve, id);2173if !matches!(self.resolve().types[def_id].kind, TypeDefKind::Resource) {2174self.assert_type(id, &name);2175}2176}2177}21782179fn type_list(&mut self, id: TypeId, _name: &str, ty: &Type, docs: &Docs) {2180let info = self.info(id);2181for (name, mode) in self.modes_of(id) {2182let lt = self.lifetime_for(&info, mode);2183self.rustdoc(docs);2184self.push_str(&format!("pub type {name}"));2185self.print_generics(lt);2186self.push_str(" = ");2187self.print_list(ty, mode);2188self.push_str(";\n");2189self.assert_type(id, &name);2190}2191}21922193fn type_stream(&mut self, id: TypeId, name: &str, ty: Option<&Type>, docs: &Docs) {2194self.rustdoc(docs);2195self.push_str(&format!("pub type {name}"));2196self.print_generics(None);2197self.push_str(" = ");2198self.print_stream(ty);2199self.push_str(";\n");2200self.assert_type(id, &name);2201}22022203fn type_future(&mut self, id: TypeId, name: &str, ty: Option<&Type>, docs: &Docs) {2204self.rustdoc(docs);2205self.push_str(&format!("pub type {name}"));2206self.print_generics(None);2207self.push_str(" = ");2208self.print_future(ty);2209self.push_str(";\n");2210self.assert_type(id, &name);2211}22122213fn print_result_ty(&mut self, result: Option<Type>, mode: TypeMode) {2214match result {2215Some(ty) => self.print_ty(&ty, mode),2216None => self.push_str("()"),2217}2218}22192220fn special_case_trappable_error(2221&mut self,2222func: &Function,2223) -> Option<(&'a Result_, TypeId, String)> {2224let result = func.result?;22252226// We fill in a special trappable error type in the case when a function has just one2227// result, which is itself a `result<a, e>`, and the `e` is *not* a primitive2228// (i.e. defined in std) type, and matches the typename given by the user.2229let id = match result {2230Type::Id(id) => id,2231_ => return None,2232};2233let result = match &self.resolve.types[id].kind {2234TypeDefKind::Result(r) => r,2235_ => return None,2236};2237let error_typeid = match result.err? {2238Type::Id(id) => resolve_type_definition_id(&self.resolve, id),2239_ => return None,2240};22412242let name = self.generator.trappable_errors.get(&error_typeid)?;22432244let mut path = self.path_to_root();2245uwrite!(path, "{name}");2246Some((result, error_typeid, path))2247}22482249fn generate_add_to_linker(&mut self, id: InterfaceId, name: &str) {2250let iface = &self.resolve.interfaces[id];2251let owner = TypeOwner::Interface(id);2252let wt = self.generator.wasmtime_path();22532254let mut required_conversion_traits = IndexSet::new();2255let extra_functions = {2256let mut functions = Vec::new();2257let mut errors_converted = IndexMap::new();2258let mut my_error_types = iface2259.types2260.iter()2261.filter(|(_, id)| self.generator.trappable_errors.contains_key(*id))2262.map(|(_, id)| *id)2263.collect::<Vec<_>>();2264my_error_types.extend(2265iface2266.functions2267.iter()2268.filter_map(|(_, func)| self.special_case_trappable_error(func))2269.map(|(_, id, _)| id),2270);2271for err_id in my_error_types {2272let err = &self.resolve.types[resolve_type_definition_id(self.resolve, err_id)];2273let err_name = err.name.as_ref().unwrap();2274let owner = match err.owner {2275TypeOwner::Interface(i) => i,2276_ => unimplemented!(),2277};2278match self.path_to_interface(owner) {2279Some(path) => {2280required_conversion_traits.insert(format!("{path}::Host"));2281}2282None => {2283if errors_converted.insert(err_name, err_id).is_none() {2284functions.push(ExtraTraitMethod::ErrorConvert {2285name: err_name,2286id: err_id,2287})2288}2289}2290}2291}2292functions2293};22942295// Generate the `pub trait` which represents the host functionality for2296// this import which additionally inherits from all resource traits2297// for this interface defined by `type_resource`.2298let generated_trait = self.generate_trait(2299"Host",2300&iface2301.functions2302.iter()2303.filter_map(|(_, f)| {2304if f.kind.resource().is_none() {2305Some(f)2306} else {2307None2308}2309})2310.collect::<Vec<_>>(),2311&extra_functions,2312&get_resources(self.resolve, id).collect::<Vec<_>>(),2313);23142315let opt_t_send_bound = if generated_trait2316.all_func_flags2317.contains(FunctionFlags::ASYNC)2318{2319"+ Send"2320} else {2321""2322};23232324let mut sync_bounds = "Host".to_string();23252326for ty in required_conversion_traits {2327uwrite!(sync_bounds, " + {ty}");2328}23292330let options_param = if self.generator.interface_link_options[&id].has_any() {2331"options: &LinkOptions,"2332} else {2333""2334};23352336uwriteln!(2337self.src,2338"2339pub fn add_to_linker<T, D>(2340linker: &mut {wt}::component::Linker<T>,2341{options_param}2342host_getter: fn(&mut T) -> D::Data<'_>,2343) -> {wt}::Result<()>2344where2345D: HostWithStore,2346for<'a> D::Data<'a>: {sync_bounds},2347T: 'static {opt_t_send_bound},2348{{2349"2350);23512352let gate = FeatureGate::open(&mut self.src, &iface.stability);2353uwriteln!(self.src, "let mut inst = linker.instance(\"{name}\")?;");23542355for (ty, _name) in get_resources(self.resolve, id) {2356self.generator.generate_add_resource_to_linker(2357self.current_interface.map(|p| p.1),2358Some(&mut self.src),2359"inst",2360self.resolve,2361ty,2362);2363}23642365for (_, func) in iface.functions.iter() {2366self.generate_add_function_to_linker(owner, func, "inst");2367}2368gate.close(&mut self.src);2369uwriteln!(self.src, "Ok(())");2370uwriteln!(self.src, "}}");2371}23722373fn import_resource_drop_flags(&mut self, name: &str) -> FunctionFlags {2374self.generator.opts.imports.resource_drop_flags(2375self.resolve,2376self.current_interface.map(|p| p.1),2377name,2378)2379}23802381fn generate_add_function_to_linker(&mut self, owner: TypeOwner, func: &Function, linker: &str) {2382let flags = self.generator.opts.imports.flags(2383self.resolve,2384self.current_interface.map(|p| p.1),2385func,2386);2387self.all_func_flags |= flags;2388let gate = FeatureGate::open(&mut self.src, &func.stability);2389uwrite!(2390self.src,2391"{linker}.{}(\"{}\", ",2392if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {2393"func_wrap_concurrent"2394} else if flags.contains(FunctionFlags::ASYNC) {2395"func_wrap_async"2396} else {2397"func_wrap"2398},2399func.name2400);2401self.generate_guest_import_closure(owner, func, flags);2402uwriteln!(self.src, ")?;");2403gate.close(&mut self.src);2404}24052406fn generate_guest_import_closure(2407&mut self,2408owner: TypeOwner,2409func: &Function,2410flags: FunctionFlags,2411) {2412// Generate the closure that's passed to a `Linker`, the final piece of2413// codegen here.24142415let wt = self.generator.wasmtime_path();2416if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {2417uwrite!(self.src, "move |caller: &{wt}::component::Accessor::<T>, (");2418} else {2419uwrite!(2420self.src,2421"move |mut caller: {wt}::StoreContextMut<'_, T>, ("2422);2423}2424for (i, _param) in func.params.iter().enumerate() {2425uwrite!(self.src, "arg{},", i);2426}2427self.src.push_str(") : (");24282429for (_, ty) in func.params.iter() {2430// Lift is required to be implied for this type, so we can't use2431// a borrowed type:2432self.print_ty(ty, TypeMode::Owned);2433self.src.push_str(", ");2434}2435self.src.push_str(")| {\n");24362437if flags.contains(FunctionFlags::TRACING) {2438if flags.contains(FunctionFlags::ASYNC) {2439self.src.push_str("use tracing::Instrument;\n");2440}24412442uwrite!(2443self.src,2444"2445let span = tracing::span!(2446tracing::Level::TRACE,2447\"wit-bindgen import\",2448module = \"{}\",2449function = \"{}\",2450);2451",2452match owner {2453TypeOwner::Interface(id) => self.resolve.interfaces[id]2454.name2455.as_deref()2456.unwrap_or("<no module>"),2457TypeOwner::World(id) => &self.resolve.worlds[id].name,2458TypeOwner::None => "<no owner>",2459},2460func.name,2461);2462}24632464if flags.contains(FunctionFlags::ASYNC) {2465let ctor = if flags.contains(FunctionFlags::STORE) {2466"pin"2467} else {2468"new"2469};2470uwriteln!(2471self.src,2472"{wt}::component::__internal::Box::{ctor}(async move {{"2473);2474} else {2475// Only directly enter the span if the function is sync. Otherwise2476// we use tracing::Instrument to ensure that the span is not entered2477// across an await point.2478if flags.contains(FunctionFlags::TRACING) {2479self.push_str("let _enter = span.enter();\n");2480}2481}24822483if flags.contains(FunctionFlags::TRACING) {2484let mut event_fields = func2485.params2486.iter()2487.enumerate()2488.map(|(i, (name, ty))| {2489let name = to_rust_ident(&name);2490formatting_for_arg(&name, i, *ty, &self.resolve, flags)2491})2492.collect::<Vec<String>>();2493event_fields.push(format!("\"call\""));2494uwrite!(2495self.src,2496"tracing::event!(tracing::Level::TRACE, {});\n",2497event_fields.join(", ")2498);2499}25002501if flags.contains(FunctionFlags::STORE) {2502if flags.contains(FunctionFlags::ASYNC) {2503uwriteln!(self.src, "let host = &caller.with_getter(host_getter);");2504} else {2505uwriteln!(2506self.src,2507"let host = {wt}::component::Access::new(caller, host_getter);"2508);2509}2510} else {2511self.src2512.push_str("let host = &mut host_getter(caller.data_mut());\n");2513}2514let func_name = rust_function_name(func);2515let host_trait = match func.kind.resource() {2516None => match owner {2517TypeOwner::World(id) => format!(2518"{}Imports",2519rust::to_rust_upper_camel_case(&self.resolve.worlds[id].name)2520),2521_ => "Host".to_string(),2522},2523Some(id) => {2524let resource = self.resolve.types[id]2525.name2526.as_ref()2527.unwrap()2528.to_upper_camel_case();2529format!("Host{resource}")2530}2531};25322533if flags.contains(FunctionFlags::STORE) {2534uwrite!(2535self.src,2536"let r = <D as {host_trait}WithStore>::{func_name}(host, "2537);2538} else {2539uwrite!(self.src, "let r = {host_trait}::{func_name}(host, ");2540}25412542for (i, _) in func.params.iter().enumerate() {2543uwrite!(self.src, "arg{},", i);2544}25452546self.src.push_str(if flags.contains(FunctionFlags::ASYNC) {2547").await;\n"2548} else {2549");\n"2550});25512552if flags.contains(FunctionFlags::TRACING) {2553uwrite!(2554self.src,2555"tracing::event!(tracing::Level::TRACE, {}, \"return\");",2556formatting_for_results(func.result, &self.resolve, flags)2557);2558}25592560if !flags.contains(FunctionFlags::TRAPPABLE) {2561if func.result.is_some() {2562uwrite!(self.src, "Ok((r,))\n");2563} else {2564uwrite!(self.src, "Ok(r)\n");2565}2566} else if let Some((_, err, _)) = self.special_case_trappable_error(func) {2567let err = &self.resolve.types[resolve_type_definition_id(self.resolve, err)];2568let err_name = err.name.as_ref().unwrap();2569let owner = match err.owner {2570TypeOwner::Interface(i) => i,2571_ => unimplemented!(),2572};2573let convert_trait = match self.path_to_interface(owner) {2574Some(path) => format!("{path}::Host"),2575None => format!("Host"),2576};2577let convert = format!("{}::convert_{}", convert_trait, err_name.to_snake_case());2578let convert = if flags.contains(FunctionFlags::STORE) {2579if flags.contains(FunctionFlags::ASYNC) {2580format!("host.with(|mut host| {convert}(&mut host.get(), e))?")2581} else {2582format!("{convert}(&mut host.get(), e)?")2583}2584} else {2585format!("{convert}(host, e)?")2586};2587uwrite!(2588self.src,2589"Ok((match r {{2590Ok(a) => Ok(a),2591Err(e) => Err({convert}),2592}},))"2593);2594} else if func.result.is_some() {2595uwrite!(self.src, "Ok((r?,))\n");2596} else {2597uwrite!(self.src, "r\n");2598}25992600if flags.contains(FunctionFlags::ASYNC) {2601if flags.contains(FunctionFlags::TRACING) {2602self.src.push_str("}.instrument(span))\n");2603} else {2604self.src.push_str("})\n");2605}2606}26072608self.src.push_str("}\n");2609}26102611fn generate_function_trait_sig(&mut self, func: &Function, flags: FunctionFlags) {2612let wt = self.generator.wasmtime_path();2613self.rustdoc(&func.docs);26142615self.push_str("fn ");2616self.push_str(&rust_function_name(func));2617if flags.contains(FunctionFlags::STORE | FunctionFlags::ASYNC) {2618uwrite!(2619self.src,2620"<T>(accessor: &{wt}::component::Accessor<T, Self>, "2621);2622} else if flags.contains(FunctionFlags::STORE) {2623uwrite!(self.src, "<T>(host: {wt}::component::Access<T, Self>, ");2624} else {2625self.push_str("(&mut self, ");2626}2627self.generate_function_params(func);2628self.push_str(")");2629self.push_str(" -> ");26302631if flags.contains(FunctionFlags::ASYNC) {2632uwrite!(self.src, "impl ::core::future::Future<Output = ");2633}26342635self.all_func_flags |= flags;2636self.generate_function_result(func, flags);26372638if flags.contains(FunctionFlags::ASYNC) {2639self.push_str("> + Send");2640}2641}26422643fn generate_function_params(&mut self, func: &Function) {2644for (name, param) in func.params.iter() {2645let name = to_rust_ident(name);2646self.push_str(&name);2647self.push_str(": ");2648self.print_ty(param, TypeMode::Owned);2649self.push_str(",");2650}2651}26522653fn generate_function_result(&mut self, func: &Function, flags: FunctionFlags) {2654if !flags.contains(FunctionFlags::TRAPPABLE) {2655self.print_result_ty(func.result, TypeMode::Owned);2656} else if let Some((r, _id, error_typename)) = self.special_case_trappable_error(func) {2657// Functions which have a single result `result<ok,err>` get special2658// cased to use the host_wasmtime_rust::Error<err>, making it possible2659// for them to trap or use `?` to propagate their errors2660self.push_str("Result<");2661if let Some(ok) = r.ok {2662self.print_ty(&ok, TypeMode::Owned);2663} else {2664self.push_str("()");2665}2666self.push_str(",");2667self.push_str(&error_typename);2668self.push_str(">");2669} else {2670// All other functions get their return values wrapped in an wasmtime::Result.2671// Returning the anyhow::Error case can be used to trap.2672let wt = self.generator.wasmtime_path();2673uwrite!(self.src, "{wt}::Result<");2674self.print_result_ty(func.result, TypeMode::Owned);2675self.push_str(">");2676}2677}26782679fn extract_typed_function(&mut self, func: &Function) -> (String, String) {2680let snake = func_field_name(self.resolve, func);2681let sig = self.typedfunc_sig(func, TypeMode::AllBorrowed("'_"));2682let extract =2683format!("*_instance.get_typed_func::<{sig}>(&mut store, &self.{snake})?.func()");2684(snake, extract)2685}26862687fn define_rust_guest_export(2688&mut self,2689resolve: &Resolve,2690ns: Option<&WorldKey>,2691func: &Function,2692) {2693let flags = self.generator.opts.exports.flags(resolve, ns, func);2694let (async_, async__, await_) = if flags.contains(FunctionFlags::ASYNC) {2695("async", "_async", ".await")2696} else {2697("", "", "")2698};26992700self.rustdoc(&func.docs);2701let wt = self.generator.wasmtime_path();27022703uwrite!(2704self.src,2705"pub {async_} fn call_{}",2706func.item_name().to_snake_case(),2707);2708if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {2709uwrite!(2710self.src,2711"<_T, _D>(&self, accessor: &{wt}::component::Accessor<_T, _D>, ",2712);2713} else {2714uwrite!(self.src, "<S: {wt}::AsContextMut>(&self, mut store: S, ",);2715}27162717let param_mode = if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {2718TypeMode::Owned2719} else {2720TypeMode::AllBorrowed("'_")2721};27222723for (i, param) in func.params.iter().enumerate() {2724uwrite!(self.src, "arg{}: ", i);2725self.print_ty(¶m.1, param_mode);2726self.push_str(",");2727}27282729uwrite!(self.src, ") -> {wt}::Result<");2730self.print_result_ty(func.result, TypeMode::Owned);2731uwrite!(self.src, ">");27322733if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {2734uwrite!(self.src, " where _T: Send, _D: {wt}::component::HasData");2735} else if flags.contains(FunctionFlags::ASYNC) {2736uwrite!(self.src, " where <S as {wt}::AsContext>::Data: Send");2737}2738uwrite!(self.src, "{{\n");27392740if flags.contains(FunctionFlags::TRACING) {2741if flags.contains(FunctionFlags::ASYNC) {2742self.src.push_str("use tracing::Instrument;\n");2743}27442745let ns = match ns {2746Some(key) => resolve.name_world_key(key),2747None => "default".to_string(),2748};2749self.src.push_str(&format!(2750"2751let span = tracing::span!(2752tracing::Level::TRACE,2753\"wit-bindgen export\",2754module = \"{ns}\",2755function = \"{}\",2756);2757",2758func.name,2759));27602761if !flags.contains(FunctionFlags::ASYNC) {2762self.src.push_str(2763"2764let _enter = span.enter();2765",2766);2767}2768}27692770self.src.push_str("let callee = unsafe {\n");2771uwrite!(2772self.src,2773"{wt}::component::TypedFunc::<{}>",2774self.typedfunc_sig(func, param_mode)2775);2776let projection_to_func = if func.kind.resource().is_some() {2777".funcs"2778} else {2779""2780};2781uwriteln!(2782self.src,2783"::new_unchecked(self{projection_to_func}.{})",2784func_field_name(self.resolve, func),2785);2786self.src.push_str("};\n");27872788self.src.push_str("let (");2789if func.result.is_some() {2790uwrite!(self.src, "ret0,");2791}2792if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {2793uwrite!(self.src, ") = callee.call_concurrent(accessor, (");2794} else {2795uwrite!(2796self.src,2797") = callee.call{async__}(store.as_context_mut(), ("2798);2799}2800for (i, _) in func.params.iter().enumerate() {2801uwrite!(self.src, "arg{}, ", i);2802}28032804let instrument = if flags.contains(FunctionFlags::ASYNC | FunctionFlags::TRACING) {2805".instrument(span.clone())"2806} else {2807""2808};2809uwriteln!(self.src, ")){instrument}{await_}?;");28102811let instrument = if flags.contains(FunctionFlags::ASYNC | FunctionFlags::TRACING) {2812".instrument(span)"2813} else {2814""2815};28162817if !flags.contains(FunctionFlags::STORE) {2818uwriteln!(2819self.src,2820"callee.post_return{async__}(store.as_context_mut()){instrument}{await_}?;"2821);2822}28232824self.src.push_str("Ok(");2825if func.result.is_some() {2826self.src.push_str("ret0");2827} else {2828self.src.push_str("()");2829}2830self.src.push_str(")\n");28312832// End function body2833self.src.push_str("}\n");2834}28352836fn rustdoc(&mut self, docs: &Docs) {2837let docs = match &docs.contents {2838Some(docs) => docs,2839None => return,2840};2841for line in docs.trim().lines() {2842self.push_str("/// ");2843self.push_str(line);2844self.push_str("\n");2845}2846}28472848fn path_to_root(&self) -> String {2849let mut path_to_root = String::new();2850if let Some((_, key, is_export)) = self.current_interface {2851match key {2852WorldKey::Name(_) => {2853path_to_root.push_str("super::");2854}2855WorldKey::Interface(_) => {2856path_to_root.push_str("super::super::super::");2857}2858}2859if is_export {2860path_to_root.push_str("super::");2861}2862}2863path_to_root2864}28652866fn partition_concurrent_funcs<'b>(2867&mut self,2868funcs: impl IntoIterator<Item = &'b Function>,2869) -> FunctionPartitioning<'b> {2870let key = self.current_interface.map(|p| p.1);2871let (with_store, without_store) = funcs2872.into_iter()2873.map(|func| {2874let flags = self.generator.opts.imports.flags(self.resolve, key, func);2875(func, flags)2876})2877.partition(|(_, flags)| flags.contains(FunctionFlags::STORE));2878FunctionPartitioning {2879with_store,2880without_store,2881}2882}28832884fn generate_trait(2885&mut self,2886trait_name: &str,2887functions: &[&Function],2888extra_functions: &[ExtraTraitMethod<'_>],2889resources: &[(TypeId, &str)],2890) -> GeneratedTrait {2891let mut ret = GeneratedTrait::default();2892let wt = self.generator.wasmtime_path();2893let partition = self.partition_concurrent_funcs(functions.iter().copied());28942895for (_, flags) in partition.with_store.iter().chain(&partition.without_store) {2896ret.all_func_flags |= *flags;2897}28982899let mut with_store_supertraits = vec![format!("{wt}::component::HasData")];2900let mut without_store_supertraits = vec![];2901for (id, name) in resources {2902let camel = name.to_upper_camel_case();2903without_store_supertraits.push(format!("Host{camel}"));2904let funcs = self.partition_concurrent_funcs(get_resource_functions(self.resolve, *id));2905for (_, flags) in funcs.with_store.iter().chain(&funcs.without_store) {2906ret.all_func_flags |= *flags;2907}2908ret.all_func_flags |= self.import_resource_drop_flags(name);2909with_store_supertraits.push(format!("Host{camel}WithStore"));2910}2911if ret.all_func_flags.contains(FunctionFlags::ASYNC) {2912with_store_supertraits.push("Send".to_string());2913without_store_supertraits.push("Send".to_string());2914}29152916uwriteln!(2917self.src,2918"pub trait {trait_name}WithStore: {} {{",2919with_store_supertraits.join(" + "),2920);2921ret.with_store_name = Some(format!("{trait_name}WithStore"));29222923let mut extra_with_store_function = false;2924for extra in extra_functions {2925match extra {2926ExtraTraitMethod::ResourceDrop { name } => {2927let flags = self.import_resource_drop_flags(name);2928if !flags.contains(FunctionFlags::STORE) {2929continue;2930}2931let camel = name.to_upper_camel_case();29322933if flags.contains(FunctionFlags::ASYNC) {2934uwrite!(2935self.src,2936"2937fn drop<T>(accessor: &{wt}::component::Accessor<T, Self>, rep: {wt}::component::Resource<{camel}>)2938-> impl ::core::future::Future<Output = {wt}::Result<()>> + Send where Self: Sized;2939"2940);2941} else {2942uwrite!(2943self.src,2944"2945fn drop<T>(accessor: {wt}::component::Access<T, Self>, rep: {wt}::component::Resource<{camel}>)2946-> {wt}::Result<()>;2947"2948);2949}29502951extra_with_store_function = true;2952}2953ExtraTraitMethod::ErrorConvert { .. } => {}2954}2955}29562957for (func, flags) in partition.with_store.iter() {2958self.generate_function_trait_sig(func, *flags);2959self.push_str(";\n");2960}2961uwriteln!(self.src, "}}");29622963// If `*WithStore` is empty, generate a blanket impl for the trait since2964// it's otherwise not necessary to implement it manually.2965if partition.with_store.is_empty() && !extra_with_store_function {2966uwriteln!(self.src, "impl<_T: ?Sized> {trait_name}WithStore for _T");2967uwriteln!(2968self.src,2969" where _T: {}",2970with_store_supertraits.join(" + ")2971);29722973uwriteln!(self.src, "{{}}");2974}29752976uwriteln!(2977self.src,2978"pub trait {trait_name}: {} {{",2979without_store_supertraits.join(" + ")2980);2981ret.name = trait_name.to_string();2982for (func, flags) in partition.without_store.iter() {2983self.generate_function_trait_sig(func, *flags);2984self.push_str(";\n");2985}29862987for extra in extra_functions {2988match extra {2989ExtraTraitMethod::ResourceDrop { name } => {2990let flags = self.import_resource_drop_flags(name);2991ret.all_func_flags |= flags;2992if flags.contains(FunctionFlags::STORE) {2993continue;2994}2995let camel = name.to_upper_camel_case();2996uwrite!(2997self.src,2998"fn drop(&mut self, rep: {wt}::component::Resource<{camel}>) -> "2999);3000if flags.contains(FunctionFlags::ASYNC) {3001uwrite!(self.src, "impl ::core::future::Future<Output =");3002}3003uwrite!(self.src, "{wt}::Result<()>");3004if flags.contains(FunctionFlags::ASYNC) {3005uwrite!(self.src, "> + Send");3006}3007uwrite!(self.src, ";");3008}3009ExtraTraitMethod::ErrorConvert { name, id } => {3010let root = self.path_to_root();3011let custom_name = &self.generator.trappable_errors[id];3012let snake = name.to_snake_case();3013let camel = name.to_upper_camel_case();3014uwriteln!(3015self.src,3016"3017fn convert_{snake}(&mut self, err: {root}{custom_name}) -> {wt}::Result<{camel}>;3018"3019);3020}3021}3022}30233024uwriteln!(self.src, "}}");30253026if self.generator.opts.skip_mut_forwarding_impls {3027return ret;3028}30293030// Generate impl HostResource for &mut HostResource3031let maybe_send = if ret.all_func_flags.contains(FunctionFlags::ASYNC) {3032"+ Send"3033} else {3034""3035};3036uwriteln!(3037self.src,3038"impl <_T: {trait_name} + ?Sized {maybe_send}> {trait_name} for &mut _T {{"3039);3040for (func, flags) in partition.without_store.iter() {3041self.generate_function_trait_sig(func, *flags);3042uwriteln!(self.src, "{{");3043if flags.contains(FunctionFlags::ASYNC) {3044uwriteln!(self.src, "async move {{");3045}3046uwrite!(3047self.src,3048"{trait_name}::{}(*self,",3049rust_function_name(func)3050);3051for (name, _) in func.params.iter() {3052uwrite!(self.src, "{},", to_rust_ident(name));3053}3054uwrite!(self.src, ")");3055if flags.contains(FunctionFlags::ASYNC) {3056uwrite!(self.src, ".await\n}}");3057}3058uwriteln!(self.src, "}}");3059}3060for extra in extra_functions {3061match extra {3062ExtraTraitMethod::ResourceDrop { name } => {3063let flags = self.import_resource_drop_flags(name);3064if flags.contains(FunctionFlags::STORE) {3065continue;3066}3067let camel = name.to_upper_camel_case();3068let mut await_ = "";3069if flags.contains(FunctionFlags::ASYNC) {3070self.src.push_str("async ");3071await_ = ".await";3072}3073uwriteln!(3074self.src,3075"3076fn drop(&mut self, rep: {wt}::component::Resource<{camel}>) -> {wt}::Result<()> {{3077{trait_name}::drop(*self, rep){await_}3078}}3079",3080);3081}3082ExtraTraitMethod::ErrorConvert { name, id } => {3083let root = self.path_to_root();3084let custom_name = &self.generator.trappable_errors[id];3085let snake = name.to_snake_case();3086let camel = name.to_upper_camel_case();3087uwriteln!(3088self.src,3089"3090fn convert_{snake}(&mut self, err: {root}{custom_name}) -> {wt}::Result<{camel}> {{3091{trait_name}::convert_{snake}(*self, err)3092}}3093",3094);3095}3096}3097}3098uwriteln!(self.src, "}}");30993100ret3101}3102}31033104enum ExtraTraitMethod<'a> {3105ResourceDrop { name: &'a str },3106ErrorConvert { name: &'a str, id: TypeId },3107}31083109struct FunctionPartitioning<'a> {3110without_store: Vec<(&'a Function, FunctionFlags)>,3111with_store: Vec<(&'a Function, FunctionFlags)>,3112}31133114#[derive(Default)]3115struct GeneratedTrait {3116name: String,3117with_store_name: Option<String>,3118all_func_flags: FunctionFlags,3119}31203121impl<'a> RustGenerator<'a> for InterfaceGenerator<'a> {3122fn resolve(&self) -> &'a Resolve {3123self.resolve3124}31253126fn ownership(&self) -> Ownership {3127self.generator.opts.ownership3128}31293130fn path_to_interface(&self, interface: InterfaceId) -> Option<String> {3131if let Some((cur, _, _)) = self.current_interface {3132if cur == interface {3133return None;3134}3135}3136let mut path_to_root = self.path_to_root();3137match &self.generator.interface_names[&interface] {3138InterfaceName::Remapped { name_at_root, .. } => path_to_root.push_str(name_at_root),3139InterfaceName::Path(path) => {3140for (i, name) in path.iter().enumerate() {3141if i > 0 {3142path_to_root.push_str("::");3143}3144path_to_root.push_str(name);3145}3146}3147}3148Some(path_to_root)3149}31503151fn push_str(&mut self, s: &str) {3152self.src.push_str(s);3153}31543155fn info(&self, ty: TypeId) -> TypeInfo {3156self.generator.types.get(ty)3157}31583159fn is_imported_interface(&self, interface: InterfaceId) -> bool {3160self.generator.interface_last_seen_as_import[&interface]3161}31623163fn wasmtime_path(&self) -> String {3164self.generator.wasmtime_path()3165}3166}31673168#[derive(Default)]3169struct LinkOptionsBuilder {3170unstable_features: BTreeSet<String>,3171}3172impl LinkOptionsBuilder {3173fn has_any(&self) -> bool {3174!self.unstable_features.is_empty()3175}3176fn add_world(&mut self, resolve: &Resolve, id: &WorldId) {3177let world = &resolve.worlds[*id];31783179self.add_stability(&world.stability);31803181for (_, import) in world.imports.iter() {3182match import {3183WorldItem::Interface { id, stability } => {3184self.add_stability(stability);3185self.add_interface(resolve, id);3186}3187WorldItem::Function(f) => {3188self.add_stability(&f.stability);3189}3190WorldItem::Type(t) => {3191self.add_type(resolve, t);3192}3193}3194}3195}3196fn add_interface(&mut self, resolve: &Resolve, id: &InterfaceId) {3197let interface = &resolve.interfaces[*id];31983199self.add_stability(&interface.stability);32003201for (_, t) in interface.types.iter() {3202self.add_type(resolve, t);3203}3204for (_, f) in interface.functions.iter() {3205self.add_stability(&f.stability);3206}3207}3208fn add_type(&mut self, resolve: &Resolve, id: &TypeId) {3209let t = &resolve.types[*id];3210self.add_stability(&t.stability);3211}3212fn add_stability(&mut self, stability: &Stability) {3213match stability {3214Stability::Unstable { feature, .. } => {3215self.unstable_features.insert(feature.clone());3216}3217Stability::Stable { .. } | Stability::Unknown => {}3218}3219}3220fn write_struct(&self, src: &mut Source) {3221if !self.has_any() {3222return;3223}32243225let mut unstable_features = self.unstable_features.iter().cloned().collect::<Vec<_>>();3226unstable_features.sort();32273228uwriteln!(3229src,3230"3231/// Link-time configurations.3232#[derive(Clone, Debug, Default)]3233pub struct LinkOptions {{3234"3235);32363237for feature in unstable_features.iter() {3238let feature_rust_name = feature.to_snake_case();3239uwriteln!(src, "{feature_rust_name}: bool,");3240}32413242uwriteln!(src, "}}");3243uwriteln!(src, "impl LinkOptions {{");32443245for feature in unstable_features.iter() {3246let feature_rust_name = feature.to_snake_case();3247uwriteln!(3248src,3249"3250/// Enable members marked as `@unstable(feature = {feature})`3251pub fn {feature_rust_name}(&mut self, enabled: bool) -> &mut Self {{3252self.{feature_rust_name} = enabled;3253self3254}}3255"3256);3257}32583259uwriteln!(src, "}}");3260}3261fn write_impl_from_world(&self, src: &mut Source, path: &str) {3262if !self.has_any() {3263return;3264}32653266let mut unstable_features = self.unstable_features.iter().cloned().collect::<Vec<_>>();3267unstable_features.sort();32683269uwriteln!(3270src,3271"3272impl core::convert::From<LinkOptions> for {path}::LinkOptions {{3273fn from(src: LinkOptions) -> Self {{3274(&src).into()3275}}3276}}32773278impl core::convert::From<&LinkOptions> for {path}::LinkOptions {{3279fn from(src: &LinkOptions) -> Self {{3280let mut dest = Self::default();3281"3282);32833284for feature in unstable_features.iter() {3285let feature_rust_name = feature.to_snake_case();3286uwriteln!(src, "dest.{feature_rust_name}(src.{feature_rust_name});");3287}32883289uwriteln!(3290src,3291"3292dest3293}}3294}}3295"3296);3297}3298}32993300struct FeatureGate {3301close: bool,3302}3303impl FeatureGate {3304fn open(src: &mut Source, stability: &Stability) -> FeatureGate {3305let close = if let Stability::Unstable { feature, .. } = stability {3306let feature_rust_name = feature.to_snake_case();3307uwrite!(src, "if options.{feature_rust_name} {{");3308true3309} else {3310false3311};3312Self { close }3313}33143315fn close(self, src: &mut Source) {3316if self.close {3317uwriteln!(src, "}}");3318}3319}3320}33213322/// Produce a string for tracing a function argument.3323fn formatting_for_arg(3324name: &str,3325index: usize,3326ty: Type,3327resolve: &Resolve,3328flags: FunctionFlags,3329) -> String {3330if !flags.contains(FunctionFlags::VERBOSE_TRACING) && type_contains_lists(ty, resolve) {3331return format!("{name} = tracing::field::debug(\"...\")");3332}33333334// Normal tracing.3335format!("{name} = tracing::field::debug(&arg{index})")3336}33373338/// Produce a string for tracing function results.3339fn formatting_for_results(result: Option<Type>, resolve: &Resolve, flags: FunctionFlags) -> String {3340let contains_lists = match result {3341Some(ty) => type_contains_lists(ty, resolve),3342None => false,3343};33443345if !flags.contains(FunctionFlags::VERBOSE_TRACING) && contains_lists {3346return format!("result = tracing::field::debug(\"...\")");3347}33483349// Normal tracing.3350format!("result = tracing::field::debug(&r)")3351}33523353/// Test whether the given type contains lists.3354///3355/// Here, a `string` is not considered a list.3356fn type_contains_lists(ty: Type, resolve: &Resolve) -> bool {3357match ty {3358Type::Id(id) => match &resolve.types[id].kind {3359TypeDefKind::Resource3360| TypeDefKind::Unknown3361| TypeDefKind::Flags(_)3362| TypeDefKind::Handle(_)3363| TypeDefKind::Enum(_)3364| TypeDefKind::Stream(_)3365| TypeDefKind::Future(_) => false,3366TypeDefKind::Option(ty) => type_contains_lists(*ty, resolve),3367TypeDefKind::Result(Result_ { ok, err }) => {3368option_type_contains_lists(*ok, resolve)3369|| option_type_contains_lists(*err, resolve)3370}3371TypeDefKind::Record(record) => record3372.fields3373.iter()3374.any(|field| type_contains_lists(field.ty, resolve)),3375TypeDefKind::Tuple(tuple) => tuple3376.types3377.iter()3378.any(|ty| type_contains_lists(*ty, resolve)),3379TypeDefKind::Variant(variant) => variant3380.cases3381.iter()3382.any(|case| option_type_contains_lists(case.ty, resolve)),3383TypeDefKind::Type(ty) => type_contains_lists(*ty, resolve),3384TypeDefKind::List(_) => true,3385TypeDefKind::FixedSizeList(..) => todo!(),3386},33873388// Technically strings are lists too, but we ignore that here because3389// they're usually short.3390_ => false,3391}3392}33933394fn option_type_contains_lists(ty: Option<Type>, resolve: &Resolve) -> bool {3395match ty {3396Some(ty) => type_contains_lists(ty, resolve),3397None => false,3398}3399}34003401/// When an interface `use`s a type from another interface, it creates a new TypeId3402/// referring to the definition TypeId. Chase this chain of references down to3403/// a TypeId for type's definition.3404fn resolve_type_definition_id(resolve: &Resolve, mut id: TypeId) -> TypeId {3405loop {3406match resolve.types[id].kind {3407TypeDefKind::Type(Type::Id(def_id)) => id = def_id,3408_ => return id,3409}3410}3411}34123413fn rust_function_name(func: &Function) -> String {3414match func.kind {3415FunctionKind::Constructor(_) => "new".to_string(),3416FunctionKind::Method(_)3417| FunctionKind::Static(_)3418| FunctionKind::AsyncMethod(_)3419| FunctionKind::AsyncStatic(_)3420| FunctionKind::Freestanding3421| FunctionKind::AsyncFreestanding => to_rust_ident(func.item_name()),3422}3423}34243425fn func_field_name(resolve: &Resolve, func: &Function) -> String {3426let mut name = String::new();3427match func.kind {3428FunctionKind::Method(id) | FunctionKind::AsyncMethod(id) => {3429name.push_str("method-");3430name.push_str(resolve.types[id].name.as_ref().unwrap());3431name.push_str("-");3432}3433FunctionKind::Static(id) | FunctionKind::AsyncStatic(id) => {3434name.push_str("static-");3435name.push_str(resolve.types[id].name.as_ref().unwrap());3436name.push_str("-");3437}3438FunctionKind::Constructor(id) => {3439name.push_str("constructor-");3440name.push_str(resolve.types[id].name.as_ref().unwrap());3441name.push_str("-");3442}3443FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {}3444}3445name.push_str(func.item_name());3446name.to_snake_case()3447}34483449fn get_resources<'a>(3450resolve: &'a Resolve,3451id: InterfaceId,3452) -> impl Iterator<Item = (TypeId, &'a str)> + 'a {3453resolve.interfaces[id]3454.types3455.iter()3456.filter_map(move |(name, ty)| match &resolve.types[*ty].kind {3457TypeDefKind::Resource => Some((*ty, name.as_str())),3458_ => None,3459})3460}34613462fn get_resource_functions<'a>(resolve: &'a Resolve, resource_id: TypeId) -> Vec<&'a Function> {3463let resource = &resolve.types[resource_id];3464match resource.owner {3465TypeOwner::World(id) => resolve.worlds[id]3466.imports3467.values()3468.filter_map(|item| match item {3469WorldItem::Function(f) => Some(f),3470_ => None,3471})3472.filter(|f| f.kind.resource() == Some(resource_id))3473.collect(),3474TypeOwner::Interface(id) => resolve.interfaces[id]3475.functions3476.values()3477.filter(|f| f.kind.resource() == Some(resource_id))3478.collect::<Vec<_>>(),3479TypeOwner::None => {3480panic!("A resource must be owned by a world or interface");3481}3482}3483}34843485fn get_world_resources<'a>(3486resolve: &'a Resolve,3487id: WorldId,3488) -> impl Iterator<Item = (TypeId, &'a str)> + 'a {3489resolve.worlds[id]3490.imports3491.iter()3492.filter_map(move |(name, item)| match item {3493WorldItem::Type(id) => match resolve.types[*id].kind {3494TypeDefKind::Resource => Some(match name {3495WorldKey::Name(s) => (*id, s.as_str()),3496WorldKey::Interface(_) => unreachable!(),3497}),3498_ => None,3499},3500_ => None,3501})3502}350335043505