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