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