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