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