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