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