1 //! > **⚠️ Warning ⚠️**: this crate is an internal-only crate for the Wasmtime
2 //! > project and is not intended for general use. APIs are not strictly
3 //! > reviewed for safety and usage outside of Wasmtime may have bugs. If
4 //! > you're interested in using this feel free to file an issue on the
5 //! > Wasmtime repository to start a discussion about doing so, but otherwise
6 //! > be aware that your usage of this crate is not supported.
7
8 use crate::rust::{RustGenerator, TypeMode, to_rust_ident, to_rust_upper_camel_case};
9 use crate::types::{TypeInfo, Types};
10 use anyhow::bail;
11 use heck::*;
12 use indexmap::{IndexMap, IndexSet};
13 use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
14 use std::fmt::Write as _;
15 use std::io::{Read, Write};
16 use std::mem;
17 use std::process::{Command, Stdio};
18 use wit_parser::*;
19
20 macro_rules! uwrite {
21 ($dst:expr, $($arg:tt)*) => {
22 write!($dst, $($arg)*).unwrap()
23 };
24 }
25
26 macro_rules! uwriteln {
27 ($dst:expr, $($arg:tt)*) => {
28 writeln!($dst, $($arg)*).unwrap()
29 };
30 }
31
32 mod config;
33 mod rust;
34 mod source;
35 mod types;
36
37 pub use config::{FunctionConfig, FunctionFilter, FunctionFlags};
38 use source::Source;
39
40 #[derive(Clone)]
41 enum InterfaceName {
42 /// This interface was remapped using `with` to some other Rust code.
43 Remapped {
44 /// This is the `::`-separated string which is the path to the mapped
45 /// item relative to the root of the `bindgen!` macro invocation.
46 ///
47 /// This path currently starts with `__with_name$N` and will then
48 /// optionally have `::` projections through to the actual item
49 /// depending on how `with` was configured.
50 name_at_root: String,
51
52 /// This is currently only used for exports and is the relative path to
53 /// where this mapped name would be located if `with` were not
54 /// specified. Basically it's the same as the `Path` variant of this
55 /// enum if the mapping weren't present.
56 local_path: Vec<String>,
57 },
58
59 /// This interface is generated in the module hierarchy specified.
60 ///
61 /// The path listed here is the path, from the root of the `bindgen!` macro,
62 /// to where this interface is generated.
63 Path(Vec<String>),
64 }
65
66 #[derive(Default)]
67 struct Wasmtime {
68 src: Source,
69 opts: Opts,
70 /// A list of all interfaces which were imported by this world.
71 import_interfaces: Vec<ImportInterface>,
72 import_functions: Vec<Function>,
73 exports: Exports,
74 types: Types,
75 sizes: SizeAlign,
76 interface_names: HashMap<InterfaceId, InterfaceName>,
77 interface_last_seen_as_import: HashMap<InterfaceId, bool>,
78 trappable_errors: IndexMap<TypeId, String>,
79 // Track the with options that were used. Remapped interfaces provided via `with`
80 // are required to be used.
81 used_with_opts: HashSet<String>,
82 world_link_options: LinkOptionsBuilder,
83 interface_link_options: HashMap<InterfaceId, LinkOptionsBuilder>,
84 }
85
86 struct ImportInterface {
87 id: InterfaceId,
88 contents: String,
89 name: InterfaceName,
90 all_func_flags: FunctionFlags,
91 }
92
93 #[derive(Default)]
94 struct Exports {
95 fields: BTreeMap<String, ExportField>,
96 modules: Vec<(InterfaceId, String, InterfaceName)>,
97 funcs: Vec<String>,
98 }
99
100 struct ExportField {
101 ty: String,
102 ty_index: String,
103 load: String,
104 get_index: String,
105 }
106
107 #[derive(Default, Debug, Clone, Copy)]
108 pub enum Ownership {
109 /// Generated types will be composed entirely of owning fields, regardless
110 /// of whether they are used as parameters to guest exports or not.
111 #[default]
112 Owning,
113
114 /// Generated types used as parameters to guest exports will be "deeply
115 /// borrowing", i.e. contain references rather than owned values when
116 /// applicable.
117 Borrowing {
118 /// Whether or not to generate "duplicate" type definitions for a single
119 /// WIT type if necessary, for example if it's used as both an import
120 /// and an export, or if it's used both as a parameter to an export and
121 /// a return value from an export.
122 duplicate_if_necessary: bool,
123 },
124 }
125
126 #[derive(Default, Debug, Clone)]
127 pub struct Opts {
128 /// Whether or not `rustfmt` is executed to format generated code.
129 pub rustfmt: bool,
130
131 /// A list of "trappable errors" which are used to replace the `E` in
132 /// `result<T, E>` found in WIT.
133 pub trappable_error_type: Vec<TrappableError>,
134
135 /// Whether to generate owning or borrowing type definitions.
136 pub ownership: Ownership,
137
138 /// Whether or not to generate code for only the interfaces of this wit file or not.
139 pub only_interfaces: bool,
140
141 /// Remapping of interface names to rust module names.
142 /// TODO: is there a better type to use for the value of this map?
143 pub with: HashMap<String, String>,
144
145 /// Additional derive attributes to add to generated types. If using in a CLI, this flag can be
146 /// specified multiple times to add multiple attributes.
147 ///
148 /// These derive attributes will be added to any generated structs or enums
149 pub additional_derive_attributes: Vec<String>,
150
151 /// Evaluate to a string literal containing the generated code rather than the generated tokens
152 /// themselves. Mostly useful for Wasmtime internal debugging and development.
153 pub stringify: bool,
154
155 /// Temporary option to skip `impl<T: Trait> Trait for &mut T` for the
156 /// `wasmtime-wasi` crate while that's given a chance to update its b
157 /// indings.
158 pub skip_mut_forwarding_impls: bool,
159
160 /// Indicates that the `T` in `Store<T>` should be send even if async is not
161 /// enabled.
162 ///
163 /// This is helpful when sync bindings depend on generated functions from
164 /// async bindings as is the case with WASI in-tree.
165 pub require_store_data_send: bool,
166
167 /// Path to the `wasmtime` crate if it's not the default path.
168 pub wasmtime_crate: Option<String>,
169
170 /// Whether to use `anyhow::Result` for trappable host-defined function
171 /// imports.
172 ///
173 /// By default, `wasmtime::Result` is used instead of `anyhow::Result`.
174 ///
175 /// When enabled, the generated code requires the `"anyhow"` cargo feature
176 /// to also be enabled in the `wasmtime` crate.
177 pub anyhow: bool,
178
179 /// If true, write the generated bindings to a file for better error
180 /// messages from `rustc`.
181 ///
182 /// This can also be toggled via the `WASMTIME_DEBUG_BINDGEN` environment
183 /// variable, but that will affect _all_ `bindgen!` macro invocations (and
184 /// can sometimes lead to one invocation overwriting another in unpredictable
185 /// ways), whereas this option lets you specify it on a case-by-case basis.
186 pub debug: bool,
187
188 /// TODO
189 pub imports: FunctionConfig,
190 /// TODO
191 pub exports: FunctionConfig,
192 }
193
194 #[derive(Debug, Clone)]
195 pub struct TrappableError {
196 /// Full path to the error, such as `wasi:io/streams.error`.
197 pub wit_path: String,
198
199 /// The name, in Rust, of the error type to generate.
200 pub rust_type_name: String,
201 }
202
203 impl Opts {
generate(&self, resolve: &Resolve, world: WorldId) -> anyhow::Result<String>204 pub fn generate(&self, resolve: &Resolve, world: WorldId) -> anyhow::Result<String> {
205 // TODO: Should we refine this test to inspect only types reachable from
206 // the specified world?
207 if !cfg!(feature = "component-model-async")
208 && resolve
209 .types
210 .iter()
211 .any(|(_, ty)| matches!(ty.kind, TypeDefKind::Future(_) | TypeDefKind::Stream(_)))
212 {
213 anyhow::bail!(
214 "must enable `component-model-async` feature when using WIT files \
215 containing future, stream, or error-context types"
216 );
217 }
218
219 let mut r = Wasmtime::default();
220 r.sizes.fill(resolve);
221 r.opts = self.clone();
222 r.populate_world_and_interface_options(resolve, world);
223 r.generate(resolve, world)
224 }
225 }
226
227 impl Wasmtime {
populate_world_and_interface_options(&mut self, resolve: &Resolve, world: WorldId)228 fn populate_world_and_interface_options(&mut self, resolve: &Resolve, world: WorldId) {
229 self.world_link_options.add_world(resolve, &world);
230
231 for (_, import) in resolve.worlds[world].imports.iter() {
232 match import {
233 WorldItem::Interface { id, .. } => {
234 let mut o = LinkOptionsBuilder::default();
235 o.add_interface(resolve, id);
236 self.interface_link_options.insert(*id, o);
237 }
238 WorldItem::Function(_) | WorldItem::Type { .. } => {}
239 }
240 }
241 }
name_interface( &mut self, resolve: &Resolve, id: InterfaceId, name: &WorldKey, is_export: bool, ) -> bool242 fn name_interface(
243 &mut self,
244 resolve: &Resolve,
245 id: InterfaceId,
246 name: &WorldKey,
247 is_export: bool,
248 ) -> bool {
249 let mut path = Vec::new();
250 if is_export {
251 path.push("exports".to_string());
252 }
253 match name {
254 WorldKey::Name(name) => {
255 path.push(name.to_snake_case());
256 }
257 WorldKey::Interface(_) => {
258 let iface = &resolve.interfaces[id];
259 let pkgname = &resolve.packages[iface.package.unwrap()].name;
260 path.push(pkgname.namespace.to_snake_case());
261 path.push(self.name_package_module(resolve, iface.package.unwrap()));
262 path.push(to_rust_ident(iface.name.as_ref().unwrap()));
263 }
264 }
265 let entry = if let Some(name_at_root) = self.lookup_replacement(resolve, name, None) {
266 InterfaceName::Remapped {
267 name_at_root,
268 local_path: path,
269 }
270 } else {
271 InterfaceName::Path(path)
272 };
273
274 let remapped = matches!(entry, InterfaceName::Remapped { .. });
275 self.interface_names.insert(id, entry);
276 remapped
277 }
278
279 /// If the package `id` is the only package with its namespace/name combo
280 /// then pass through the name unmodified. If, however, there are multiple
281 /// versions of this package then the package module is going to get version
282 /// information.
name_package_module(&self, resolve: &Resolve, id: PackageId) -> String283 fn name_package_module(&self, resolve: &Resolve, id: PackageId) -> String {
284 let pkg = &resolve.packages[id];
285 let versions_with_same_name = resolve
286 .packages
287 .iter()
288 .filter_map(|(_, p)| {
289 if p.name.namespace == pkg.name.namespace && p.name.name == pkg.name.name {
290 Some(&p.name.version)
291 } else {
292 None
293 }
294 })
295 .collect::<Vec<_>>();
296 let base = pkg.name.name.to_snake_case();
297 if versions_with_same_name.len() == 1 {
298 return base;
299 }
300
301 let version = match &pkg.name.version {
302 Some(version) => version,
303 // If this package didn't have a version then don't mangle its name
304 // and other packages with the same name but with versions present
305 // will have their names mangled.
306 None => return base,
307 };
308
309 // Here there's multiple packages with the same name that differ only in
310 // version, so the version needs to be mangled into the Rust module name
311 // that we're generating. This in theory could look at all of
312 // `versions_with_same_name` and produce a minimal diff, e.g. for 0.1.0
313 // and 0.2.0 this could generate "foo1" and "foo2", but for now
314 // a simpler path is chosen to generate "foo0_1_0" and "foo0_2_0".
315 let version = version
316 .to_string()
317 .replace('.', "_")
318 .replace('-', "_")
319 .replace('+', "_")
320 .to_snake_case();
321 format!("{base}{version}")
322 }
323
generate(&mut self, resolve: &Resolve, id: WorldId) -> anyhow::Result<String>324 fn generate(&mut self, resolve: &Resolve, id: WorldId) -> anyhow::Result<String> {
325 self.types.analyze(resolve, id);
326
327 self.world_link_options.write_struct(&mut self.src);
328
329 // Resolve the `trappable_error_type` configuration values to `TypeId`
330 // values. This is done by iterating over each `trappable_error_type`
331 // and then locating the interface that it corresponds to as well as the
332 // type within that interface.
333 //
334 // Note that `LookupItem::InterfaceNoPop` is used here as the full
335 // hierarchical behavior of `lookup_keys` isn't used as the interface
336 // must be named here.
337 'outer: for (i, te) in self.opts.trappable_error_type.iter().enumerate() {
338 let error_name = format!("_TrappableError{i}");
339 for (id, iface) in resolve.interfaces.iter() {
340 for (key, projection) in lookup_keys(
341 resolve,
342 &WorldKey::Interface(id),
343 LookupItem::InterfaceNoPop,
344 ) {
345 assert!(projection.is_empty());
346
347 // If `wit_path` looks like `{key}.{type_name}` where
348 // `type_name` is a type within `iface` then we've found a
349 // match. Otherwise continue to the next lookup key if there
350 // is one, and failing that continue to the next interface.
351 let suffix = match te.wit_path.strip_prefix(&key) {
352 Some(s) => s,
353 None => continue,
354 };
355 let suffix = match suffix.strip_prefix('.') {
356 Some(s) => s,
357 None => continue,
358 };
359 if let Some(id) = iface.types.get(suffix) {
360 uwriteln!(self.src, "type {error_name} = {};", te.rust_type_name);
361 let prev = self.trappable_errors.insert(*id, error_name);
362 assert!(prev.is_none());
363 continue 'outer;
364 }
365 }
366 }
367
368 bail!(
369 "failed to locate a WIT error type corresponding to the \
370 `trappable_error_type` name `{}` provided",
371 te.wit_path
372 )
373 }
374
375 // Convert all entries in `with` as relative to the root of where the
376 // macro itself is invoked. This emits a `pub use` to bring the name
377 // into scope under an "anonymous name" which then replaces the `with`
378 // map entry.
379 let mut with = self.opts.with.iter_mut().collect::<Vec<_>>();
380 with.sort();
381 for (i, (_k, v)) in with.into_iter().enumerate() {
382 let name = format!("__with_name{i}");
383 uwriteln!(self.src, "#[doc(hidden)]\npub use {v} as {name};");
384 *v = name;
385 }
386
387 let world = &resolve.worlds[id];
388 for (name, import) in world.imports.iter() {
389 if !self.opts.only_interfaces || matches!(import, WorldItem::Interface { .. }) {
390 self.import(resolve, name, import);
391 }
392 }
393
394 for (name, export) in world.exports.iter() {
395 if !self.opts.only_interfaces || matches!(export, WorldItem::Interface { .. }) {
396 self.export(resolve, name, export);
397 }
398 }
399 self.finish(resolve, id)
400 }
401
import(&mut self, resolve: &Resolve, name: &WorldKey, item: &WorldItem)402 fn import(&mut self, resolve: &Resolve, name: &WorldKey, item: &WorldItem) {
403 let mut generator = InterfaceGenerator::new(self, resolve);
404 match item {
405 WorldItem::Function(func) => {
406 self.import_functions.push(func.clone());
407 }
408 WorldItem::Interface { id, .. } => {
409 generator
410 .generator
411 .interface_last_seen_as_import
412 .insert(*id, true);
413 generator.current_interface = Some((*id, name, false));
414 let snake = to_rust_ident(&match name {
415 WorldKey::Name(s) => s.to_snake_case(),
416 WorldKey::Interface(id) => resolve.interfaces[*id]
417 .name
418 .as_ref()
419 .unwrap()
420 .to_snake_case(),
421 });
422 let module = if generator
423 .generator
424 .name_interface(resolve, *id, name, false)
425 {
426 // If this interface is remapped then that means that it was
427 // provided via the `with` key in the bindgen configuration.
428 // That means that bindings generation is skipped here. To
429 // accommodate future bindgens depending on this bindgen
430 // though we still generate a module which reexports the
431 // original module. This helps maintain the same output
432 // structure regardless of whether `with` is used.
433 let name_at_root = match &generator.generator.interface_names[id] {
434 InterfaceName::Remapped { name_at_root, .. } => name_at_root,
435 InterfaceName::Path(_) => unreachable!(),
436 };
437 let path_to_root = generator.path_to_root();
438 format!(
439 "
440 pub mod {snake} {{
441 #[allow(unused_imports)]
442 pub use {path_to_root}{name_at_root}::*;
443 }}
444 "
445 )
446 } else {
447 // If this interface is not remapped then it's time to
448 // actually generate bindings here.
449 generator.generator.interface_link_options[id].write_struct(&mut generator.src);
450 generator.types(*id);
451 let key_name = resolve.name_world_key(name);
452 generator.generate_add_to_linker(*id, &key_name);
453
454 let module = &generator.src[..];
455 let wt = generator.generator.wasmtime_path();
456
457 format!(
458 "
459 #[allow(clippy::all)]
460 pub mod {snake} {{
461 #[allow(unused_imports)]
462 use {wt}::component::__internal::Box;
463
464 {module}
465 }}
466 "
467 )
468 };
469 let all_func_flags = generator.all_func_flags;
470 self.import_interfaces.push(ImportInterface {
471 id: *id,
472 contents: module,
473 name: self.interface_names[id].clone(),
474 all_func_flags,
475 });
476
477 let interface_path = self.import_interface_path(id);
478 self.interface_link_options[id]
479 .write_impl_from_world(&mut self.src, &interface_path);
480 }
481 WorldItem::Type { id, .. } => {
482 let name = match name {
483 WorldKey::Name(name) => name,
484 WorldKey::Interface(_) => unreachable!(),
485 };
486 generator.define_type(name, *id);
487 let body = mem::take(&mut generator.src);
488 self.src.push_str(&body);
489 }
490 };
491 }
492
export(&mut self, resolve: &Resolve, name: &WorldKey, item: &WorldItem)493 fn export(&mut self, resolve: &Resolve, name: &WorldKey, item: &WorldItem) {
494 let wt = self.wasmtime_path();
495 let mut generator = InterfaceGenerator::new(self, resolve);
496 let field;
497 let ty;
498 let ty_index;
499 let load;
500 let get_index;
501 match item {
502 WorldItem::Function(func) => {
503 generator.define_rust_guest_export(resolve, None, func);
504 let body = mem::take(&mut generator.src).into();
505 load = generator.extract_typed_function(func).1;
506 assert!(generator.src.is_empty());
507 generator.generator.exports.funcs.push(body);
508 ty_index = format!("{wt}::component::ComponentExportIndex");
509 field = func_field_name(resolve, func);
510 ty = format!("{wt}::component::Func");
511 let sig = generator.typedfunc_sig(func, TypeMode::AllBorrowed("'_"));
512 let typecheck = format!(
513 "match item {{
514 {wt}::component::types::ComponentItem::ComponentFunc(func) => {{
515 {wt}::error::Context::context(
516 func.typecheck::<{sig}>(&_instance_type),
517 \"type-checking export func `{0}`\"
518 )?;
519 index
520 }}
521 _ => Err({wt}::format_err!(\"export `{0}` is not a function\"))?,
522 }}",
523 func.name
524 );
525 get_index = format!(
526 "{{ let (item, index) = _component.get_export(None, \"{}\")
527 .ok_or_else(|| {wt}::format_err!(\"no export `{0}` found\"))?;
528 {typecheck}
529 }}",
530 func.name
531 );
532 }
533 WorldItem::Type { .. } => unreachable!(),
534 WorldItem::Interface { id, .. } => {
535 generator
536 .generator
537 .interface_last_seen_as_import
538 .insert(*id, false);
539 generator.generator.name_interface(resolve, *id, name, true);
540 generator.current_interface = Some((*id, name, true));
541 generator.types(*id);
542 let struct_name = "Guest";
543 let iface = &resolve.interfaces[*id];
544 let iface_name = match name {
545 WorldKey::Name(name) => name,
546 WorldKey::Interface(_) => iface.name.as_ref().unwrap(),
547 };
548 uwriteln!(generator.src, "#[derive(Clone)]");
549 uwriteln!(generator.src, "pub struct {struct_name} {{");
550 for (_, func) in iface.functions.iter() {
551 uwriteln!(
552 generator.src,
553 "{}: {wt}::component::Func,",
554 func_field_name(resolve, func)
555 );
556 }
557 uwriteln!(generator.src, "}}");
558
559 uwriteln!(generator.src, "#[derive(Clone)]");
560 uwriteln!(generator.src, "pub struct {struct_name}Indices {{");
561 for (_, func) in iface.functions.iter() {
562 uwriteln!(
563 generator.src,
564 "{}: {wt}::component::ComponentExportIndex,",
565 func_field_name(resolve, func)
566 );
567 }
568 uwriteln!(generator.src, "}}");
569
570 uwriteln!(generator.src, "impl {struct_name}Indices {{");
571 let instance_name = resolve.name_world_key(name);
572 uwrite!(
573 generator.src,
574 "
575 /// Constructor for [`{struct_name}Indices`] which takes a
576 /// [`Component`]({wt}::component::Component) as input and can be executed
577 /// before instantiation.
578 ///
579 /// This constructor can be used to front-load string lookups to find exports
580 /// within a component.
581 pub fn new<_T>(
582 _instance_pre: &{wt}::component::InstancePre<_T>,
583 ) -> {wt}::Result<{struct_name}Indices> {{
584 let instance = _instance_pre.component().get_export_index(None, \"{instance_name}\")
585 .ok_or_else(|| {wt}::format_err!(\"no exported instance named `{instance_name}`\"))?;
586 let mut lookup = move |name| {{
587 _instance_pre.component().get_export_index(Some(&instance), name).ok_or_else(|| {{
588 {wt}::format_err!(
589 \"instance export `{instance_name}` does \\
590 not have export `{{name}}`\"
591 )
592 }})
593 }};
594 let _ = &mut lookup;
595 "
596 );
597 let mut fields = Vec::new();
598 for (_, func) in iface.functions.iter() {
599 let name = func_field_name(resolve, func);
600 uwriteln!(generator.src, "let {name} = lookup(\"{}\")?;", func.name);
601 fields.push(name);
602 }
603 uwriteln!(generator.src, "Ok({struct_name}Indices {{");
604 for name in fields {
605 uwriteln!(generator.src, "{name},");
606 }
607 uwriteln!(generator.src, "}})");
608 uwriteln!(generator.src, "}}"); // end `fn _new`
609
610 uwrite!(
611 generator.src,
612 "
613 pub fn load(
614 &self,
615 mut store: impl {wt}::AsContextMut,
616 instance: &{wt}::component::Instance,
617 ) -> {wt}::Result<{struct_name}> {{
618 let _instance = instance;
619 let _instance_pre = _instance.instance_pre(&store);
620 let _instance_type = _instance_pre.instance_type();
621 let mut store = store.as_context_mut();
622 let _ = &mut store;
623 "
624 );
625 let mut fields = Vec::new();
626 for (_, func) in iface.functions.iter() {
627 let (name, getter) = generator.extract_typed_function(func);
628 uwriteln!(generator.src, "let {name} = {getter};");
629 fields.push(name);
630 }
631 uwriteln!(generator.src, "Ok({struct_name} {{");
632 for name in fields {
633 uwriteln!(generator.src, "{name},");
634 }
635 uwriteln!(generator.src, "}})");
636 uwriteln!(generator.src, "}}"); // end `fn new`
637 uwriteln!(generator.src, "}}"); // end `impl {struct_name}Indices`
638
639 uwriteln!(generator.src, "impl {struct_name} {{");
640 let mut resource_methods = IndexMap::new();
641
642 for (_, func) in iface.functions.iter() {
643 match func.kind.resource() {
644 None => {
645 generator.define_rust_guest_export(resolve, Some(name), func);
646 }
647 Some(id) => {
648 resource_methods.entry(id).or_insert(Vec::new()).push(func);
649 }
650 }
651 }
652
653 for (id, _) in resource_methods.iter() {
654 let name = resolve.types[*id].name.as_ref().unwrap();
655 let snake = name.to_snake_case();
656 let camel = name.to_upper_camel_case();
657 uwriteln!(
658 generator.src,
659 "pub fn {snake}(&self) -> Guest{camel}<'_> {{
660 Guest{camel} {{ funcs: self }}
661 }}"
662 );
663 }
664
665 uwriteln!(generator.src, "}}");
666
667 for (id, methods) in resource_methods {
668 let resource_name = resolve.types[id].name.as_ref().unwrap();
669 let camel = resource_name.to_upper_camel_case();
670 uwriteln!(generator.src, "impl Guest{camel}<'_> {{");
671 for method in methods {
672 generator.define_rust_guest_export(resolve, Some(name), method);
673 }
674 uwriteln!(generator.src, "}}");
675 }
676
677 let module = &generator.src[..];
678 let snake = to_rust_ident(iface_name);
679
680 let module = format!(
681 "
682 #[allow(clippy::all)]
683 pub mod {snake} {{
684 #[allow(unused_imports)]
685 use {wt}::component::__internal::Box;
686
687 {module}
688 }}
689 "
690 );
691 let pkgname = match name {
692 WorldKey::Name(_) => None,
693 WorldKey::Interface(_) => {
694 Some(resolve.packages[iface.package.unwrap()].name.clone())
695 }
696 };
697 self.exports
698 .modules
699 .push((*id, module, self.interface_names[id].clone()));
700
701 let (path, method_name) = match pkgname {
702 Some(pkgname) => (
703 format!(
704 "exports::{}::{}::{snake}::{struct_name}",
705 pkgname.namespace.to_snake_case(),
706 self.name_package_module(resolve, iface.package.unwrap()),
707 ),
708 format!(
709 "{}_{}_{snake}",
710 pkgname.namespace.to_snake_case(),
711 self.name_package_module(resolve, iface.package.unwrap())
712 ),
713 ),
714 None => (format!("exports::{snake}::{struct_name}"), snake.clone()),
715 };
716 field = format!("interface{}", self.exports.fields.len());
717 load = format!("self.{field}.load(&mut store, &_instance)?");
718 self.exports.funcs.push(format!(
719 "
720 pub fn {method_name}(&self) -> &{path} {{
721 &self.{field}
722 }}
723 ",
724 ));
725 ty_index = format!("{path}Indices");
726 ty = path;
727 get_index = format!("{ty_index}::new(_instance_pre)?");
728 }
729 }
730 let prev = self.exports.fields.insert(
731 field,
732 ExportField {
733 ty,
734 ty_index,
735 load,
736 get_index,
737 },
738 );
739 assert!(prev.is_none());
740 }
741
build_world_struct(&mut self, resolve: &Resolve, world: WorldId)742 fn build_world_struct(&mut self, resolve: &Resolve, world: WorldId) {
743 let wt = self.wasmtime_path();
744 let world_name = &resolve.worlds[world].name;
745 let camel = to_rust_upper_camel_case(&world_name);
746 uwriteln!(
747 self.src,
748 "
749 /// Auto-generated bindings for a pre-instantiated version of a
750 /// component which implements the world `{world_name}`.
751 ///
752 /// This structure is created through [`{camel}Pre::new`] which
753 /// takes a [`InstancePre`]({wt}::component::InstancePre) that
754 /// has been created through a [`Linker`]({wt}::component::Linker).
755 ///
756 /// For more information see [`{camel}`] as well.
757 pub struct {camel}Pre<T: 'static> {{
758 instance_pre: {wt}::component::InstancePre<T>,
759 indices: {camel}Indices,
760 }}
761
762 impl<T: 'static> Clone for {camel}Pre<T> {{
763 fn clone(&self) -> Self {{
764 Self {{
765 instance_pre: self.instance_pre.clone(),
766 indices: self.indices.clone(),
767 }}
768 }}
769 }}
770
771 impl<_T: 'static> {camel}Pre<_T> {{
772 /// Creates a new copy of `{camel}Pre` bindings which can then
773 /// be used to instantiate into a particular store.
774 ///
775 /// This method may fail if the component behind `instance_pre`
776 /// does not have the required exports.
777 pub fn new(instance_pre: {wt}::component::InstancePre<_T>) -> {wt}::Result<Self> {{
778 let indices = {camel}Indices::new(&instance_pre)?;
779 Ok(Self {{ instance_pre, indices }})
780 }}
781
782 pub fn engine(&self) -> &{wt}::Engine {{
783 self.instance_pre.engine()
784 }}
785
786 pub fn instance_pre(&self) -> &{wt}::component::InstancePre<_T> {{
787 &self.instance_pre
788 }}
789
790 /// Instantiates a new instance of [`{camel}`] within the
791 /// `store` provided.
792 ///
793 /// This function will use `self` as the pre-instantiated
794 /// instance to perform instantiation. Afterwards the preloaded
795 /// indices in `self` are used to lookup all exports on the
796 /// resulting instance.
797 pub fn instantiate(
798 &self,
799 mut store: impl {wt}::AsContextMut<Data = _T>,
800 ) -> {wt}::Result<{camel}> {{
801 let mut store = store.as_context_mut();
802 let instance = self.instance_pre.instantiate(&mut store)?;
803 self.indices.load(&mut store, &instance)
804 }}
805 }}
806 "
807 );
808
809 if cfg!(feature = "async") {
810 uwriteln!(
811 self.src,
812 "
813 impl<_T: Send + 'static> {camel}Pre<_T> {{
814 /// Same as [`Self::instantiate`], except with `async`.
815 pub async fn instantiate_async(
816 &self,
817 mut store: impl {wt}::AsContextMut<Data = _T>,
818 ) -> {wt}::Result<{camel}> {{
819 let mut store = store.as_context_mut();
820 let instance = self.instance_pre.instantiate_async(&mut store).await?;
821 self.indices.load(&mut store, &instance)
822 }}
823 }}
824 "
825 );
826 }
827
828 uwriteln!(
829 self.src,
830 "
831 /// Auto-generated bindings for index of the exports of
832 /// `{world_name}`.
833 ///
834 /// This is an implementation detail of [`{camel}Pre`] and can
835 /// be constructed if needed as well.
836 ///
837 /// For more information see [`{camel}`] as well.
838 #[derive(Clone)]
839 pub struct {camel}Indices {{"
840 );
841 for (name, field) in self.exports.fields.iter() {
842 uwriteln!(self.src, "{name}: {},", field.ty_index);
843 }
844 self.src.push_str("}\n");
845
846 uwriteln!(
847 self.src,
848 "
849 /// Auto-generated bindings for an instance a component which
850 /// implements the world `{world_name}`.
851 ///
852 /// This structure can be created through a number of means
853 /// depending on your requirements and what you have on hand:
854 ///
855 /// * The most convenient way is to use
856 /// [`{camel}::instantiate`] which only needs a
857 /// [`Store`], [`Component`], and [`Linker`].
858 ///
859 /// * Alternatively you can create a [`{camel}Pre`] ahead of
860 /// time with a [`Component`] to front-load string lookups
861 /// of exports once instead of per-instantiation. This
862 /// method then uses [`{camel}Pre::instantiate`] to
863 /// create a [`{camel}`].
864 ///
865 /// * If you've instantiated the instance yourself already
866 /// then you can use [`{camel}::new`].
867 ///
868 /// These methods are all equivalent to one another and move
869 /// around the tradeoff of what work is performed when.
870 ///
871 /// [`Store`]: {wt}::Store
872 /// [`Component`]: {wt}::component::Component
873 /// [`Linker`]: {wt}::component::Linker
874 pub struct {camel} {{"
875 );
876 for (name, field) in self.exports.fields.iter() {
877 uwriteln!(self.src, "{name}: {},", field.ty);
878 }
879 self.src.push_str("}\n");
880
881 let world_trait = self.world_imports_trait(resolve, world);
882
883 uwriteln!(self.src, "const _: () = {{");
884
885 uwriteln!(
886 self.src,
887 "impl {camel}Indices {{
888 /// Creates a new copy of `{camel}Indices` bindings which can then
889 /// be used to instantiate into a particular store.
890 ///
891 /// This method may fail if the component does not have the
892 /// required exports.
893 pub fn new<_T>(_instance_pre: &{wt}::component::InstancePre<_T>) -> {wt}::Result<Self> {{
894 let _component = _instance_pre.component();
895 let _instance_type = _instance_pre.instance_type();
896 ",
897 );
898 for (name, field) in self.exports.fields.iter() {
899 uwriteln!(self.src, "let {name} = {};", field.get_index);
900 }
901 uwriteln!(self.src, "Ok({camel}Indices {{");
902 for (name, _) in self.exports.fields.iter() {
903 uwriteln!(self.src, "{name},");
904 }
905 uwriteln!(self.src, "}})");
906 uwriteln!(self.src, "}}"); // close `fn new`
907
908 uwriteln!(
909 self.src,
910 "
911 /// Uses the indices stored in `self` to load an instance
912 /// of [`{camel}`] from the instance provided.
913 ///
914 /// Note that at this time this method will additionally
915 /// perform type-checks of all exports.
916 pub fn load(
917 &self,
918 mut store: impl {wt}::AsContextMut,
919 instance: &{wt}::component::Instance,
920 ) -> {wt}::Result<{camel}> {{
921 let _ = &mut store;
922 let _instance = instance;
923 ",
924 );
925 for (name, field) in self.exports.fields.iter() {
926 uwriteln!(self.src, "let {name} = {};", field.load);
927 }
928 uwriteln!(self.src, "Ok({camel} {{");
929 for (name, _) in self.exports.fields.iter() {
930 uwriteln!(self.src, "{name},");
931 }
932 uwriteln!(self.src, "}})");
933 uwriteln!(self.src, "}}"); // close `fn load`
934 uwriteln!(self.src, "}}"); // close `impl {camel}Indices`
935
936 uwriteln!(
937 self.src,
938 "impl {camel} {{
939 /// Convenience wrapper around [`{camel}Pre::new`] and
940 /// [`{camel}Pre::instantiate`].
941 pub fn instantiate<_T>(
942 store: impl {wt}::AsContextMut<Data = _T>,
943 component: &{wt}::component::Component,
944 linker: &{wt}::component::Linker<_T>,
945 ) -> {wt}::Result<{camel}> {{
946 let pre = linker.instantiate_pre(component)?;
947 {camel}Pre::new(pre)?.instantiate(store)
948 }}
949
950 /// Convenience wrapper around [`{camel}Indices::new`] and
951 /// [`{camel}Indices::load`].
952 pub fn new(
953 mut store: impl {wt}::AsContextMut,
954 instance: &{wt}::component::Instance,
955 ) -> {wt}::Result<{camel}> {{
956 let indices = {camel}Indices::new(&instance.instance_pre(&store))?;
957 indices.load(&mut store, instance)
958 }}
959 ",
960 );
961
962 if cfg!(feature = "async") {
963 uwriteln!(
964 self.src,
965 "
966 /// Convenience wrapper around [`{camel}Pre::new`] and
967 /// [`{camel}Pre::instantiate_async`].
968 pub async fn instantiate_async<_T>(
969 store: impl {wt}::AsContextMut<Data = _T>,
970 component: &{wt}::component::Component,
971 linker: &{wt}::component::Linker<_T>,
972 ) -> {wt}::Result<{camel}>
973 where _T: Send,
974 {{
975 let pre = linker.instantiate_pre(component)?;
976 {camel}Pre::new(pre)?.instantiate_async(store).await
977 }}
978 ",
979 );
980 }
981 self.world_add_to_linker(resolve, world, world_trait.as_ref());
982
983 for func in self.exports.funcs.iter() {
984 self.src.push_str(func);
985 }
986
987 uwriteln!(self.src, "}}"); // close `impl {camel}`
988
989 uwriteln!(self.src, "}};"); // close `const _: () = ...
990 }
991
finish(&mut self, resolve: &Resolve, world: WorldId) -> anyhow::Result<String>992 fn finish(&mut self, resolve: &Resolve, world: WorldId) -> anyhow::Result<String> {
993 let remapping_keys = self.opts.with.keys().cloned().collect::<HashSet<String>>();
994
995 let mut unused_keys = remapping_keys
996 .difference(&self.used_with_opts)
997 .map(|s| s.as_str())
998 .collect::<Vec<&str>>();
999
1000 unused_keys.sort();
1001
1002 if !unused_keys.is_empty() {
1003 anyhow::bail!(
1004 "interfaces were specified in the `with` config option but are not referenced in the target world: {unused_keys:?}"
1005 );
1006 }
1007
1008 if !self.opts.only_interfaces {
1009 self.build_world_struct(resolve, world)
1010 }
1011
1012 self.opts.imports.assert_all_rules_used("imports")?;
1013 self.opts.exports.assert_all_rules_used("exports")?;
1014
1015 let imports = mem::take(&mut self.import_interfaces);
1016 self.emit_modules(
1017 imports
1018 .into_iter()
1019 .map(|i| (i.id, i.contents, i.name))
1020 .collect(),
1021 );
1022
1023 let exports = mem::take(&mut self.exports.modules);
1024 self.emit_modules(exports);
1025
1026 let mut src = mem::take(&mut self.src);
1027 if self.opts.rustfmt {
1028 let mut child = Command::new("rustfmt")
1029 .arg("--edition=2018")
1030 .stdin(Stdio::piped())
1031 .stdout(Stdio::piped())
1032 .spawn()
1033 .expect("failed to spawn `rustfmt`");
1034 child
1035 .stdin
1036 .take()
1037 .unwrap()
1038 .write_all(src.as_bytes())
1039 .unwrap();
1040 src.as_mut_string().truncate(0);
1041 child
1042 .stdout
1043 .take()
1044 .unwrap()
1045 .read_to_string(src.as_mut_string())
1046 .unwrap();
1047 let status = child.wait().unwrap();
1048 assert!(status.success());
1049 }
1050
1051 Ok(src.into())
1052 }
1053
emit_modules(&mut self, modules: Vec<(InterfaceId, String, InterfaceName)>)1054 fn emit_modules(&mut self, modules: Vec<(InterfaceId, String, InterfaceName)>) {
1055 #[derive(Default)]
1056 struct Module {
1057 submodules: BTreeMap<String, Module>,
1058 contents: Vec<String>,
1059 }
1060 let mut map = Module::default();
1061 for (_, module, name) in modules {
1062 let path = match name {
1063 InterfaceName::Remapped { local_path, .. } => local_path,
1064 InterfaceName::Path(path) => path,
1065 };
1066 let mut cur = &mut map;
1067 for name in path[..path.len() - 1].iter() {
1068 cur = cur
1069 .submodules
1070 .entry(name.clone())
1071 .or_insert(Module::default());
1072 }
1073 cur.contents.push(module);
1074 }
1075
1076 emit(&mut self.src, map);
1077
1078 fn emit(me: &mut Source, module: Module) {
1079 for (name, submodule) in module.submodules {
1080 uwriteln!(me, "pub mod {name} {{");
1081 emit(me, submodule);
1082 uwriteln!(me, "}}");
1083 }
1084 for submodule in module.contents {
1085 uwriteln!(me, "{submodule}");
1086 }
1087 }
1088 }
1089
1090 /// Attempts to find the `key`, possibly with the resource projection
1091 /// `item`, within the `with` map provided to bindings configuration.
lookup_replacement( &mut self, resolve: &Resolve, key: &WorldKey, item: Option<&str>, ) -> Option<String>1092 fn lookup_replacement(
1093 &mut self,
1094 resolve: &Resolve,
1095 key: &WorldKey,
1096 item: Option<&str>,
1097 ) -> Option<String> {
1098 let item = match item {
1099 Some(item) => LookupItem::Name(item),
1100 None => LookupItem::None,
1101 };
1102
1103 for (lookup, mut projection) in lookup_keys(resolve, key, item) {
1104 if let Some(renamed) = self.opts.with.get(&lookup) {
1105 projection.push(renamed.clone());
1106 projection.reverse();
1107 self.used_with_opts.insert(lookup);
1108 return Some(projection.join("::"));
1109 }
1110 }
1111
1112 None
1113 }
1114
wasmtime_path(&self) -> String1115 fn wasmtime_path(&self) -> String {
1116 self.opts
1117 .wasmtime_crate
1118 .clone()
1119 .unwrap_or("wasmtime".to_string())
1120 }
1121 }
1122
1123 enum LookupItem<'a> {
1124 None,
1125 Name(&'a str),
1126 InterfaceNoPop,
1127 }
1128
lookup_keys( resolve: &Resolve, key: &WorldKey, item: LookupItem<'_>, ) -> Vec<(String, Vec<String>)>1129 fn lookup_keys(
1130 resolve: &Resolve,
1131 key: &WorldKey,
1132 item: LookupItem<'_>,
1133 ) -> Vec<(String, Vec<String>)> {
1134 struct Name<'a> {
1135 prefix: Prefix,
1136 item: Option<&'a str>,
1137 }
1138
1139 #[derive(Copy, Clone)]
1140 enum Prefix {
1141 Namespace(PackageId),
1142 UnversionedPackage(PackageId),
1143 VersionedPackage(PackageId),
1144 UnversionedInterface(InterfaceId),
1145 VersionedInterface(InterfaceId),
1146 }
1147
1148 let prefix = match key {
1149 WorldKey::Interface(id) => Prefix::VersionedInterface(*id),
1150
1151 // Non-interface-keyed names don't get the lookup logic below,
1152 // they're relatively uncommon so only lookup the precise key here.
1153 WorldKey::Name(key) => {
1154 let to_lookup = match item {
1155 LookupItem::Name(item) => format!("{key}.{item}"),
1156 LookupItem::None | LookupItem::InterfaceNoPop => key.to_string(),
1157 };
1158 return vec![(to_lookup, Vec::new())];
1159 }
1160 };
1161
1162 // Here names are iteratively attempted as `key` + `item` is "walked to
1163 // its root" and each attempt is consulted in `self.opts.with`. This
1164 // loop will start at the leaf, the most specific path, and then walk to
1165 // the root, popping items, trying to find a result.
1166 //
1167 // Each time a name is "popped" the projection from the next path is
1168 // pushed onto `projection`. This means that if we actually find a match
1169 // then `projection` is a collection of namespaces that results in the
1170 // final replacement name.
1171 let (interface_required, item) = match item {
1172 LookupItem::None => (false, None),
1173 LookupItem::Name(s) => (false, Some(s)),
1174 LookupItem::InterfaceNoPop => (true, None),
1175 };
1176 let mut name = Name { prefix, item };
1177 let mut projection = Vec::new();
1178 let mut ret = Vec::new();
1179 loop {
1180 let lookup = name.lookup_key(resolve);
1181 ret.push((lookup, projection.clone()));
1182 if !name.pop(resolve, &mut projection) {
1183 break;
1184 }
1185 if interface_required {
1186 match name.prefix {
1187 Prefix::VersionedInterface(_) | Prefix::UnversionedInterface(_) => {}
1188 _ => break,
1189 }
1190 }
1191 }
1192
1193 return ret;
1194
1195 impl<'a> Name<'a> {
1196 fn lookup_key(&self, resolve: &Resolve) -> String {
1197 let mut s = self.prefix.lookup_key(resolve);
1198 if let Some(item) = self.item {
1199 s.push_str(".");
1200 s.push_str(item);
1201 }
1202 s
1203 }
1204
1205 fn pop(&mut self, resolve: &'a Resolve, projection: &mut Vec<String>) -> bool {
1206 match (self.item, self.prefix) {
1207 // If this is a versioned resource name, try the unversioned
1208 // resource name next.
1209 (Some(_), Prefix::VersionedInterface(id)) => {
1210 self.prefix = Prefix::UnversionedInterface(id);
1211 true
1212 }
1213 // If this is an unversioned resource name then time to
1214 // ignore the resource itself and move on to the next most
1215 // specific item, versioned interface names.
1216 (Some(item), Prefix::UnversionedInterface(id)) => {
1217 self.prefix = Prefix::VersionedInterface(id);
1218 self.item = None;
1219 projection.push(item.to_upper_camel_case());
1220 true
1221 }
1222 (Some(_), _) => unreachable!(),
1223 (None, _) => self.prefix.pop(resolve, projection),
1224 }
1225 }
1226 }
1227
1228 impl Prefix {
1229 fn lookup_key(&self, resolve: &Resolve) -> String {
1230 match *self {
1231 Prefix::Namespace(id) => resolve.packages[id].name.namespace.clone(),
1232 Prefix::UnversionedPackage(id) => {
1233 let mut name = resolve.packages[id].name.clone();
1234 name.version = None;
1235 name.to_string()
1236 }
1237 Prefix::VersionedPackage(id) => resolve.packages[id].name.to_string(),
1238 Prefix::UnversionedInterface(id) => {
1239 let id = resolve.id_of(id).unwrap();
1240 match id.find('@') {
1241 Some(i) => id[..i].to_string(),
1242 None => id,
1243 }
1244 }
1245 Prefix::VersionedInterface(id) => resolve.id_of(id).unwrap(),
1246 }
1247 }
1248
1249 fn pop(&mut self, resolve: &Resolve, projection: &mut Vec<String>) -> bool {
1250 *self = match *self {
1251 // try the unversioned interface next
1252 Prefix::VersionedInterface(id) => Prefix::UnversionedInterface(id),
1253 // try this interface's versioned package next
1254 Prefix::UnversionedInterface(id) => {
1255 let iface = &resolve.interfaces[id];
1256 let name = iface.name.as_ref().unwrap();
1257 projection.push(to_rust_ident(name));
1258 Prefix::VersionedPackage(iface.package.unwrap())
1259 }
1260 // try the unversioned package next
1261 Prefix::VersionedPackage(id) => Prefix::UnversionedPackage(id),
1262 // try this package's namespace next
1263 Prefix::UnversionedPackage(id) => {
1264 let name = &resolve.packages[id].name;
1265 projection.push(to_rust_ident(&name.name));
1266 Prefix::Namespace(id)
1267 }
1268 // nothing left to try any more
1269 Prefix::Namespace(_) => return false,
1270 };
1271 true
1272 }
1273 }
1274 }
1275
1276 impl Wasmtime {
has_world_imports_trait(&self, resolve: &Resolve, world: WorldId) -> bool1277 fn has_world_imports_trait(&self, resolve: &Resolve, world: WorldId) -> bool {
1278 !self.import_functions.is_empty() || get_world_resources(resolve, world).count() > 0
1279 }
1280
world_imports_trait(&mut self, resolve: &Resolve, world: WorldId) -> Option<GeneratedTrait>1281 fn world_imports_trait(&mut self, resolve: &Resolve, world: WorldId) -> Option<GeneratedTrait> {
1282 if !self.has_world_imports_trait(resolve, world) {
1283 return None;
1284 }
1285
1286 let world_camel = to_rust_upper_camel_case(&resolve.worlds[world].name);
1287
1288 let functions = self.import_functions.clone();
1289 let mut generator = InterfaceGenerator::new(self, resolve);
1290 let generated_trait = generator.generate_trait(
1291 &format!("{world_camel}Imports"),
1292 &functions
1293 .iter()
1294 .filter(|f| f.kind.resource().is_none())
1295 .collect::<Vec<_>>(),
1296 &[],
1297 &get_world_resources(resolve, world).collect::<Vec<_>>(),
1298 );
1299 let src = String::from(mem::take(&mut generator.src));
1300 self.src.push_str(&src);
1301 Some(generated_trait)
1302 }
1303
import_interface_paths(&self) -> Vec<(InterfaceId, String)>1304 fn import_interface_paths(&self) -> Vec<(InterfaceId, String)> {
1305 self.import_interfaces
1306 .iter()
1307 .map(|i| {
1308 let path = match &i.name {
1309 InterfaceName::Path(path) => path.join("::"),
1310 InterfaceName::Remapped { name_at_root, .. } => name_at_root.clone(),
1311 };
1312 (i.id, path)
1313 })
1314 .collect()
1315 }
1316
import_interface_path(&self, id: &InterfaceId) -> String1317 fn import_interface_path(&self, id: &InterfaceId) -> String {
1318 match &self.interface_names[id] {
1319 InterfaceName::Path(path) => path.join("::"),
1320 InterfaceName::Remapped { name_at_root, .. } => name_at_root.clone(),
1321 }
1322 }
1323
import_interface_all_func_flags(&self, id: InterfaceId) -> FunctionFlags1324 fn import_interface_all_func_flags(&self, id: InterfaceId) -> FunctionFlags {
1325 for i in self.import_interfaces.iter() {
1326 if id != i.id {
1327 continue;
1328 }
1329
1330 return i.all_func_flags;
1331 }
1332 unreachable!()
1333 }
1334
world_host_traits( &self, world_trait: Option<&GeneratedTrait>, ) -> (Vec<String>, Vec<String>)1335 fn world_host_traits(
1336 &self,
1337 world_trait: Option<&GeneratedTrait>,
1338 ) -> (Vec<String>, Vec<String>) {
1339 let mut without_store = Vec::new();
1340 let mut without_store_async = false;
1341 let mut with_store = Vec::new();
1342 let mut with_store_async = false;
1343 for (id, path) in self.import_interface_paths() {
1344 without_store.push(format!("{path}::Host"));
1345 let flags = self.import_interface_all_func_flags(id);
1346 without_store_async = without_store_async || flags.contains(FunctionFlags::ASYNC);
1347
1348 // Note that the requirement of `HostWithStore` is technically
1349 // dependent on `FunctionFlags::STORE`, but when `with` is in use we
1350 // don't necessarily know whether the other bindings generation
1351 // specified this flag or not. To handle that always assume that a
1352 // `HostWithStore` bound is needed.
1353 with_store.push(format!("{path}::HostWithStore"));
1354 with_store_async = with_store_async || flags.contains(FunctionFlags::ASYNC);
1355 }
1356 if let Some(world_trait) = world_trait {
1357 without_store.push(world_trait.name.clone());
1358 without_store_async =
1359 without_store_async || world_trait.all_func_flags.contains(FunctionFlags::ASYNC);
1360
1361 if world_trait.with_store_name.is_some() {
1362 with_store.extend(world_trait.with_store_name.clone());
1363 with_store_async =
1364 with_store_async || world_trait.all_func_flags.contains(FunctionFlags::ASYNC);
1365 }
1366 }
1367 if without_store_async {
1368 without_store.push("Send".to_string());
1369 }
1370 if with_store_async {
1371 with_store.push("Send".to_string());
1372 }
1373 (without_store, with_store)
1374 }
1375
world_add_to_linker( &mut self, resolve: &Resolve, world: WorldId, world_trait: Option<&GeneratedTrait>, )1376 fn world_add_to_linker(
1377 &mut self,
1378 resolve: &Resolve,
1379 world: WorldId,
1380 world_trait: Option<&GeneratedTrait>,
1381 ) {
1382 let has_world_imports_trait = self.has_world_imports_trait(resolve, world);
1383 if self.import_interfaces.is_empty() && !has_world_imports_trait {
1384 return;
1385 }
1386
1387 let (options_param, options_arg) = if self.world_link_options.has_any() {
1388 ("options: &LinkOptions,", ", options")
1389 } else {
1390 ("", "")
1391 };
1392
1393 let mut all_func_flags = FunctionFlags::empty();
1394 if let Some(world_trait) = world_trait {
1395 all_func_flags |= world_trait.all_func_flags;
1396 }
1397 for i in self.import_interfaces.iter() {
1398 all_func_flags |= i.all_func_flags;
1399 }
1400
1401 all_func_flags |= self.opts.imports.default;
1402 all_func_flags |= self.opts.exports.default;
1403
1404 let opt_t_send_bound =
1405 if all_func_flags.contains(FunctionFlags::ASYNC) || self.opts.require_store_data_send {
1406 "+ Send"
1407 } else {
1408 ""
1409 };
1410
1411 let wt = self.wasmtime_path();
1412 if let Some(world_trait) = world_trait {
1413 let d_bound = match &world_trait.with_store_name {
1414 Some(name) => name.clone(),
1415 None => format!("{wt}::component::HasData"),
1416 };
1417 uwrite!(
1418 self.src,
1419 "
1420 pub fn add_to_linker_imports<T, D>(
1421 linker: &mut {wt}::component::Linker<T>,
1422 {options_param}
1423 host_getter: fn(&mut T) -> D::Data<'_>,
1424 ) -> {wt}::Result<()>
1425 where
1426 D: {d_bound},
1427 for<'a> D::Data<'a>: {name},
1428 T: 'static {opt_t_send_bound}
1429 {{
1430 let mut linker = linker.root();
1431 ",
1432 name = world_trait.name,
1433 );
1434 let gate = FeatureGate::open(&mut self.src, &resolve.worlds[world].stability);
1435 for (ty, _name) in get_world_resources(resolve, world) {
1436 self.generate_add_resource_to_linker(None, None, "linker", resolve, ty);
1437 }
1438 for f in self.import_functions.clone() {
1439 let mut generator = InterfaceGenerator::new(self, resolve);
1440 generator.generate_add_function_to_linker(TypeOwner::World(world), &f, "linker");
1441 let src = String::from(generator.src);
1442 self.src.push_str(&src);
1443 self.src.push_str("\n");
1444 }
1445 gate.close(&mut self.src);
1446 uwriteln!(self.src, "Ok(())\n}}");
1447 }
1448
1449 let (sync_bounds, concurrent_bounds) = self.world_host_traits(world_trait);
1450 let sync_bounds = sync_bounds.join(" + ");
1451 let concurrent_bounds = concurrent_bounds.join(" + ");
1452 let d_bounds = if !concurrent_bounds.is_empty() {
1453 concurrent_bounds
1454 } else {
1455 format!("{wt}::component::HasData")
1456 };
1457
1458 uwriteln!(
1459 self.src,
1460 "
1461 pub fn add_to_linker<T, D>(
1462 linker: &mut {wt}::component::Linker<T>,
1463 {options_param}
1464 host_getter: fn(&mut T) -> D::Data<'_>,
1465 ) -> {wt}::Result<()>
1466 where
1467 D: {d_bounds},
1468 for<'a> D::Data<'a>: {sync_bounds},
1469 T: 'static {opt_t_send_bound}
1470 {{
1471 "
1472 );
1473 let gate = FeatureGate::open(&mut self.src, &resolve.worlds[world].stability);
1474 if has_world_imports_trait {
1475 uwriteln!(
1476 self.src,
1477 "Self::add_to_linker_imports::<T, D>(linker {options_arg}, host_getter)?;"
1478 );
1479 }
1480 for (interface_id, path) in self.import_interface_paths() {
1481 let options_arg = if self.interface_link_options[&interface_id].has_any() {
1482 ", &options.into()"
1483 } else {
1484 ""
1485 };
1486
1487 let import_stability = resolve.worlds[world]
1488 .imports
1489 .iter()
1490 .filter_map(|(_, i)| match i {
1491 WorldItem::Interface { id, stability, .. } if *id == interface_id => {
1492 Some(stability.clone())
1493 }
1494 _ => None,
1495 })
1496 .next()
1497 .unwrap_or(Stability::Unknown);
1498
1499 let gate = FeatureGate::open(&mut self.src, &import_stability);
1500 uwriteln!(
1501 self.src,
1502 "{path}::add_to_linker::<T, D>(linker {options_arg}, host_getter)?;"
1503 );
1504 gate.close(&mut self.src);
1505 }
1506 gate.close(&mut self.src);
1507 uwriteln!(self.src, "Ok(())\n}}");
1508 }
1509
generate_add_resource_to_linker( &mut self, key: Option<&WorldKey>, src: Option<&mut Source>, inst: &str, resolve: &Resolve, ty: TypeId, )1510 fn generate_add_resource_to_linker(
1511 &mut self,
1512 key: Option<&WorldKey>,
1513 src: Option<&mut Source>,
1514 inst: &str,
1515 resolve: &Resolve,
1516 ty: TypeId,
1517 ) {
1518 let ty = &resolve.types[ty];
1519 let name = ty.name.as_ref().unwrap();
1520 let stability = &ty.stability;
1521 let wt = self.wasmtime_path();
1522 let src = src.unwrap_or(&mut self.src);
1523 let gate = FeatureGate::open(src, stability);
1524 let camel = name.to_upper_camel_case();
1525
1526 let flags = self.opts.imports.resource_drop_flags(resolve, key, name);
1527 if flags.contains(FunctionFlags::ASYNC) {
1528 if flags.contains(FunctionFlags::STORE) {
1529 uwriteln!(
1530 src,
1531 "{inst}.resource_concurrent(
1532 \"{name}\",
1533 {wt}::component::ResourceType::host::<{camel}>(),
1534 move |caller: &{wt}::component::Accessor::<T>, rep| {{
1535 {wt}::component::__internal::Box::pin(async move {{
1536 let accessor = &caller.with_getter(host_getter);
1537 {wt}::ToWasmtimeResult::to_wasmtime_result(
1538 Host{camel}WithStore::drop(accessor, {wt}::component::Resource::new_own(rep)).await
1539 )
1540 }})
1541 }},
1542 )?;"
1543 )
1544 } else {
1545 uwriteln!(
1546 src,
1547 "{inst}.resource_async(
1548 \"{name}\",
1549 {wt}::component::ResourceType::host::<{camel}>(),
1550 move |mut store, rep| {{
1551 {wt}::component::__internal::Box::new(async move {{
1552 {wt}::ToWasmtimeResult::to_wasmtime_result(
1553 Host{camel}::drop(&mut host_getter(store.data_mut()), {wt}::component::Resource::new_own(rep)).await
1554 )
1555 }})
1556 }},
1557 )?;"
1558 )
1559 }
1560 } else {
1561 let (first_arg, trait_suffix) = if flags.contains(FunctionFlags::STORE) {
1562 (
1563 format!("{wt}::component::Access::new(store, host_getter)"),
1564 "WithStore",
1565 )
1566 } else {
1567 ("&mut host_getter(store.data_mut())".to_string(), "")
1568 };
1569 uwriteln!(
1570 src,
1571 "{inst}.resource(
1572 \"{name}\",
1573 {wt}::component::ResourceType::host::<{camel}>(),
1574 move |mut store, rep| -> {wt}::Result<()> {{
1575
1576 let resource = {wt}::component::Resource::new_own(rep);
1577 {wt}::ToWasmtimeResult::to_wasmtime_result(
1578 Host{camel}{trait_suffix}::drop({first_arg}, resource)
1579 )
1580 }},
1581 )?;",
1582 )
1583 }
1584 gate.close(src);
1585 }
1586 }
1587
1588 struct InterfaceGenerator<'a> {
1589 src: Source,
1590 generator: &'a mut Wasmtime,
1591 resolve: &'a Resolve,
1592 current_interface: Option<(InterfaceId, &'a WorldKey, bool)>,
1593 all_func_flags: FunctionFlags,
1594 }
1595
1596 impl<'a> InterfaceGenerator<'a> {
new(generator: &'a mut Wasmtime, resolve: &'a Resolve) -> InterfaceGenerator<'a>1597 fn new(generator: &'a mut Wasmtime, resolve: &'a Resolve) -> InterfaceGenerator<'a> {
1598 InterfaceGenerator {
1599 src: Source::default(),
1600 generator,
1601 resolve,
1602 current_interface: None,
1603 all_func_flags: FunctionFlags::empty(),
1604 }
1605 }
1606
types_imported(&self) -> bool1607 fn types_imported(&self) -> bool {
1608 match self.current_interface {
1609 Some((_, _, is_export)) => !is_export,
1610 None => true,
1611 }
1612 }
1613
types(&mut self, id: InterfaceId)1614 fn types(&mut self, id: InterfaceId) {
1615 for (name, id) in self.resolve.interfaces[id].types.iter() {
1616 self.define_type(name, *id);
1617 }
1618 }
1619
define_type(&mut self, name: &str, id: TypeId)1620 fn define_type(&mut self, name: &str, id: TypeId) {
1621 let ty = &self.resolve.types[id];
1622 match &ty.kind {
1623 TypeDefKind::Record(record) => self.type_record(id, name, record, &ty.docs),
1624 TypeDefKind::Flags(flags) => self.type_flags(id, name, flags, &ty.docs),
1625 TypeDefKind::Tuple(tuple) => self.type_tuple(id, name, tuple, &ty.docs),
1626 TypeDefKind::Enum(enum_) => self.type_enum(id, name, enum_, &ty.docs),
1627 TypeDefKind::Variant(variant) => self.type_variant(id, name, variant, &ty.docs),
1628 TypeDefKind::Option(t) => self.type_option(id, name, t, &ty.docs),
1629 TypeDefKind::Result(r) => self.type_result(id, name, r, &ty.docs),
1630 TypeDefKind::List(t) => self.type_list(id, name, t, &ty.docs),
1631 TypeDefKind::Type(t) => self.type_alias(id, name, t, &ty.docs),
1632 TypeDefKind::Future(t) => self.type_future(id, name, t.as_ref(), &ty.docs),
1633 TypeDefKind::Stream(t) => self.type_stream(id, name, t.as_ref(), &ty.docs),
1634 TypeDefKind::Handle(handle) => self.type_handle(id, name, handle, &ty.docs),
1635 TypeDefKind::Resource => self.type_resource(id, name, ty, &ty.docs),
1636 TypeDefKind::Map(k, v) => self.type_map(id, name, k, v, &ty.docs),
1637 TypeDefKind::Unknown => unreachable!(),
1638 TypeDefKind::FixedLengthList(..) => todo!(),
1639 }
1640 }
1641
type_handle(&mut self, id: TypeId, name: &str, handle: &Handle, docs: &Docs)1642 fn type_handle(&mut self, id: TypeId, name: &str, handle: &Handle, docs: &Docs) {
1643 self.rustdoc(docs);
1644 let name = name.to_upper_camel_case();
1645 uwriteln!(self.src, "pub type {name} = ");
1646 self.print_handle(handle);
1647 self.push_str(";\n");
1648 self.assert_type(id, &name);
1649 }
1650
type_resource(&mut self, id: TypeId, name: &str, _resource: &TypeDef, docs: &Docs)1651 fn type_resource(&mut self, id: TypeId, name: &str, _resource: &TypeDef, docs: &Docs) {
1652 let camel = name.to_upper_camel_case();
1653 let wt = self.generator.wasmtime_path();
1654
1655 if self.types_imported() {
1656 self.rustdoc(docs);
1657
1658 let replacement = match self.current_interface {
1659 Some((_, key, _)) => {
1660 self.generator
1661 .lookup_replacement(self.resolve, key, Some(name))
1662 }
1663 None => {
1664 self.generator.used_with_opts.insert(name.into());
1665 self.generator.opts.with.get(name).cloned()
1666 }
1667 };
1668 match replacement {
1669 Some(path) => {
1670 uwriteln!(
1671 self.src,
1672 "pub use {}{path} as {camel};",
1673 self.path_to_root()
1674 );
1675 }
1676 None => {
1677 uwriteln!(self.src, "pub enum {camel} {{}}");
1678 }
1679 }
1680
1681 // Generate resource trait
1682
1683 let functions = get_resource_functions(self.resolve, id);
1684 let trait_ = self.generate_trait(
1685 &format!("Host{camel}"),
1686 &functions,
1687 &[ExtraTraitMethod::ResourceDrop { name }],
1688 &[],
1689 );
1690 self.all_func_flags |= trait_.all_func_flags;
1691 } else {
1692 self.rustdoc(docs);
1693 uwriteln!(
1694 self.src,
1695 "
1696 pub type {camel} = {wt}::component::ResourceAny;
1697
1698 pub struct Guest{camel}<'a> {{
1699 funcs: &'a Guest,
1700 }}
1701 "
1702 );
1703 }
1704 }
1705
type_record(&mut self, id: TypeId, _name: &str, record: &Record, docs: &Docs)1706 fn type_record(&mut self, id: TypeId, _name: &str, record: &Record, docs: &Docs) {
1707 let info = self.info(id);
1708 let wt = self.generator.wasmtime_path();
1709
1710 // We use a BTree set to make sure we don't have any duplicates and we have a stable order
1711 let additional_derives: BTreeSet<String> = self
1712 .generator
1713 .opts
1714 .additional_derive_attributes
1715 .iter()
1716 .cloned()
1717 .collect();
1718
1719 for (name, mode) in self.modes_of(id) {
1720 let lt = self.lifetime_for(&info, mode);
1721 self.rustdoc(docs);
1722
1723 let mut derives = additional_derives.clone();
1724
1725 uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]");
1726 if lt.is_none() {
1727 uwriteln!(self.src, "#[derive({wt}::component::Lift)]");
1728 }
1729 uwriteln!(self.src, "#[derive({wt}::component::Lower)]");
1730 self.push_str("#[component(record)]\n");
1731 if let Some(path) = &self.generator.opts.wasmtime_crate {
1732 uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n");
1733 }
1734
1735 if info.is_copy() {
1736 derives.extend(["Copy", "Clone"].into_iter().map(|s| s.to_string()));
1737 } else if info.is_clone() {
1738 derives.insert("Clone".to_string());
1739 }
1740
1741 if !derives.is_empty() {
1742 self.push_str("#[derive(");
1743 self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", "));
1744 self.push_str(")]\n")
1745 }
1746
1747 self.push_str(&format!("pub struct {name}"));
1748 self.print_generics(lt);
1749 self.push_str(" {\n");
1750 for field in record.fields.iter() {
1751 self.rustdoc(&field.docs);
1752 self.push_str(&format!("#[component(name = \"{}\")]\n", field.name));
1753 self.push_str("pub ");
1754 self.push_str(&to_rust_ident(&field.name));
1755 self.push_str(": ");
1756 self.print_ty(&field.ty, mode);
1757 self.push_str(",\n");
1758 }
1759 self.push_str("}\n");
1760
1761 self.push_str("impl");
1762 self.print_generics(lt);
1763 self.push_str(" core::fmt::Debug for ");
1764 self.push_str(&name);
1765 self.print_generics(lt);
1766 self.push_str(" {\n");
1767 self.push_str(
1768 "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n",
1769 );
1770 self.push_str(&format!("f.debug_struct(\"{name}\")"));
1771 for field in record.fields.iter() {
1772 self.push_str(&format!(
1773 ".field(\"{}\", &self.{})",
1774 field.name,
1775 to_rust_ident(&field.name)
1776 ));
1777 }
1778 self.push_str(".finish()\n");
1779 self.push_str("}\n");
1780 self.push_str("}\n");
1781
1782 if info.error {
1783 self.push_str("impl");
1784 self.print_generics(lt);
1785 self.push_str(" core::fmt::Display for ");
1786 self.push_str(&name);
1787 self.print_generics(lt);
1788 self.push_str(" {\n");
1789 self.push_str(
1790 "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n",
1791 );
1792 self.push_str("write!(f, \"{:?}\", self)\n");
1793 self.push_str("}\n");
1794 self.push_str("}\n");
1795
1796 self.push_str("impl core::error::Error for ");
1797 self.push_str(&name);
1798 self.push_str("{}\n");
1799 }
1800 self.assert_type(id, &name);
1801 }
1802 }
1803
type_tuple(&mut self, id: TypeId, _name: &str, tuple: &Tuple, docs: &Docs)1804 fn type_tuple(&mut self, id: TypeId, _name: &str, tuple: &Tuple, docs: &Docs) {
1805 let info = self.info(id);
1806 for (name, mode) in self.modes_of(id) {
1807 let lt = self.lifetime_for(&info, mode);
1808 self.rustdoc(docs);
1809 self.push_str(&format!("pub type {name}"));
1810 self.print_generics(lt);
1811 self.push_str(" = (");
1812 for ty in tuple.types.iter() {
1813 self.print_ty(ty, mode);
1814 self.push_str(",");
1815 }
1816 self.push_str(");\n");
1817 self.assert_type(id, &name);
1818 }
1819 }
1820
type_flags(&mut self, id: TypeId, name: &str, flags: &Flags, docs: &Docs)1821 fn type_flags(&mut self, id: TypeId, name: &str, flags: &Flags, docs: &Docs) {
1822 self.rustdoc(docs);
1823 let wt = self.generator.wasmtime_path();
1824 let rust_name = to_rust_upper_camel_case(name);
1825 uwriteln!(self.src, "{wt}::component::flags!(\n");
1826 self.src.push_str(&format!("{rust_name} {{\n"));
1827 for flag in flags.flags.iter() {
1828 // TODO wasmtime-component-macro doesn't support docs for flags rn
1829 uwrite!(
1830 self.src,
1831 "#[component(name=\"{}\")] const {};\n",
1832 flag.name,
1833 flag.name.to_shouty_snake_case()
1834 );
1835 }
1836 self.src.push_str("}\n");
1837 self.src.push_str(");\n\n");
1838 self.assert_type(id, &rust_name);
1839 }
1840
type_variant(&mut self, id: TypeId, _name: &str, variant: &Variant, docs: &Docs)1841 fn type_variant(&mut self, id: TypeId, _name: &str, variant: &Variant, docs: &Docs) {
1842 self.print_rust_enum(
1843 id,
1844 variant.cases.iter().map(|c| {
1845 (
1846 c.name.to_upper_camel_case(),
1847 Some(c.name.clone()),
1848 &c.docs,
1849 c.ty.as_ref(),
1850 )
1851 }),
1852 docs,
1853 "variant",
1854 );
1855 }
1856
type_option(&mut self, id: TypeId, _name: &str, payload: &Type, docs: &Docs)1857 fn type_option(&mut self, id: TypeId, _name: &str, payload: &Type, docs: &Docs) {
1858 let info = self.info(id);
1859
1860 for (name, mode) in self.modes_of(id) {
1861 self.rustdoc(docs);
1862 let lt = self.lifetime_for(&info, mode);
1863 self.push_str(&format!("pub type {name}"));
1864 self.print_generics(lt);
1865 self.push_str("= Option<");
1866 self.print_ty(payload, mode);
1867 self.push_str(">;\n");
1868 self.assert_type(id, &name);
1869 }
1870 }
1871
1872 // Emit a double-check that the wit-parser-understood size of a type agrees
1873 // with the Wasmtime-understood size of a type.
assert_type(&mut self, id: TypeId, name: &str)1874 fn assert_type(&mut self, id: TypeId, name: &str) {
1875 self.push_str("const _: () = {\n");
1876 let wt = self.generator.wasmtime_path();
1877 uwriteln!(
1878 self.src,
1879 "assert!({} == <{name} as {wt}::component::ComponentType>::SIZE32);",
1880 self.generator.sizes.size(&Type::Id(id)).size_wasm32(),
1881 );
1882 uwriteln!(
1883 self.src,
1884 "assert!({} == <{name} as {wt}::component::ComponentType>::ALIGN32);",
1885 self.generator.sizes.align(&Type::Id(id)).align_wasm32(),
1886 );
1887 self.push_str("};\n");
1888 }
1889
print_rust_enum<'b>( &mut self, id: TypeId, cases: impl IntoIterator<Item = (String, Option<String>, &'b Docs, Option<&'b Type>)> + Clone, docs: &Docs, derive_component: &str, ) where Self: Sized,1890 fn print_rust_enum<'b>(
1891 &mut self,
1892 id: TypeId,
1893 cases: impl IntoIterator<Item = (String, Option<String>, &'b Docs, Option<&'b Type>)> + Clone,
1894 docs: &Docs,
1895 derive_component: &str,
1896 ) where
1897 Self: Sized,
1898 {
1899 let info = self.info(id);
1900 let wt = self.generator.wasmtime_path();
1901
1902 // We use a BTree set to make sure we don't have any duplicates and we have a stable order
1903 let additional_derives: BTreeSet<String> = self
1904 .generator
1905 .opts
1906 .additional_derive_attributes
1907 .iter()
1908 .cloned()
1909 .collect();
1910
1911 for (name, mode) in self.modes_of(id) {
1912 let name = to_rust_upper_camel_case(&name);
1913
1914 let mut derives = additional_derives.clone();
1915
1916 self.rustdoc(docs);
1917 let lt = self.lifetime_for(&info, mode);
1918 uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]");
1919 if lt.is_none() {
1920 uwriteln!(self.src, "#[derive({wt}::component::Lift)]");
1921 }
1922 uwriteln!(self.src, "#[derive({wt}::component::Lower)]");
1923 self.push_str(&format!("#[component({derive_component})]\n"));
1924 if let Some(path) = &self.generator.opts.wasmtime_crate {
1925 uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n");
1926 }
1927 if info.is_copy() {
1928 derives.extend(["Copy", "Clone"].into_iter().map(|s| s.to_string()));
1929 } else if info.is_clone() {
1930 derives.insert("Clone".to_string());
1931 }
1932
1933 if !derives.is_empty() {
1934 self.push_str("#[derive(");
1935 self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", "));
1936 self.push_str(")]\n")
1937 }
1938
1939 self.push_str(&format!("pub enum {name}"));
1940 self.print_generics(lt);
1941 self.push_str("{\n");
1942 for (case_name, component_name, docs, payload) in cases.clone() {
1943 self.rustdoc(docs);
1944 if let Some(n) = component_name {
1945 self.push_str(&format!("#[component(name = \"{n}\")] "));
1946 }
1947 self.push_str(&case_name);
1948 if let Some(ty) = payload {
1949 self.push_str("(");
1950 self.print_ty(ty, mode);
1951 self.push_str(")")
1952 }
1953 self.push_str(",\n");
1954 }
1955 self.push_str("}\n");
1956
1957 self.print_rust_enum_debug(
1958 id,
1959 mode,
1960 &name,
1961 cases
1962 .clone()
1963 .into_iter()
1964 .map(|(name, _attr, _docs, ty)| (name, ty)),
1965 );
1966
1967 if info.error {
1968 self.push_str("impl");
1969 self.print_generics(lt);
1970 self.push_str(" core::fmt::Display for ");
1971 self.push_str(&name);
1972 self.print_generics(lt);
1973 self.push_str(" {\n");
1974 self.push_str(
1975 "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n",
1976 );
1977 self.push_str("write!(f, \"{:?}\", self)\n");
1978 self.push_str("}\n");
1979 self.push_str("}\n");
1980
1981 self.push_str("impl");
1982 self.print_generics(lt);
1983 self.push_str(" core::error::Error for ");
1984 self.push_str(&name);
1985 self.print_generics(lt);
1986 self.push_str(" {}\n");
1987 }
1988
1989 self.assert_type(id, &name);
1990 }
1991 }
1992
print_rust_enum_debug<'b>( &mut self, id: TypeId, mode: TypeMode, name: &str, cases: impl IntoIterator<Item = (String, Option<&'b Type>)>, ) where Self: Sized,1993 fn print_rust_enum_debug<'b>(
1994 &mut self,
1995 id: TypeId,
1996 mode: TypeMode,
1997 name: &str,
1998 cases: impl IntoIterator<Item = (String, Option<&'b Type>)>,
1999 ) where
2000 Self: Sized,
2001 {
2002 let info = self.info(id);
2003 let lt = self.lifetime_for(&info, mode);
2004 self.push_str("impl");
2005 self.print_generics(lt);
2006 self.push_str(" core::fmt::Debug for ");
2007 self.push_str(name);
2008 self.print_generics(lt);
2009 self.push_str(" {\n");
2010 self.push_str("fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n");
2011 self.push_str("match self {\n");
2012 for (case_name, payload) in cases {
2013 self.push_str(name);
2014 self.push_str("::");
2015 self.push_str(&case_name);
2016 if payload.is_some() {
2017 self.push_str("(e)");
2018 }
2019 self.push_str(" => {\n");
2020 self.push_str(&format!("f.debug_tuple(\"{name}::{case_name}\")"));
2021 if payload.is_some() {
2022 self.push_str(".field(e)");
2023 }
2024 self.push_str(".finish()\n");
2025 self.push_str("}\n");
2026 }
2027 self.push_str("}\n");
2028 self.push_str("}\n");
2029 self.push_str("}\n");
2030 }
2031
type_result(&mut self, id: TypeId, _name: &str, result: &Result_, docs: &Docs)2032 fn type_result(&mut self, id: TypeId, _name: &str, result: &Result_, docs: &Docs) {
2033 let info = self.info(id);
2034
2035 for (name, mode) in self.modes_of(id) {
2036 self.rustdoc(docs);
2037 let lt = self.lifetime_for(&info, mode);
2038 self.push_str(&format!("pub type {name}"));
2039 self.print_generics(lt);
2040 self.push_str("= Result<");
2041 self.print_optional_ty(result.ok.as_ref(), mode);
2042 self.push_str(",");
2043 self.print_optional_ty(result.err.as_ref(), mode);
2044 self.push_str(">;\n");
2045 self.assert_type(id, &name);
2046 }
2047 }
2048
type_enum(&mut self, id: TypeId, name: &str, enum_: &Enum, docs: &Docs)2049 fn type_enum(&mut self, id: TypeId, name: &str, enum_: &Enum, docs: &Docs) {
2050 let info = self.info(id);
2051 let wt = self.generator.wasmtime_path();
2052
2053 // We use a BTree set to make sure we don't have any duplicates and have a stable order
2054 let mut derives: BTreeSet<String> = self
2055 .generator
2056 .opts
2057 .additional_derive_attributes
2058 .iter()
2059 .cloned()
2060 .collect();
2061
2062 derives.extend(
2063 ["Clone", "Copy", "PartialEq", "Eq"]
2064 .into_iter()
2065 .map(|s| s.to_string()),
2066 );
2067
2068 let name = to_rust_upper_camel_case(name);
2069 self.rustdoc(docs);
2070 uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]");
2071 uwriteln!(self.src, "#[derive({wt}::component::Lift)]");
2072 uwriteln!(self.src, "#[derive({wt}::component::Lower)]");
2073 self.push_str("#[component(enum)]\n");
2074 if let Some(path) = &self.generator.opts.wasmtime_crate {
2075 uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n");
2076 }
2077
2078 self.push_str("#[derive(");
2079 self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", "));
2080 self.push_str(")]\n");
2081
2082 let repr = match enum_.cases.len().ilog2() {
2083 0..=7 => "u8",
2084 8..=15 => "u16",
2085 _ => "u32",
2086 };
2087 uwriteln!(self.src, "#[repr({repr})]");
2088
2089 self.push_str(&format!("pub enum {name} {{\n"));
2090 for case in enum_.cases.iter() {
2091 self.rustdoc(&case.docs);
2092 self.push_str(&format!("#[component(name = \"{}\")]", case.name));
2093 self.push_str(&case.name.to_upper_camel_case());
2094 self.push_str(",\n");
2095 }
2096 self.push_str("}\n");
2097
2098 // Auto-synthesize an implementation of the standard `Error` trait for
2099 // error-looking types based on their name.
2100 if info.error {
2101 self.push_str("impl ");
2102 self.push_str(&name);
2103 self.push_str("{\n");
2104
2105 self.push_str("pub fn name(&self) -> &'static str {\n");
2106 self.push_str("match self {\n");
2107 for case in enum_.cases.iter() {
2108 self.push_str(&name);
2109 self.push_str("::");
2110 self.push_str(&case.name.to_upper_camel_case());
2111 self.push_str(" => \"");
2112 self.push_str(case.name.as_str());
2113 self.push_str("\",\n");
2114 }
2115 self.push_str("}\n");
2116 self.push_str("}\n");
2117
2118 self.push_str("pub fn message(&self) -> &'static str {\n");
2119 self.push_str("match self {\n");
2120 for case in enum_.cases.iter() {
2121 self.push_str(&name);
2122 self.push_str("::");
2123 self.push_str(&case.name.to_upper_camel_case());
2124 self.push_str(" => \"");
2125 if let Some(contents) = &case.docs.contents {
2126 self.push_str(contents.trim());
2127 }
2128 self.push_str("\",\n");
2129 }
2130 self.push_str("}\n");
2131 self.push_str("}\n");
2132
2133 self.push_str("}\n");
2134
2135 self.push_str("impl core::fmt::Debug for ");
2136 self.push_str(&name);
2137 self.push_str(
2138 "{\nfn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n",
2139 );
2140 self.push_str("f.debug_struct(\"");
2141 self.push_str(&name);
2142 self.push_str("\")\n");
2143 self.push_str(".field(\"code\", &(*self as i32))\n");
2144 self.push_str(".field(\"name\", &self.name())\n");
2145 self.push_str(".field(\"message\", &self.message())\n");
2146 self.push_str(".finish()\n");
2147 self.push_str("}\n");
2148 self.push_str("}\n");
2149
2150 self.push_str("impl core::fmt::Display for ");
2151 self.push_str(&name);
2152 self.push_str(
2153 "{\nfn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n",
2154 );
2155 self.push_str("write!(f, \"{} (error {})\", self.name(), *self as i32)");
2156 self.push_str("}\n");
2157 self.push_str("}\n");
2158 self.push_str("\n");
2159 self.push_str("impl core::error::Error for ");
2160 self.push_str(&name);
2161 self.push_str("{}\n");
2162 } else {
2163 self.print_rust_enum_debug(
2164 id,
2165 TypeMode::Owned,
2166 &name,
2167 enum_
2168 .cases
2169 .iter()
2170 .map(|c| (c.name.to_upper_camel_case(), None)),
2171 )
2172 }
2173 self.assert_type(id, &name);
2174 }
2175
type_alias(&mut self, id: TypeId, _name: &str, ty: &Type, docs: &Docs)2176 fn type_alias(&mut self, id: TypeId, _name: &str, ty: &Type, docs: &Docs) {
2177 let info = self.info(id);
2178 for (name, mode) in self.modes_of(id) {
2179 self.rustdoc(docs);
2180 self.push_str(&format!("pub type {name}"));
2181 let lt = self.lifetime_for(&info, mode);
2182 self.print_generics(lt);
2183 self.push_str(" = ");
2184 self.print_ty(ty, mode);
2185 self.push_str(";\n");
2186 let def_id = resolve_type_definition_id(self.resolve, id);
2187 if !matches!(self.resolve().types[def_id].kind, TypeDefKind::Resource) {
2188 self.assert_type(id, &name);
2189 }
2190 }
2191 }
2192
type_list(&mut self, id: TypeId, _name: &str, ty: &Type, docs: &Docs)2193 fn type_list(&mut self, id: TypeId, _name: &str, ty: &Type, docs: &Docs) {
2194 let info = self.info(id);
2195 for (name, mode) in self.modes_of(id) {
2196 let lt = self.lifetime_for(&info, mode);
2197 self.rustdoc(docs);
2198 self.push_str(&format!("pub type {name}"));
2199 self.print_generics(lt);
2200 self.push_str(" = ");
2201 self.print_list(ty, mode);
2202 self.push_str(";\n");
2203 self.assert_type(id, &name);
2204 }
2205 }
2206
type_map(&mut self, id: TypeId, _name: &str, key: &Type, value: &Type, docs: &Docs)2207 fn type_map(&mut self, id: TypeId, _name: &str, key: &Type, value: &Type, docs: &Docs) {
2208 let info = self.info(id);
2209 for (name, mode) in self.modes_of(id) {
2210 let lt = self.lifetime_for(&info, mode);
2211 self.rustdoc(docs);
2212 self.push_str(&format!("pub type {name}"));
2213 self.print_generics(lt);
2214 self.push_str(" = ");
2215 let key_ty = self.ty(key, mode);
2216 let value_ty = self.ty(value, mode);
2217 self.push_str(&format!("std::collections::HashMap<{key_ty}, {value_ty}>"));
2218 self.push_str(";\n");
2219 self.assert_type(id, &name);
2220 }
2221 }
2222
type_stream(&mut self, id: TypeId, name: &str, ty: Option<&Type>, docs: &Docs)2223 fn type_stream(&mut self, id: TypeId, name: &str, ty: Option<&Type>, docs: &Docs) {
2224 self.rustdoc(docs);
2225 self.push_str(&format!("pub type {name}"));
2226 self.print_generics(None);
2227 self.push_str(" = ");
2228 self.print_stream(ty);
2229 self.push_str(";\n");
2230 self.assert_type(id, &name);
2231 }
2232
type_future(&mut self, id: TypeId, name: &str, ty: Option<&Type>, docs: &Docs)2233 fn type_future(&mut self, id: TypeId, name: &str, ty: Option<&Type>, docs: &Docs) {
2234 self.rustdoc(docs);
2235 self.push_str(&format!("pub type {name}"));
2236 self.print_generics(None);
2237 self.push_str(" = ");
2238 self.print_future(ty);
2239 self.push_str(";\n");
2240 self.assert_type(id, &name);
2241 }
2242
print_result_ty(&mut self, result: Option<Type>, mode: TypeMode)2243 fn print_result_ty(&mut self, result: Option<Type>, mode: TypeMode) {
2244 match result {
2245 Some(ty) => self.print_ty(&ty, mode),
2246 None => self.push_str("()"),
2247 }
2248 }
2249
special_case_trappable_error( &mut self, func: &Function, ) -> Option<(&'a Result_, TypeId, String)>2250 fn special_case_trappable_error(
2251 &mut self,
2252 func: &Function,
2253 ) -> Option<(&'a Result_, TypeId, String)> {
2254 let result = func.result?;
2255
2256 // We fill in a special trappable error type in the case when a function has just one
2257 // result, which is itself a `result<a, e>`, and the `e` is *not* a primitive
2258 // (i.e. defined in std) type, and matches the typename given by the user.
2259 let id = match result {
2260 Type::Id(id) => id,
2261 _ => return None,
2262 };
2263 let result = match &self.resolve.types[id].kind {
2264 TypeDefKind::Result(r) => r,
2265 _ => return None,
2266 };
2267 let error_typeid = match result.err? {
2268 Type::Id(id) => resolve_type_definition_id(&self.resolve, id),
2269 _ => return None,
2270 };
2271
2272 let name = self.generator.trappable_errors.get(&error_typeid)?;
2273
2274 let mut path = self.path_to_root();
2275 uwrite!(path, "{name}");
2276 Some((result, error_typeid, path))
2277 }
2278
generate_add_to_linker(&mut self, id: InterfaceId, name: &str)2279 fn generate_add_to_linker(&mut self, id: InterfaceId, name: &str) {
2280 let iface = &self.resolve.interfaces[id];
2281 let owner = TypeOwner::Interface(id);
2282 let wt = self.generator.wasmtime_path();
2283
2284 let mut required_conversion_traits = IndexSet::new();
2285 let extra_functions = {
2286 let mut functions = Vec::new();
2287 let mut errors_converted = IndexMap::new();
2288 let mut my_error_types = iface
2289 .types
2290 .iter()
2291 .filter(|(_, id)| self.generator.trappable_errors.contains_key(*id))
2292 .map(|(_, id)| *id)
2293 .collect::<Vec<_>>();
2294 my_error_types.extend(
2295 iface
2296 .functions
2297 .iter()
2298 .filter_map(|(_, func)| self.special_case_trappable_error(func))
2299 .map(|(_, id, _)| id),
2300 );
2301 for err_id in my_error_types {
2302 let err = &self.resolve.types[resolve_type_definition_id(self.resolve, err_id)];
2303 let err_name = err.name.as_ref().unwrap();
2304 let owner = match err.owner {
2305 TypeOwner::Interface(i) => i,
2306 _ => unimplemented!(),
2307 };
2308 match self.path_to_interface(owner) {
2309 Some(path) => {
2310 required_conversion_traits.insert(format!("{path}::Host"));
2311 }
2312 None => {
2313 if errors_converted.insert(err_name, err_id).is_none() {
2314 functions.push(ExtraTraitMethod::ErrorConvert {
2315 name: err_name,
2316 id: err_id,
2317 })
2318 }
2319 }
2320 }
2321 }
2322 functions
2323 };
2324
2325 // Generate the `pub trait` which represents the host functionality for
2326 // this import which additionally inherits from all resource traits
2327 // for this interface defined by `type_resource`.
2328 let generated_trait = self.generate_trait(
2329 "Host",
2330 &iface
2331 .functions
2332 .iter()
2333 .filter_map(|(_, f)| {
2334 if f.kind.resource().is_none() {
2335 Some(f)
2336 } else {
2337 None
2338 }
2339 })
2340 .collect::<Vec<_>>(),
2341 &extra_functions,
2342 &get_resources(self.resolve, id).collect::<Vec<_>>(),
2343 );
2344
2345 let opt_t_send_bound = if generated_trait
2346 .all_func_flags
2347 .contains(FunctionFlags::ASYNC)
2348 {
2349 "+ Send"
2350 } else {
2351 ""
2352 };
2353
2354 let mut sync_bounds = "Host".to_string();
2355
2356 for ty in required_conversion_traits {
2357 uwrite!(sync_bounds, " + {ty}");
2358 }
2359
2360 let options_param = if self.generator.interface_link_options[&id].has_any() {
2361 "options: &LinkOptions,"
2362 } else {
2363 ""
2364 };
2365
2366 uwriteln!(
2367 self.src,
2368 "
2369 pub fn add_to_linker<T, D>(
2370 linker: &mut {wt}::component::Linker<T>,
2371 {options_param}
2372 host_getter: fn(&mut T) -> D::Data<'_>,
2373 ) -> {wt}::Result<()>
2374 where
2375 D: HostWithStore,
2376 for<'a> D::Data<'a>: {sync_bounds},
2377 T: 'static {opt_t_send_bound},
2378 {{
2379 "
2380 );
2381
2382 let gate = FeatureGate::open(&mut self.src, &iface.stability);
2383 uwriteln!(self.src, "let mut inst = linker.instance(\"{name}\")?;");
2384
2385 for (ty, _name) in get_resources(self.resolve, id) {
2386 self.generator.generate_add_resource_to_linker(
2387 self.current_interface.map(|p| p.1),
2388 Some(&mut self.src),
2389 "inst",
2390 self.resolve,
2391 ty,
2392 );
2393 }
2394
2395 for (_, func) in iface.functions.iter() {
2396 self.generate_add_function_to_linker(owner, func, "inst");
2397 }
2398 gate.close(&mut self.src);
2399 uwriteln!(self.src, "Ok(())");
2400 uwriteln!(self.src, "}}");
2401 }
2402
import_resource_drop_flags(&mut self, name: &str) -> FunctionFlags2403 fn import_resource_drop_flags(&mut self, name: &str) -> FunctionFlags {
2404 self.generator.opts.imports.resource_drop_flags(
2405 self.resolve,
2406 self.current_interface.map(|p| p.1),
2407 name,
2408 )
2409 }
2410
generate_add_function_to_linker(&mut self, owner: TypeOwner, func: &Function, linker: &str)2411 fn generate_add_function_to_linker(&mut self, owner: TypeOwner, func: &Function, linker: &str) {
2412 let flags = self.generator.opts.imports.flags(
2413 self.resolve,
2414 self.current_interface.map(|p| p.1),
2415 func,
2416 );
2417 self.all_func_flags |= flags;
2418 let gate = FeatureGate::open(&mut self.src, &func.stability);
2419 uwrite!(
2420 self.src,
2421 "{linker}.{}(\"{}\", ",
2422 if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {
2423 "func_wrap_concurrent"
2424 } else if flags.contains(FunctionFlags::ASYNC) {
2425 "func_wrap_async"
2426 } else {
2427 "func_wrap"
2428 },
2429 func.name
2430 );
2431 self.generate_guest_import_closure(owner, func, flags);
2432 uwriteln!(self.src, ")?;");
2433 gate.close(&mut self.src);
2434 }
2435
generate_guest_import_closure( &mut self, owner: TypeOwner, func: &Function, flags: FunctionFlags, )2436 fn generate_guest_import_closure(
2437 &mut self,
2438 owner: TypeOwner,
2439 func: &Function,
2440 flags: FunctionFlags,
2441 ) {
2442 // Generate the closure that's passed to a `Linker`, the final piece of
2443 // codegen here.
2444
2445 let wt = self.generator.wasmtime_path();
2446 if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {
2447 uwrite!(self.src, "move |caller: &{wt}::component::Accessor::<T>, (");
2448 } else {
2449 uwrite!(
2450 self.src,
2451 "move |mut caller: {wt}::StoreContextMut<'_, T>, ("
2452 );
2453 }
2454 for (i, _param) in func.params.iter().enumerate() {
2455 uwrite!(self.src, "arg{},", i);
2456 }
2457 self.src.push_str(") : (");
2458
2459 for param in func.params.iter() {
2460 // Lift is required to be implied for this type, so we can't use
2461 // a borrowed type:
2462 self.print_ty(¶m.ty, TypeMode::Owned);
2463 self.src.push_str(", ");
2464 }
2465 self.src.push_str(")| {\n");
2466
2467 if flags.contains(FunctionFlags::TRACING) {
2468 if flags.contains(FunctionFlags::ASYNC) {
2469 self.src.push_str("use tracing::Instrument;\n");
2470 }
2471
2472 uwrite!(
2473 self.src,
2474 "
2475 let span = tracing::span!(
2476 tracing::Level::TRACE,
2477 \"wit-bindgen import\",
2478 module = \"{}\",
2479 function = \"{}\",
2480 );
2481 ",
2482 match owner {
2483 TypeOwner::Interface(id) => self.resolve.interfaces[id]
2484 .name
2485 .as_deref()
2486 .unwrap_or("<no module>"),
2487 TypeOwner::World(id) => &self.resolve.worlds[id].name,
2488 TypeOwner::None => "<no owner>",
2489 },
2490 func.name,
2491 );
2492 }
2493
2494 if flags.contains(FunctionFlags::ASYNC) {
2495 let ctor = if flags.contains(FunctionFlags::STORE) {
2496 "pin"
2497 } else {
2498 "new"
2499 };
2500 uwriteln!(
2501 self.src,
2502 "{wt}::component::__internal::Box::{ctor}(async move {{"
2503 );
2504 } else {
2505 // Only directly enter the span if the function is sync. Otherwise
2506 // we use tracing::Instrument to ensure that the span is not entered
2507 // across an await point.
2508 if flags.contains(FunctionFlags::TRACING) {
2509 self.push_str("let _enter = span.enter();\n");
2510 }
2511 }
2512
2513 if flags.contains(FunctionFlags::TRACING) {
2514 let mut event_fields = func
2515 .params
2516 .iter()
2517 .enumerate()
2518 .map(|(i, param)| {
2519 let name = to_rust_ident(¶m.name);
2520 formatting_for_arg(&name, i, param.ty, &self.resolve, flags)
2521 })
2522 .collect::<Vec<String>>();
2523 event_fields.push(format!("\"call\""));
2524 uwrite!(
2525 self.src,
2526 "tracing::event!(tracing::Level::TRACE, {});\n",
2527 event_fields.join(", ")
2528 );
2529 }
2530
2531 if flags.contains(FunctionFlags::STORE) {
2532 if flags.contains(FunctionFlags::ASYNC) {
2533 uwriteln!(self.src, "let host = &caller.with_getter(host_getter);");
2534 } else {
2535 uwriteln!(
2536 self.src,
2537 "let access_cx = {wt}::AsContextMut::as_context_mut(&mut caller);"
2538 );
2539 uwriteln!(
2540 self.src,
2541 "let host = {wt}::component::Access::new(access_cx, host_getter);"
2542 );
2543 }
2544 } else {
2545 self.src
2546 .push_str("let host = &mut host_getter(caller.data_mut());\n");
2547 }
2548 let func_name = rust_function_name(func);
2549 let host_trait = match func.kind.resource() {
2550 None => match owner {
2551 TypeOwner::World(id) => format!(
2552 "{}Imports",
2553 rust::to_rust_upper_camel_case(&self.resolve.worlds[id].name)
2554 ),
2555 _ => "Host".to_string(),
2556 },
2557 Some(id) => {
2558 let resource = self.resolve.types[id]
2559 .name
2560 .as_ref()
2561 .unwrap()
2562 .to_upper_camel_case();
2563 format!("Host{resource}")
2564 }
2565 };
2566
2567 if flags.contains(FunctionFlags::STORE) {
2568 uwrite!(
2569 self.src,
2570 "let r = <D as {host_trait}WithStore>::{func_name}(host, "
2571 );
2572 } else {
2573 uwrite!(self.src, "let r = {host_trait}::{func_name}(host, ");
2574 }
2575
2576 for (i, _) in func.params.iter().enumerate() {
2577 uwrite!(self.src, "arg{},", i);
2578 }
2579
2580 self.src.push_str(if flags.contains(FunctionFlags::ASYNC) {
2581 ").await;\n"
2582 } else {
2583 ");\n"
2584 });
2585
2586 if flags.contains(FunctionFlags::TRACING) {
2587 uwrite!(
2588 self.src,
2589 "tracing::event!(tracing::Level::TRACE, {}, \"return\");",
2590 formatting_for_results(func.result, &self.resolve, flags)
2591 );
2592 }
2593
2594 if !flags.contains(FunctionFlags::TRAPPABLE) {
2595 if func.result.is_some() {
2596 uwrite!(self.src, "Ok((r,))\n");
2597 } else {
2598 uwrite!(self.src, "Ok(r)\n");
2599 }
2600 } else if let Some((_, err, _)) = self.special_case_trappable_error(func) {
2601 let err = &self.resolve.types[resolve_type_definition_id(self.resolve, err)];
2602 let err_name = err.name.as_ref().unwrap();
2603 let owner = match err.owner {
2604 TypeOwner::Interface(i) => i,
2605 _ => unimplemented!(),
2606 };
2607 let convert_trait = match self.path_to_interface(owner) {
2608 Some(path) => format!("{path}::Host"),
2609 None => format!("Host"),
2610 };
2611 let convert = format!("{}::convert_{}", convert_trait, err_name.to_snake_case());
2612 let convert = if flags.contains(FunctionFlags::STORE) {
2613 if flags.contains(FunctionFlags::ASYNC) {
2614 format!("caller.with(|mut host| {convert}(&mut host_getter(host.get()), e))")
2615 } else {
2616 format!("{convert}(&mut host_getter(caller.data_mut()), e)")
2617 }
2618 } else {
2619 format!("{convert}(host, e)")
2620 };
2621 uwrite!(
2622 self.src,
2623 "Ok((match r {{
2624 Ok(a) => Ok(a),
2625 Err(e) => Err({wt}::ToWasmtimeResult::to_wasmtime_result({convert})?),
2626 }},))"
2627 );
2628 } else if func.result.is_some() {
2629 uwrite!(
2630 self.src,
2631 "Ok(({wt}::ToWasmtimeResult::to_wasmtime_result(r)?,))\n"
2632 );
2633 } else {
2634 uwrite!(self.src, "{wt}::ToWasmtimeResult::to_wasmtime_result(r)\n");
2635 }
2636
2637 if flags.contains(FunctionFlags::ASYNC) {
2638 if flags.contains(FunctionFlags::TRACING) {
2639 self.src.push_str("}.instrument(span))\n");
2640 } else {
2641 self.src.push_str("})\n");
2642 }
2643 }
2644
2645 self.src.push_str("}\n");
2646 }
2647
generate_function_trait_sig(&mut self, func: &Function, flags: FunctionFlags)2648 fn generate_function_trait_sig(&mut self, func: &Function, flags: FunctionFlags) {
2649 let wt = self.generator.wasmtime_path();
2650 self.rustdoc(&func.docs);
2651
2652 self.push_str("fn ");
2653 self.push_str(&rust_function_name(func));
2654 if flags.contains(FunctionFlags::STORE | FunctionFlags::ASYNC) {
2655 uwrite!(
2656 self.src,
2657 "<T: Send>(accessor: &{wt}::component::Accessor<T, Self>, "
2658 );
2659 } else if flags.contains(FunctionFlags::STORE) {
2660 uwrite!(self.src, "<T>(host: {wt}::component::Access<T, Self>, ");
2661 } else {
2662 self.push_str("(&mut self, ");
2663 }
2664 self.generate_function_params(func);
2665 self.push_str(")");
2666 self.push_str(" -> ");
2667
2668 if flags.contains(FunctionFlags::ASYNC) {
2669 uwrite!(self.src, "impl ::core::future::Future<Output = ");
2670 }
2671
2672 self.all_func_flags |= flags;
2673 self.generate_function_result(func, flags);
2674
2675 if flags.contains(FunctionFlags::ASYNC) {
2676 self.push_str("> + Send");
2677 }
2678 }
2679
generate_function_params(&mut self, func: &Function)2680 fn generate_function_params(&mut self, func: &Function) {
2681 for param in func.params.iter() {
2682 let name = to_rust_ident(¶m.name);
2683 self.push_str(&name);
2684 self.push_str(": ");
2685 self.print_ty(¶m.ty, TypeMode::Owned);
2686 self.push_str(",");
2687 }
2688 }
2689
push_wasmtime_or_anyhow_result(&mut self)2690 fn push_wasmtime_or_anyhow_result(&mut self) {
2691 let wt = self.generator.wasmtime_path();
2692 uwrite!(self.src, "{wt}::");
2693 if self.generator.opts.anyhow {
2694 self.push_str("anyhow::");
2695 }
2696 self.push_str("Result");
2697 }
2698
generate_function_result(&mut self, func: &Function, flags: FunctionFlags)2699 fn generate_function_result(&mut self, func: &Function, flags: FunctionFlags) {
2700 if !flags.contains(FunctionFlags::TRAPPABLE) {
2701 self.print_result_ty(func.result, TypeMode::Owned);
2702 } else if let Some((r, _id, error_typename)) = self.special_case_trappable_error(func) {
2703 // Functions which have a single result `result<ok,err>` get special
2704 // cased to use the host_wasmtime_rust::Error<err>, making it possible
2705 // for them to trap or use `?` to propagate their errors
2706 self.push_str("Result<");
2707 if let Some(ok) = r.ok {
2708 self.print_ty(&ok, TypeMode::Owned);
2709 } else {
2710 self.push_str("()");
2711 }
2712 self.push_str(",");
2713 self.push_str(&error_typename);
2714 self.push_str(">");
2715 } else {
2716 // All other functions get their return values wrapped in an wasmtime::Result.
2717 // Returning the anyhow::Error case can be used to trap.
2718 self.push_wasmtime_or_anyhow_result();
2719 self.push_str("<");
2720 self.print_result_ty(func.result, TypeMode::Owned);
2721 self.push_str(">");
2722 }
2723 }
2724
extract_typed_function(&mut self, func: &Function) -> (String, String)2725 fn extract_typed_function(&mut self, func: &Function) -> (String, String) {
2726 let snake = func_field_name(self.resolve, func);
2727 let sig = self.typedfunc_sig(func, TypeMode::AllBorrowed("'_"));
2728 let extract =
2729 format!("*_instance.get_typed_func::<{sig}>(&mut store, &self.{snake})?.func()");
2730 (snake, extract)
2731 }
2732
define_rust_guest_export( &mut self, resolve: &Resolve, ns: Option<&WorldKey>, func: &Function, )2733 fn define_rust_guest_export(
2734 &mut self,
2735 resolve: &Resolve,
2736 ns: Option<&WorldKey>,
2737 func: &Function,
2738 ) {
2739 let flags = self.generator.opts.exports.flags(resolve, ns, func);
2740 let (async_, async__, await_) = if flags.contains(FunctionFlags::ASYNC) {
2741 ("async", "_async", ".await")
2742 } else {
2743 ("", "", "")
2744 };
2745
2746 self.rustdoc(&func.docs);
2747 let wt = self.generator.wasmtime_path();
2748
2749 uwrite!(
2750 self.src,
2751 "pub {async_} fn call_{}",
2752 func.item_name().to_snake_case(),
2753 );
2754 if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {
2755 uwrite!(
2756 self.src,
2757 "<_T, _D>(&self, accessor: &{wt}::component::Accessor<_T, _D>, ",
2758 );
2759 } else {
2760 uwrite!(self.src, "<S: {wt}::AsContextMut>(&self, mut store: S, ",);
2761 }
2762
2763 let param_mode = if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {
2764 TypeMode::Owned
2765 } else {
2766 TypeMode::AllBorrowed("'_")
2767 };
2768
2769 for (i, param) in func.params.iter().enumerate() {
2770 uwrite!(self.src, "arg{}: ", i);
2771 self.print_ty(¶m.ty, param_mode);
2772 self.push_str(",");
2773 }
2774
2775 uwrite!(self.src, ") -> {wt}::Result<");
2776 self.print_result_ty(func.result, TypeMode::Owned);
2777 uwrite!(self.src, ">");
2778
2779 if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {
2780 uwrite!(self.src, " where _T: Send, _D: {wt}::component::HasData");
2781 } else if flags.contains(FunctionFlags::ASYNC) {
2782 uwrite!(self.src, " where <S as {wt}::AsContext>::Data: Send");
2783 }
2784 uwrite!(self.src, "{{\n");
2785
2786 if flags.contains(FunctionFlags::TRACING) {
2787 if flags.contains(FunctionFlags::ASYNC) {
2788 self.src.push_str("use tracing::Instrument;\n");
2789 }
2790
2791 let ns = match ns {
2792 Some(key) => resolve.name_world_key(key),
2793 None => "default".to_string(),
2794 };
2795 self.src.push_str(&format!(
2796 "
2797 let span = tracing::span!(
2798 tracing::Level::TRACE,
2799 \"wit-bindgen export\",
2800 module = \"{ns}\",
2801 function = \"{}\",
2802 );
2803 ",
2804 func.name,
2805 ));
2806
2807 if !flags.contains(FunctionFlags::ASYNC) {
2808 self.src.push_str(
2809 "
2810 let _enter = span.enter();
2811 ",
2812 );
2813 }
2814 }
2815
2816 self.src.push_str("let callee = unsafe {\n");
2817 uwrite!(
2818 self.src,
2819 "{wt}::component::TypedFunc::<{}>",
2820 self.typedfunc_sig(func, param_mode)
2821 );
2822 let projection_to_func = if func.kind.resource().is_some() {
2823 ".funcs"
2824 } else {
2825 ""
2826 };
2827 uwriteln!(
2828 self.src,
2829 "::new_unchecked(self{projection_to_func}.{})",
2830 func_field_name(self.resolve, func),
2831 );
2832 self.src.push_str("};\n");
2833
2834 self.src.push_str("let (");
2835 if func.result.is_some() {
2836 uwrite!(self.src, "ret0,");
2837 }
2838
2839 if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {
2840 uwrite!(self.src, ") = callee.call_concurrent(accessor, (");
2841 } else {
2842 uwrite!(
2843 self.src,
2844 ") = callee.call{async__}(store.as_context_mut(), ("
2845 );
2846 };
2847
2848 for (i, _) in func.params.iter().enumerate() {
2849 uwrite!(self.src, "arg{}, ", i);
2850 }
2851
2852 let instrument = if flags.contains(FunctionFlags::ASYNC | FunctionFlags::TRACING) {
2853 ".instrument(span.clone())"
2854 } else {
2855 ""
2856 };
2857 uwriteln!(self.src, ")){instrument}{await_}?;");
2858
2859 self.src.push_str("Ok(");
2860 if func.result.is_some() {
2861 self.src.push_str("ret0");
2862 } else {
2863 self.src.push_str("()");
2864 }
2865 self.src.push_str(")\n");
2866
2867 // End function body
2868 self.src.push_str("}\n");
2869 }
2870
rustdoc(&mut self, docs: &Docs)2871 fn rustdoc(&mut self, docs: &Docs) {
2872 let docs = match &docs.contents {
2873 Some(docs) => docs,
2874 None => return,
2875 };
2876 for line in docs.trim().lines() {
2877 self.push_str("/// ");
2878 self.push_str(line);
2879 self.push_str("\n");
2880 }
2881 }
2882
path_to_root(&self) -> String2883 fn path_to_root(&self) -> String {
2884 let mut path_to_root = String::new();
2885 if let Some((_, key, is_export)) = self.current_interface {
2886 match key {
2887 WorldKey::Name(_) => {
2888 path_to_root.push_str("super::");
2889 }
2890 WorldKey::Interface(_) => {
2891 path_to_root.push_str("super::super::super::");
2892 }
2893 }
2894 if is_export {
2895 path_to_root.push_str("super::");
2896 }
2897 }
2898 path_to_root
2899 }
2900
partition_concurrent_funcs<'b>( &mut self, funcs: impl IntoIterator<Item = &'b Function>, ) -> FunctionPartitioning<'b>2901 fn partition_concurrent_funcs<'b>(
2902 &mut self,
2903 funcs: impl IntoIterator<Item = &'b Function>,
2904 ) -> FunctionPartitioning<'b> {
2905 let key = self.current_interface.map(|p| p.1);
2906 let (with_store, without_store) = funcs
2907 .into_iter()
2908 .map(|func| {
2909 let flags = self.generator.opts.imports.flags(self.resolve, key, func);
2910 (func, flags)
2911 })
2912 .partition(|(_, flags)| flags.contains(FunctionFlags::STORE));
2913 FunctionPartitioning {
2914 with_store,
2915 without_store,
2916 }
2917 }
2918
generate_trait( &mut self, trait_name: &str, functions: &[&Function], extra_functions: &[ExtraTraitMethod<'_>], resources: &[(TypeId, &str)], ) -> GeneratedTrait2919 fn generate_trait(
2920 &mut self,
2921 trait_name: &str,
2922 functions: &[&Function],
2923 extra_functions: &[ExtraTraitMethod<'_>],
2924 resources: &[(TypeId, &str)],
2925 ) -> GeneratedTrait {
2926 let mut ret = GeneratedTrait::default();
2927 let wt = self.generator.wasmtime_path();
2928 let partition = self.partition_concurrent_funcs(functions.iter().copied());
2929
2930 for (_, flags) in partition.with_store.iter().chain(&partition.without_store) {
2931 ret.all_func_flags |= *flags;
2932 }
2933
2934 let mut with_store_supertraits = vec![format!("{wt}::component::HasData")];
2935 let mut without_store_supertraits = vec![];
2936 for (id, name) in resources {
2937 let camel = name.to_upper_camel_case();
2938 without_store_supertraits.push(format!("Host{camel}"));
2939 let funcs = self.partition_concurrent_funcs(get_resource_functions(self.resolve, *id));
2940 for (_, flags) in funcs.with_store.iter().chain(&funcs.without_store) {
2941 ret.all_func_flags |= *flags;
2942 }
2943 ret.all_func_flags |= self.import_resource_drop_flags(name);
2944 with_store_supertraits.push(format!("Host{camel}WithStore"));
2945 }
2946 if ret.all_func_flags.contains(FunctionFlags::ASYNC) {
2947 with_store_supertraits.push("Send".to_string());
2948 without_store_supertraits.push("Send".to_string());
2949 }
2950
2951 uwriteln!(
2952 self.src,
2953 "pub trait {trait_name}WithStore: {} {{",
2954 with_store_supertraits.join(" + "),
2955 );
2956 ret.with_store_name = Some(format!("{trait_name}WithStore"));
2957
2958 let mut extra_with_store_function = false;
2959 for extra in extra_functions {
2960 match extra {
2961 ExtraTraitMethod::ResourceDrop { name } => {
2962 let flags = self.import_resource_drop_flags(name);
2963 if !flags.contains(FunctionFlags::STORE) {
2964 continue;
2965 }
2966 let camel = name.to_upper_camel_case();
2967
2968 if flags.contains(FunctionFlags::ASYNC) {
2969 uwrite!(
2970 self.src,
2971 "
2972 fn drop<T>(accessor: &{wt}::component::Accessor<T, Self>, rep: {wt}::component::Resource<{camel}>)
2973 -> impl ::core::future::Future<Output =
2974 "
2975 );
2976 self.push_wasmtime_or_anyhow_result();
2977 self.push_str("<()>> + Send where Self: Sized;");
2978 } else {
2979 uwrite!(
2980 self.src,
2981 "
2982 fn drop<T>(accessor: {wt}::component::Access<T, Self>, rep: {wt}::component::Resource<{camel}>)
2983 ->
2984 "
2985 );
2986 self.push_wasmtime_or_anyhow_result();
2987 self.push_str("<()>;");
2988 }
2989
2990 extra_with_store_function = true;
2991 }
2992 ExtraTraitMethod::ErrorConvert { .. } => {}
2993 }
2994 }
2995
2996 for (func, flags) in partition.with_store.iter() {
2997 self.generate_function_trait_sig(func, *flags);
2998 self.push_str(";\n");
2999 }
3000 uwriteln!(self.src, "}}");
3001
3002 // If `*WithStore` is empty, generate a blanket impl for the trait since
3003 // it's otherwise not necessary to implement it manually.
3004 if partition.with_store.is_empty() && !extra_with_store_function {
3005 uwriteln!(self.src, "impl<_T: ?Sized> {trait_name}WithStore for _T");
3006 uwriteln!(
3007 self.src,
3008 " where _T: {}",
3009 with_store_supertraits.join(" + ")
3010 );
3011
3012 uwriteln!(self.src, "{{}}");
3013 }
3014
3015 uwriteln!(
3016 self.src,
3017 "pub trait {trait_name}: {} {{",
3018 without_store_supertraits.join(" + ")
3019 );
3020 ret.name = trait_name.to_string();
3021 for (func, flags) in partition.without_store.iter() {
3022 self.generate_function_trait_sig(func, *flags);
3023 self.push_str(";\n");
3024 }
3025
3026 for extra in extra_functions {
3027 match extra {
3028 ExtraTraitMethod::ResourceDrop { name } => {
3029 let flags = self.import_resource_drop_flags(name);
3030 ret.all_func_flags |= flags;
3031 if flags.contains(FunctionFlags::STORE) {
3032 continue;
3033 }
3034 let camel = name.to_upper_camel_case();
3035 uwrite!(
3036 self.src,
3037 "fn drop(&mut self, rep: {wt}::component::Resource<{camel}>) -> "
3038 );
3039 if flags.contains(FunctionFlags::ASYNC) {
3040 uwrite!(self.src, "impl ::core::future::Future<Output =");
3041 }
3042 self.push_wasmtime_or_anyhow_result();
3043 self.push_str("<()>");
3044 if flags.contains(FunctionFlags::ASYNC) {
3045 uwrite!(self.src, "> + Send");
3046 }
3047 uwrite!(self.src, ";");
3048 }
3049 ExtraTraitMethod::ErrorConvert { name, id } => {
3050 let root = self.path_to_root();
3051 let custom_name = &self.generator.trappable_errors[id];
3052 let snake = name.to_snake_case();
3053 let camel = name.to_upper_camel_case();
3054 uwrite!(
3055 self.src,
3056 "
3057 fn convert_{snake}(&mut self, err: {root}{custom_name}) ->
3058 "
3059 );
3060 self.push_wasmtime_or_anyhow_result();
3061 uwrite!(self.src, "<{camel}>;");
3062 }
3063 }
3064 }
3065
3066 uwriteln!(self.src, "}}");
3067
3068 if self.generator.opts.skip_mut_forwarding_impls {
3069 return ret;
3070 }
3071
3072 // Generate impl HostResource for &mut HostResource
3073 let maybe_send = if ret.all_func_flags.contains(FunctionFlags::ASYNC) {
3074 "+ Send"
3075 } else {
3076 ""
3077 };
3078 uwriteln!(
3079 self.src,
3080 "impl <_T: {trait_name} + ?Sized {maybe_send}> {trait_name} for &mut _T {{"
3081 );
3082 for (func, flags) in partition.without_store.iter() {
3083 self.generate_function_trait_sig(func, *flags);
3084 uwriteln!(self.src, "{{");
3085 if flags.contains(FunctionFlags::ASYNC) {
3086 uwriteln!(self.src, "async move {{");
3087 }
3088 uwrite!(
3089 self.src,
3090 "{trait_name}::{}(*self,",
3091 rust_function_name(func)
3092 );
3093 for param in func.params.iter() {
3094 uwrite!(self.src, "{},", to_rust_ident(¶m.name));
3095 }
3096 uwrite!(self.src, ")");
3097 if flags.contains(FunctionFlags::ASYNC) {
3098 uwrite!(self.src, ".await\n}}");
3099 }
3100 uwriteln!(self.src, "}}");
3101 }
3102 for extra in extra_functions {
3103 match extra {
3104 ExtraTraitMethod::ResourceDrop { name } => {
3105 let flags = self.import_resource_drop_flags(name);
3106 if flags.contains(FunctionFlags::STORE) {
3107 continue;
3108 }
3109 let camel = name.to_upper_camel_case();
3110 let mut await_ = "";
3111 if flags.contains(FunctionFlags::ASYNC) {
3112 self.src.push_str("async ");
3113 await_ = ".await";
3114 }
3115 uwrite!(
3116 self.src,
3117 "fn drop(&mut self, rep: {wt}::component::Resource<{camel}>) -> ",
3118 );
3119 self.push_wasmtime_or_anyhow_result();
3120 uwriteln!(
3121 self.src,
3122 "<()> {{
3123 {trait_name}::drop(*self, rep){await_}
3124 }}
3125 ",
3126 );
3127 }
3128 ExtraTraitMethod::ErrorConvert { name, id } => {
3129 let root = self.path_to_root();
3130 let custom_name = &self.generator.trappable_errors[id];
3131 let snake = name.to_snake_case();
3132 let camel = name.to_upper_camel_case();
3133 uwrite!(
3134 self.src,
3135 "fn convert_{snake}(&mut self, err: {root}{custom_name}) -> ",
3136 );
3137 self.push_wasmtime_or_anyhow_result();
3138 uwriteln!(
3139 self.src,
3140 "<{camel}> {{
3141 {trait_name}::convert_{snake}(*self, err)
3142 }}
3143 ",
3144 );
3145 }
3146 }
3147 }
3148 uwriteln!(self.src, "}}");
3149
3150 ret
3151 }
3152 }
3153
3154 enum ExtraTraitMethod<'a> {
3155 ResourceDrop { name: &'a str },
3156 ErrorConvert { name: &'a str, id: TypeId },
3157 }
3158
3159 struct FunctionPartitioning<'a> {
3160 without_store: Vec<(&'a Function, FunctionFlags)>,
3161 with_store: Vec<(&'a Function, FunctionFlags)>,
3162 }
3163
3164 #[derive(Default)]
3165 struct GeneratedTrait {
3166 name: String,
3167 with_store_name: Option<String>,
3168 all_func_flags: FunctionFlags,
3169 }
3170
3171 impl<'a> RustGenerator<'a> for InterfaceGenerator<'a> {
resolve(&self) -> &'a Resolve3172 fn resolve(&self) -> &'a Resolve {
3173 self.resolve
3174 }
3175
ownership(&self) -> Ownership3176 fn ownership(&self) -> Ownership {
3177 self.generator.opts.ownership
3178 }
3179
path_to_interface(&self, interface: InterfaceId) -> Option<String>3180 fn path_to_interface(&self, interface: InterfaceId) -> Option<String> {
3181 if let Some((cur, _, _)) = self.current_interface {
3182 if cur == interface {
3183 return None;
3184 }
3185 }
3186 let mut path_to_root = self.path_to_root();
3187 match &self.generator.interface_names[&interface] {
3188 InterfaceName::Remapped { name_at_root, .. } => path_to_root.push_str(name_at_root),
3189 InterfaceName::Path(path) => {
3190 for (i, name) in path.iter().enumerate() {
3191 if i > 0 {
3192 path_to_root.push_str("::");
3193 }
3194 path_to_root.push_str(name);
3195 }
3196 }
3197 }
3198 Some(path_to_root)
3199 }
3200
push_str(&mut self, s: &str)3201 fn push_str(&mut self, s: &str) {
3202 self.src.push_str(s);
3203 }
3204
info(&self, ty: TypeId) -> TypeInfo3205 fn info(&self, ty: TypeId) -> TypeInfo {
3206 self.generator.types.get(ty)
3207 }
3208
is_imported_interface(&self, interface: InterfaceId) -> bool3209 fn is_imported_interface(&self, interface: InterfaceId) -> bool {
3210 self.generator.interface_last_seen_as_import[&interface]
3211 }
3212
wasmtime_path(&self) -> String3213 fn wasmtime_path(&self) -> String {
3214 self.generator.wasmtime_path()
3215 }
3216 }
3217
3218 #[derive(Default)]
3219 struct LinkOptionsBuilder {
3220 unstable_features: BTreeSet<String>,
3221 }
3222 impl LinkOptionsBuilder {
has_any(&self) -> bool3223 fn has_any(&self) -> bool {
3224 !self.unstable_features.is_empty()
3225 }
add_world(&mut self, resolve: &Resolve, id: &WorldId)3226 fn add_world(&mut self, resolve: &Resolve, id: &WorldId) {
3227 let world = &resolve.worlds[*id];
3228
3229 self.add_stability(&world.stability);
3230
3231 for (_, import) in world.imports.iter() {
3232 match import {
3233 WorldItem::Interface { id, stability, .. } => {
3234 self.add_stability(stability);
3235 self.add_interface(resolve, id);
3236 }
3237 WorldItem::Function(f) => {
3238 self.add_stability(&f.stability);
3239 }
3240 WorldItem::Type { id, .. } => {
3241 self.add_type(resolve, id);
3242 }
3243 }
3244 }
3245 }
add_interface(&mut self, resolve: &Resolve, id: &InterfaceId)3246 fn add_interface(&mut self, resolve: &Resolve, id: &InterfaceId) {
3247 let interface = &resolve.interfaces[*id];
3248
3249 self.add_stability(&interface.stability);
3250
3251 for (_, t) in interface.types.iter() {
3252 self.add_type(resolve, t);
3253 }
3254 for (_, f) in interface.functions.iter() {
3255 self.add_stability(&f.stability);
3256 }
3257 }
add_type(&mut self, resolve: &Resolve, id: &TypeId)3258 fn add_type(&mut self, resolve: &Resolve, id: &TypeId) {
3259 let t = &resolve.types[*id];
3260 self.add_stability(&t.stability);
3261 }
add_stability(&mut self, stability: &Stability)3262 fn add_stability(&mut self, stability: &Stability) {
3263 match stability {
3264 Stability::Unstable { feature, .. } => {
3265 self.unstable_features.insert(feature.clone());
3266 }
3267 Stability::Stable { .. } | Stability::Unknown => {}
3268 }
3269 }
write_struct(&self, src: &mut Source)3270 fn write_struct(&self, src: &mut Source) {
3271 if !self.has_any() {
3272 return;
3273 }
3274
3275 let mut unstable_features = self.unstable_features.iter().cloned().collect::<Vec<_>>();
3276 unstable_features.sort();
3277
3278 uwriteln!(
3279 src,
3280 "
3281 /// Link-time configurations.
3282 #[derive(Clone, Debug, Default)]
3283 pub struct LinkOptions {{
3284 "
3285 );
3286
3287 for feature in unstable_features.iter() {
3288 let feature_rust_name = feature.to_snake_case();
3289 uwriteln!(src, "{feature_rust_name}: bool,");
3290 }
3291
3292 uwriteln!(src, "}}");
3293 uwriteln!(src, "impl LinkOptions {{");
3294
3295 for feature in unstable_features.iter() {
3296 let feature_rust_name = feature.to_snake_case();
3297 uwriteln!(
3298 src,
3299 "
3300 /// Enable members marked as `@unstable(feature = {feature})`
3301 pub fn {feature_rust_name}(&mut self, enabled: bool) -> &mut Self {{
3302 self.{feature_rust_name} = enabled;
3303 self
3304 }}
3305 "
3306 );
3307 }
3308
3309 uwriteln!(src, "}}");
3310 }
write_impl_from_world(&self, src: &mut Source, path: &str)3311 fn write_impl_from_world(&self, src: &mut Source, path: &str) {
3312 if !self.has_any() {
3313 return;
3314 }
3315
3316 let mut unstable_features = self.unstable_features.iter().cloned().collect::<Vec<_>>();
3317 unstable_features.sort();
3318
3319 uwriteln!(
3320 src,
3321 "
3322 impl core::convert::From<LinkOptions> for {path}::LinkOptions {{
3323 fn from(src: LinkOptions) -> Self {{
3324 (&src).into()
3325 }}
3326 }}
3327
3328 impl core::convert::From<&LinkOptions> for {path}::LinkOptions {{
3329 fn from(src: &LinkOptions) -> Self {{
3330 let mut dest = Self::default();
3331 "
3332 );
3333
3334 for feature in unstable_features.iter() {
3335 let feature_rust_name = feature.to_snake_case();
3336 uwriteln!(src, "dest.{feature_rust_name}(src.{feature_rust_name});");
3337 }
3338
3339 uwriteln!(
3340 src,
3341 "
3342 dest
3343 }}
3344 }}
3345 "
3346 );
3347 }
3348 }
3349
3350 struct FeatureGate {
3351 close: bool,
3352 }
3353 impl FeatureGate {
open(src: &mut Source, stability: &Stability) -> FeatureGate3354 fn open(src: &mut Source, stability: &Stability) -> FeatureGate {
3355 let close = if let Stability::Unstable { feature, .. } = stability {
3356 let feature_rust_name = feature.to_snake_case();
3357 uwrite!(src, "if options.{feature_rust_name} {{");
3358 true
3359 } else {
3360 false
3361 };
3362 Self { close }
3363 }
3364
close(self, src: &mut Source)3365 fn close(self, src: &mut Source) {
3366 if self.close {
3367 uwriteln!(src, "}}");
3368 }
3369 }
3370 }
3371
3372 /// Produce a string for tracing a function argument.
formatting_for_arg( name: &str, index: usize, ty: Type, resolve: &Resolve, flags: FunctionFlags, ) -> String3373 fn formatting_for_arg(
3374 name: &str,
3375 index: usize,
3376 ty: Type,
3377 resolve: &Resolve,
3378 flags: FunctionFlags,
3379 ) -> String {
3380 if !flags.contains(FunctionFlags::VERBOSE_TRACING) && type_contains_lists(ty, resolve) {
3381 return format!("{name} = tracing::field::debug(\"...\")");
3382 }
3383
3384 // Normal tracing.
3385 format!("{name} = tracing::field::debug(&arg{index})")
3386 }
3387
3388 /// Produce a string for tracing function results.
formatting_for_results(result: Option<Type>, resolve: &Resolve, flags: FunctionFlags) -> String3389 fn formatting_for_results(result: Option<Type>, resolve: &Resolve, flags: FunctionFlags) -> String {
3390 let contains_lists = match result {
3391 Some(ty) => type_contains_lists(ty, resolve),
3392 None => false,
3393 };
3394
3395 if !flags.contains(FunctionFlags::VERBOSE_TRACING) && contains_lists {
3396 return format!("result = tracing::field::debug(\"...\")");
3397 }
3398
3399 // Normal tracing.
3400 format!("result = tracing::field::debug(&r)")
3401 }
3402
3403 /// Test whether the given type contains lists.
3404 ///
3405 /// Here, a `string` is not considered a list.
type_contains_lists(ty: Type, resolve: &Resolve) -> bool3406 fn type_contains_lists(ty: Type, resolve: &Resolve) -> bool {
3407 match ty {
3408 Type::Id(id) => match &resolve.types[id].kind {
3409 TypeDefKind::Resource
3410 | TypeDefKind::Unknown
3411 | TypeDefKind::Flags(_)
3412 | TypeDefKind::Handle(_)
3413 | TypeDefKind::Enum(_)
3414 | TypeDefKind::Stream(_)
3415 | TypeDefKind::Future(_) => false,
3416 TypeDefKind::Option(ty) => type_contains_lists(*ty, resolve),
3417 TypeDefKind::Result(Result_ { ok, err }) => {
3418 option_type_contains_lists(*ok, resolve)
3419 || option_type_contains_lists(*err, resolve)
3420 }
3421 TypeDefKind::Record(record) => record
3422 .fields
3423 .iter()
3424 .any(|field| type_contains_lists(field.ty, resolve)),
3425 TypeDefKind::Tuple(tuple) => tuple
3426 .types
3427 .iter()
3428 .any(|ty| type_contains_lists(*ty, resolve)),
3429 TypeDefKind::Variant(variant) => variant
3430 .cases
3431 .iter()
3432 .any(|case| option_type_contains_lists(case.ty, resolve)),
3433 TypeDefKind::Type(ty) => type_contains_lists(*ty, resolve),
3434 TypeDefKind::List(_) => true,
3435 TypeDefKind::Map(k, v) => {
3436 type_contains_lists(*k, resolve) || type_contains_lists(*v, resolve)
3437 }
3438 TypeDefKind::FixedLengthList(..) => todo!(),
3439 },
3440
3441 // Technically strings are lists too, but we ignore that here because
3442 // they're usually short.
3443 _ => false,
3444 }
3445 }
3446
option_type_contains_lists(ty: Option<Type>, resolve: &Resolve) -> bool3447 fn option_type_contains_lists(ty: Option<Type>, resolve: &Resolve) -> bool {
3448 match ty {
3449 Some(ty) => type_contains_lists(ty, resolve),
3450 None => false,
3451 }
3452 }
3453
3454 /// When an interface `use`s a type from another interface, it creates a new TypeId
3455 /// referring to the definition TypeId. Chase this chain of references down to
3456 /// a TypeId for type's definition.
resolve_type_definition_id(resolve: &Resolve, mut id: TypeId) -> TypeId3457 fn resolve_type_definition_id(resolve: &Resolve, mut id: TypeId) -> TypeId {
3458 loop {
3459 match resolve.types[id].kind {
3460 TypeDefKind::Type(Type::Id(def_id)) => id = def_id,
3461 _ => return id,
3462 }
3463 }
3464 }
3465
rust_function_name(func: &Function) -> String3466 fn rust_function_name(func: &Function) -> String {
3467 match func.kind {
3468 FunctionKind::Constructor(_) => "new".to_string(),
3469 FunctionKind::Method(_)
3470 | FunctionKind::Static(_)
3471 | FunctionKind::AsyncMethod(_)
3472 | FunctionKind::AsyncStatic(_)
3473 | FunctionKind::Freestanding
3474 | FunctionKind::AsyncFreestanding => to_rust_ident(func.item_name()),
3475 }
3476 }
3477
func_field_name(resolve: &Resolve, func: &Function) -> String3478 fn func_field_name(resolve: &Resolve, func: &Function) -> String {
3479 let mut name = String::new();
3480 match func.kind {
3481 FunctionKind::Method(id) | FunctionKind::AsyncMethod(id) => {
3482 name.push_str("method-");
3483 name.push_str(resolve.types[id].name.as_ref().unwrap());
3484 name.push_str("-");
3485 }
3486 FunctionKind::Static(id) | FunctionKind::AsyncStatic(id) => {
3487 name.push_str("static-");
3488 name.push_str(resolve.types[id].name.as_ref().unwrap());
3489 name.push_str("-");
3490 }
3491 FunctionKind::Constructor(id) => {
3492 name.push_str("constructor-");
3493 name.push_str(resolve.types[id].name.as_ref().unwrap());
3494 name.push_str("-");
3495 }
3496 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {}
3497 }
3498 name.push_str(func.item_name());
3499 name.to_snake_case()
3500 }
3501
get_resources<'a>( resolve: &'a Resolve, id: InterfaceId, ) -> impl Iterator<Item = (TypeId, &'a str)> + 'a3502 fn get_resources<'a>(
3503 resolve: &'a Resolve,
3504 id: InterfaceId,
3505 ) -> impl Iterator<Item = (TypeId, &'a str)> + 'a {
3506 resolve.interfaces[id]
3507 .types
3508 .iter()
3509 .filter_map(move |(name, ty)| match &resolve.types[*ty].kind {
3510 TypeDefKind::Resource => Some((*ty, name.as_str())),
3511 _ => None,
3512 })
3513 }
3514
get_resource_functions<'a>(resolve: &'a Resolve, resource_id: TypeId) -> Vec<&'a Function>3515 fn get_resource_functions<'a>(resolve: &'a Resolve, resource_id: TypeId) -> Vec<&'a Function> {
3516 let resource = &resolve.types[resource_id];
3517 match resource.owner {
3518 TypeOwner::World(id) => resolve.worlds[id]
3519 .imports
3520 .values()
3521 .filter_map(|item| match item {
3522 WorldItem::Function(f) => Some(f),
3523 _ => None,
3524 })
3525 .filter(|f| f.kind.resource() == Some(resource_id))
3526 .collect(),
3527 TypeOwner::Interface(id) => resolve.interfaces[id]
3528 .functions
3529 .values()
3530 .filter(|f| f.kind.resource() == Some(resource_id))
3531 .collect::<Vec<_>>(),
3532 TypeOwner::None => {
3533 panic!("A resource must be owned by a world or interface");
3534 }
3535 }
3536 }
3537
get_world_resources<'a>( resolve: &'a Resolve, id: WorldId, ) -> impl Iterator<Item = (TypeId, &'a str)> + 'a3538 fn get_world_resources<'a>(
3539 resolve: &'a Resolve,
3540 id: WorldId,
3541 ) -> impl Iterator<Item = (TypeId, &'a str)> + 'a {
3542 resolve.worlds[id]
3543 .imports
3544 .iter()
3545 .filter_map(move |(name, item)| match item {
3546 WorldItem::Type { id, .. } => match resolve.types[*id].kind {
3547 TypeDefKind::Resource => Some(match name {
3548 WorldKey::Name(s) => (*id, s.as_str()),
3549 WorldKey::Interface(_) => unreachable!(),
3550 }),
3551 _ => None,
3552 },
3553 _ => None,
3554 })
3555 }
3556