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 all_func_flags |= self.opts.imports.default;
1399 all_func_flags |= self.opts.exports.default;
1400
1401 let opt_t_send_bound =
1402 if all_func_flags.contains(FunctionFlags::ASYNC) || self.opts.require_store_data_send {
1403 "+ Send"
1404 } else {
1405 ""
1406 };
1407
1408 let wt = self.wasmtime_path();
1409 if let Some(world_trait) = world_trait {
1410 let d_bound = match &world_trait.with_store_name {
1411 Some(name) => name.clone(),
1412 None => format!("{wt}::component::HasData"),
1413 };
1414 uwrite!(
1415 self.src,
1416 "
1417 pub fn add_to_linker_imports<T, D>(
1418 linker: &mut {wt}::component::Linker<T>,
1419 {options_param}
1420 host_getter: fn(&mut T) -> D::Data<'_>,
1421 ) -> {wt}::Result<()>
1422 where
1423 D: {d_bound},
1424 for<'a> D::Data<'a>: {name},
1425 T: 'static {opt_t_send_bound}
1426 {{
1427 let mut linker = linker.root();
1428 ",
1429 name = world_trait.name,
1430 );
1431 let gate = FeatureGate::open(&mut self.src, &resolve.worlds[world].stability);
1432 for (ty, _name) in get_world_resources(resolve, world) {
1433 self.generate_add_resource_to_linker(None, None, "linker", resolve, ty);
1434 }
1435 for f in self.import_functions.clone() {
1436 let mut generator = InterfaceGenerator::new(self, resolve);
1437 generator.generate_add_function_to_linker(TypeOwner::World(world), &f, "linker");
1438 let src = String::from(generator.src);
1439 self.src.push_str(&src);
1440 self.src.push_str("\n");
1441 }
1442 gate.close(&mut self.src);
1443 uwriteln!(self.src, "Ok(())\n}}");
1444 }
1445
1446 let (sync_bounds, concurrent_bounds) = self.world_host_traits(world_trait);
1447 let sync_bounds = sync_bounds.join(" + ");
1448 let concurrent_bounds = concurrent_bounds.join(" + ");
1449 let d_bounds = if !concurrent_bounds.is_empty() {
1450 concurrent_bounds
1451 } else {
1452 format!("{wt}::component::HasData")
1453 };
1454
1455 uwriteln!(
1456 self.src,
1457 "
1458 pub fn add_to_linker<T, D>(
1459 linker: &mut {wt}::component::Linker<T>,
1460 {options_param}
1461 host_getter: fn(&mut T) -> D::Data<'_>,
1462 ) -> {wt}::Result<()>
1463 where
1464 D: {d_bounds},
1465 for<'a> D::Data<'a>: {sync_bounds},
1466 T: 'static {opt_t_send_bound}
1467 {{
1468 "
1469 );
1470 let gate = FeatureGate::open(&mut self.src, &resolve.worlds[world].stability);
1471 if has_world_imports_trait {
1472 uwriteln!(
1473 self.src,
1474 "Self::add_to_linker_imports::<T, D>(linker {options_arg}, host_getter)?;"
1475 );
1476 }
1477 for (interface_id, path) in self.import_interface_paths() {
1478 let options_arg = if self.interface_link_options[&interface_id].has_any() {
1479 ", &options.into()"
1480 } else {
1481 ""
1482 };
1483
1484 let import_stability = resolve.worlds[world]
1485 .imports
1486 .iter()
1487 .filter_map(|(_, i)| match i {
1488 WorldItem::Interface { id, stability } if *id == interface_id => {
1489 Some(stability.clone())
1490 }
1491 _ => None,
1492 })
1493 .next()
1494 .unwrap_or(Stability::Unknown);
1495
1496 let gate = FeatureGate::open(&mut self.src, &import_stability);
1497 uwriteln!(
1498 self.src,
1499 "{path}::add_to_linker::<T, D>(linker {options_arg}, host_getter)?;"
1500 );
1501 gate.close(&mut self.src);
1502 }
1503 gate.close(&mut self.src);
1504 uwriteln!(self.src, "Ok(())\n}}");
1505 }
1506
1507 fn generate_add_resource_to_linker(
1508 &mut self,
1509 key: Option<&WorldKey>,
1510 src: Option<&mut Source>,
1511 inst: &str,
1512 resolve: &Resolve,
1513 ty: TypeId,
1514 ) {
1515 let ty = &resolve.types[ty];
1516 let name = ty.name.as_ref().unwrap();
1517 let stability = &ty.stability;
1518 let wt = self.wasmtime_path();
1519 let src = src.unwrap_or(&mut self.src);
1520 let gate = FeatureGate::open(src, stability);
1521 let camel = name.to_upper_camel_case();
1522
1523 let flags = self.opts.imports.resource_drop_flags(resolve, key, name);
1524 if flags.contains(FunctionFlags::ASYNC) {
1525 if flags.contains(FunctionFlags::STORE) {
1526 uwriteln!(
1527 src,
1528 "{inst}.resource_concurrent(
1529 \"{name}\",
1530 {wt}::component::ResourceType::host::<{camel}>(),
1531 move |caller: &{wt}::component::Accessor::<T>, rep| {{
1532 {wt}::component::__internal::Box::pin(async move {{
1533 let accessor = &caller.with_getter(host_getter);
1534 Host{camel}WithStore::drop(accessor, {wt}::component::Resource::new_own(rep)).await
1535 }})
1536 }},
1537 )?;"
1538 )
1539 } else {
1540 uwriteln!(
1541 src,
1542 "{inst}.resource_async(
1543 \"{name}\",
1544 {wt}::component::ResourceType::host::<{camel}>(),
1545 move |mut store, rep| {{
1546 {wt}::component::__internal::Box::new(async move {{
1547 Host{camel}::drop(&mut host_getter(store.data_mut()), {wt}::component::Resource::new_own(rep)).await
1548 }})
1549 }},
1550 )?;"
1551 )
1552 }
1553 } else {
1554 let (first_arg, trait_suffix) = if flags.contains(FunctionFlags::STORE) {
1555 (
1556 format!("{wt}::component::Access::new(store, host_getter)"),
1557 "WithStore",
1558 )
1559 } else {
1560 ("&mut host_getter(store.data_mut())".to_string(), "")
1561 };
1562 uwriteln!(
1563 src,
1564 "{inst}.resource(
1565 \"{name}\",
1566 {wt}::component::ResourceType::host::<{camel}>(),
1567 move |mut store, rep| -> {wt}::Result<()> {{
1568
1569 let resource = {wt}::component::Resource::new_own(rep);
1570 Host{camel}{trait_suffix}::drop({first_arg}, resource)
1571 }},
1572 )?;",
1573 )
1574 }
1575 gate.close(src);
1576 }
1577}
1578
1579struct InterfaceGenerator<'a> {
1580 src: Source,
1581 generator: &'a mut Wasmtime,
1582 resolve: &'a Resolve,
1583 current_interface: Option<(InterfaceId, &'a WorldKey, bool)>,
1584 all_func_flags: FunctionFlags,
1585}
1586
1587impl<'a> InterfaceGenerator<'a> {
1588 fn new(generator: &'a mut Wasmtime, resolve: &'a Resolve) -> InterfaceGenerator<'a> {
1589 InterfaceGenerator {
1590 src: Source::default(),
1591 generator,
1592 resolve,
1593 current_interface: None,
1594 all_func_flags: FunctionFlags::empty(),
1595 }
1596 }
1597
1598 fn types_imported(&self) -> bool {
1599 match self.current_interface {
1600 Some((_, _, is_export)) => !is_export,
1601 None => true,
1602 }
1603 }
1604
1605 fn types(&mut self, id: InterfaceId) {
1606 for (name, id) in self.resolve.interfaces[id].types.iter() {
1607 self.define_type(name, *id);
1608 }
1609 }
1610
1611 fn define_type(&mut self, name: &str, id: TypeId) {
1612 let ty = &self.resolve.types[id];
1613 match &ty.kind {
1614 TypeDefKind::Record(record) => self.type_record(id, name, record, &ty.docs),
1615 TypeDefKind::Flags(flags) => self.type_flags(id, name, flags, &ty.docs),
1616 TypeDefKind::Tuple(tuple) => self.type_tuple(id, name, tuple, &ty.docs),
1617 TypeDefKind::Enum(enum_) => self.type_enum(id, name, enum_, &ty.docs),
1618 TypeDefKind::Variant(variant) => self.type_variant(id, name, variant, &ty.docs),
1619 TypeDefKind::Option(t) => self.type_option(id, name, t, &ty.docs),
1620 TypeDefKind::Result(r) => self.type_result(id, name, r, &ty.docs),
1621 TypeDefKind::List(t) => self.type_list(id, name, t, &ty.docs),
1622 TypeDefKind::Type(t) => self.type_alias(id, name, t, &ty.docs),
1623 TypeDefKind::Future(t) => self.type_future(id, name, t.as_ref(), &ty.docs),
1624 TypeDefKind::Stream(t) => self.type_stream(id, name, t.as_ref(), &ty.docs),
1625 TypeDefKind::Handle(handle) => self.type_handle(id, name, handle, &ty.docs),
1626 TypeDefKind::Resource => self.type_resource(id, name, ty, &ty.docs),
1627 TypeDefKind::Unknown => unreachable!(),
1628 TypeDefKind::FixedSizeList(..) => todo!(),
1629 }
1630 }
1631
1632 fn type_handle(&mut self, id: TypeId, name: &str, handle: &Handle, docs: &Docs) {
1633 self.rustdoc(docs);
1634 let name = name.to_upper_camel_case();
1635 uwriteln!(self.src, "pub type {name} = ");
1636 self.print_handle(handle);
1637 self.push_str(";\n");
1638 self.assert_type(id, &name);
1639 }
1640
1641 fn type_resource(&mut self, id: TypeId, name: &str, _resource: &TypeDef, docs: &Docs) {
1642 let camel = name.to_upper_camel_case();
1643 let wt = self.generator.wasmtime_path();
1644
1645 if self.types_imported() {
1646 self.rustdoc(docs);
1647
1648 let replacement = match self.current_interface {
1649 Some((_, key, _)) => {
1650 self.generator
1651 .lookup_replacement(self.resolve, key, Some(name))
1652 }
1653 None => {
1654 self.generator.used_with_opts.insert(name.into());
1655 self.generator.opts.with.get(name).cloned()
1656 }
1657 };
1658 match replacement {
1659 Some(path) => {
1660 uwriteln!(
1661 self.src,
1662 "pub use {}{path} as {camel};",
1663 self.path_to_root()
1664 );
1665 }
1666 None => {
1667 uwriteln!(self.src, "pub enum {camel} {{}}");
1668 }
1669 }
1670
1671 let functions = get_resource_functions(self.resolve, id);
1674 let trait_ = self.generate_trait(
1675 &format!("Host{camel}"),
1676 &functions,
1677 &[ExtraTraitMethod::ResourceDrop { name }],
1678 &[],
1679 );
1680 self.all_func_flags |= trait_.all_func_flags;
1681 } else {
1682 self.rustdoc(docs);
1683 uwriteln!(
1684 self.src,
1685 "
1686 pub type {camel} = {wt}::component::ResourceAny;
1687
1688 pub struct Guest{camel}<'a> {{
1689 funcs: &'a Guest,
1690 }}
1691 "
1692 );
1693 }
1694 }
1695
1696 fn type_record(&mut self, id: TypeId, _name: &str, record: &Record, docs: &Docs) {
1697 let info = self.info(id);
1698 let wt = self.generator.wasmtime_path();
1699
1700 let additional_derives: BTreeSet<String> = self
1702 .generator
1703 .opts
1704 .additional_derive_attributes
1705 .iter()
1706 .cloned()
1707 .collect();
1708
1709 for (name, mode) in self.modes_of(id) {
1710 let lt = self.lifetime_for(&info, mode);
1711 self.rustdoc(docs);
1712
1713 let mut derives = additional_derives.clone();
1714
1715 uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]");
1716 if lt.is_none() {
1717 uwriteln!(self.src, "#[derive({wt}::component::Lift)]");
1718 }
1719 uwriteln!(self.src, "#[derive({wt}::component::Lower)]");
1720 self.push_str("#[component(record)]\n");
1721 if let Some(path) = &self.generator.opts.wasmtime_crate {
1722 uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n");
1723 }
1724
1725 if info.is_copy() {
1726 derives.extend(["Copy", "Clone"].into_iter().map(|s| s.to_string()));
1727 } else if info.is_clone() {
1728 derives.insert("Clone".to_string());
1729 }
1730
1731 if !derives.is_empty() {
1732 self.push_str("#[derive(");
1733 self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", "));
1734 self.push_str(")]\n")
1735 }
1736
1737 self.push_str(&format!("pub struct {name}"));
1738 self.print_generics(lt);
1739 self.push_str(" {\n");
1740 for field in record.fields.iter() {
1741 self.rustdoc(&field.docs);
1742 self.push_str(&format!("#[component(name = \"{}\")]\n", field.name));
1743 self.push_str("pub ");
1744 self.push_str(&to_rust_ident(&field.name));
1745 self.push_str(": ");
1746 self.print_ty(&field.ty, mode);
1747 self.push_str(",\n");
1748 }
1749 self.push_str("}\n");
1750
1751 self.push_str("impl");
1752 self.print_generics(lt);
1753 self.push_str(" core::fmt::Debug for ");
1754 self.push_str(&name);
1755 self.print_generics(lt);
1756 self.push_str(" {\n");
1757 self.push_str(
1758 "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n",
1759 );
1760 self.push_str(&format!("f.debug_struct(\"{name}\")"));
1761 for field in record.fields.iter() {
1762 self.push_str(&format!(
1763 ".field(\"{}\", &self.{})",
1764 field.name,
1765 to_rust_ident(&field.name)
1766 ));
1767 }
1768 self.push_str(".finish()\n");
1769 self.push_str("}\n");
1770 self.push_str("}\n");
1771
1772 if info.error {
1773 self.push_str("impl");
1774 self.print_generics(lt);
1775 self.push_str(" core::fmt::Display for ");
1776 self.push_str(&name);
1777 self.print_generics(lt);
1778 self.push_str(" {\n");
1779 self.push_str(
1780 "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n",
1781 );
1782 self.push_str("write!(f, \"{:?}\", self)\n");
1783 self.push_str("}\n");
1784 self.push_str("}\n");
1785
1786 self.push_str("impl core::error::Error for ");
1787 self.push_str(&name);
1788 self.push_str("{}\n");
1789 }
1790 self.assert_type(id, &name);
1791 }
1792 }
1793
1794 fn type_tuple(&mut self, id: TypeId, _name: &str, tuple: &Tuple, docs: &Docs) {
1795 let info = self.info(id);
1796 for (name, mode) in self.modes_of(id) {
1797 let lt = self.lifetime_for(&info, mode);
1798 self.rustdoc(docs);
1799 self.push_str(&format!("pub type {name}"));
1800 self.print_generics(lt);
1801 self.push_str(" = (");
1802 for ty in tuple.types.iter() {
1803 self.print_ty(ty, mode);
1804 self.push_str(",");
1805 }
1806 self.push_str(");\n");
1807 self.assert_type(id, &name);
1808 }
1809 }
1810
1811 fn type_flags(&mut self, id: TypeId, name: &str, flags: &Flags, docs: &Docs) {
1812 self.rustdoc(docs);
1813 let wt = self.generator.wasmtime_path();
1814 let rust_name = to_rust_upper_camel_case(name);
1815 uwriteln!(self.src, "{wt}::component::flags!(\n");
1816 self.src.push_str(&format!("{rust_name} {{\n"));
1817 for flag in flags.flags.iter() {
1818 uwrite!(
1820 self.src,
1821 "#[component(name=\"{}\")] const {};\n",
1822 flag.name,
1823 flag.name.to_shouty_snake_case()
1824 );
1825 }
1826 self.src.push_str("}\n");
1827 self.src.push_str(");\n\n");
1828 self.assert_type(id, &rust_name);
1829 }
1830
1831 fn type_variant(&mut self, id: TypeId, _name: &str, variant: &Variant, docs: &Docs) {
1832 self.print_rust_enum(
1833 id,
1834 variant.cases.iter().map(|c| {
1835 (
1836 c.name.to_upper_camel_case(),
1837 Some(c.name.clone()),
1838 &c.docs,
1839 c.ty.as_ref(),
1840 )
1841 }),
1842 docs,
1843 "variant",
1844 );
1845 }
1846
1847 fn type_option(&mut self, id: TypeId, _name: &str, payload: &Type, docs: &Docs) {
1848 let info = self.info(id);
1849
1850 for (name, mode) in self.modes_of(id) {
1851 self.rustdoc(docs);
1852 let lt = self.lifetime_for(&info, mode);
1853 self.push_str(&format!("pub type {name}"));
1854 self.print_generics(lt);
1855 self.push_str("= Option<");
1856 self.print_ty(payload, mode);
1857 self.push_str(">;\n");
1858 self.assert_type(id, &name);
1859 }
1860 }
1861
1862 fn assert_type(&mut self, id: TypeId, name: &str) {
1865 self.push_str("const _: () = {\n");
1866 let wt = self.generator.wasmtime_path();
1867 uwriteln!(
1868 self.src,
1869 "assert!({} == <{name} as {wt}::component::ComponentType>::SIZE32);",
1870 self.generator.sizes.size(&Type::Id(id)).size_wasm32(),
1871 );
1872 uwriteln!(
1873 self.src,
1874 "assert!({} == <{name} as {wt}::component::ComponentType>::ALIGN32);",
1875 self.generator.sizes.align(&Type::Id(id)).align_wasm32(),
1876 );
1877 self.push_str("};\n");
1878 }
1879
1880 fn print_rust_enum<'b>(
1881 &mut self,
1882 id: TypeId,
1883 cases: impl IntoIterator<Item = (String, Option<String>, &'b Docs, Option<&'b Type>)> + Clone,
1884 docs: &Docs,
1885 derive_component: &str,
1886 ) where
1887 Self: Sized,
1888 {
1889 let info = self.info(id);
1890 let wt = self.generator.wasmtime_path();
1891
1892 let additional_derives: BTreeSet<String> = self
1894 .generator
1895 .opts
1896 .additional_derive_attributes
1897 .iter()
1898 .cloned()
1899 .collect();
1900
1901 for (name, mode) in self.modes_of(id) {
1902 let name = to_rust_upper_camel_case(&name);
1903
1904 let mut derives = additional_derives.clone();
1905
1906 self.rustdoc(docs);
1907 let lt = self.lifetime_for(&info, mode);
1908 uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]");
1909 if lt.is_none() {
1910 uwriteln!(self.src, "#[derive({wt}::component::Lift)]");
1911 }
1912 uwriteln!(self.src, "#[derive({wt}::component::Lower)]");
1913 self.push_str(&format!("#[component({derive_component})]\n"));
1914 if let Some(path) = &self.generator.opts.wasmtime_crate {
1915 uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n");
1916 }
1917 if info.is_copy() {
1918 derives.extend(["Copy", "Clone"].into_iter().map(|s| s.to_string()));
1919 } else if info.is_clone() {
1920 derives.insert("Clone".to_string());
1921 }
1922
1923 if !derives.is_empty() {
1924 self.push_str("#[derive(");
1925 self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", "));
1926 self.push_str(")]\n")
1927 }
1928
1929 self.push_str(&format!("pub enum {name}"));
1930 self.print_generics(lt);
1931 self.push_str("{\n");
1932 for (case_name, component_name, docs, payload) in cases.clone() {
1933 self.rustdoc(docs);
1934 if let Some(n) = component_name {
1935 self.push_str(&format!("#[component(name = \"{n}\")] "));
1936 }
1937 self.push_str(&case_name);
1938 if let Some(ty) = payload {
1939 self.push_str("(");
1940 self.print_ty(ty, mode);
1941 self.push_str(")")
1942 }
1943 self.push_str(",\n");
1944 }
1945 self.push_str("}\n");
1946
1947 self.print_rust_enum_debug(
1948 id,
1949 mode,
1950 &name,
1951 cases
1952 .clone()
1953 .into_iter()
1954 .map(|(name, _attr, _docs, ty)| (name, ty)),
1955 );
1956
1957 if info.error {
1958 self.push_str("impl");
1959 self.print_generics(lt);
1960 self.push_str(" core::fmt::Display for ");
1961 self.push_str(&name);
1962 self.print_generics(lt);
1963 self.push_str(" {\n");
1964 self.push_str(
1965 "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n",
1966 );
1967 self.push_str("write!(f, \"{:?}\", self)\n");
1968 self.push_str("}\n");
1969 self.push_str("}\n");
1970
1971 self.push_str("impl");
1972 self.print_generics(lt);
1973 self.push_str(" core::error::Error for ");
1974 self.push_str(&name);
1975 self.print_generics(lt);
1976 self.push_str(" {}\n");
1977 }
1978
1979 self.assert_type(id, &name);
1980 }
1981 }
1982
1983 fn print_rust_enum_debug<'b>(
1984 &mut self,
1985 id: TypeId,
1986 mode: TypeMode,
1987 name: &str,
1988 cases: impl IntoIterator<Item = (String, Option<&'b Type>)>,
1989 ) where
1990 Self: Sized,
1991 {
1992 let info = self.info(id);
1993 let lt = self.lifetime_for(&info, mode);
1994 self.push_str("impl");
1995 self.print_generics(lt);
1996 self.push_str(" core::fmt::Debug for ");
1997 self.push_str(name);
1998 self.print_generics(lt);
1999 self.push_str(" {\n");
2000 self.push_str("fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n");
2001 self.push_str("match self {\n");
2002 for (case_name, payload) in cases {
2003 self.push_str(name);
2004 self.push_str("::");
2005 self.push_str(&case_name);
2006 if payload.is_some() {
2007 self.push_str("(e)");
2008 }
2009 self.push_str(" => {\n");
2010 self.push_str(&format!("f.debug_tuple(\"{name}::{case_name}\")"));
2011 if payload.is_some() {
2012 self.push_str(".field(e)");
2013 }
2014 self.push_str(".finish()\n");
2015 self.push_str("}\n");
2016 }
2017 self.push_str("}\n");
2018 self.push_str("}\n");
2019 self.push_str("}\n");
2020 }
2021
2022 fn type_result(&mut self, id: TypeId, _name: &str, result: &Result_, docs: &Docs) {
2023 let info = self.info(id);
2024
2025 for (name, mode) in self.modes_of(id) {
2026 self.rustdoc(docs);
2027 let lt = self.lifetime_for(&info, mode);
2028 self.push_str(&format!("pub type {name}"));
2029 self.print_generics(lt);
2030 self.push_str("= Result<");
2031 self.print_optional_ty(result.ok.as_ref(), mode);
2032 self.push_str(",");
2033 self.print_optional_ty(result.err.as_ref(), mode);
2034 self.push_str(">;\n");
2035 self.assert_type(id, &name);
2036 }
2037 }
2038
2039 fn type_enum(&mut self, id: TypeId, name: &str, enum_: &Enum, docs: &Docs) {
2040 let info = self.info(id);
2041 let wt = self.generator.wasmtime_path();
2042
2043 let mut derives: BTreeSet<String> = self
2045 .generator
2046 .opts
2047 .additional_derive_attributes
2048 .iter()
2049 .cloned()
2050 .collect();
2051
2052 derives.extend(
2053 ["Clone", "Copy", "PartialEq", "Eq"]
2054 .into_iter()
2055 .map(|s| s.to_string()),
2056 );
2057
2058 let name = to_rust_upper_camel_case(name);
2059 self.rustdoc(docs);
2060 uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]");
2061 uwriteln!(self.src, "#[derive({wt}::component::Lift)]");
2062 uwriteln!(self.src, "#[derive({wt}::component::Lower)]");
2063 self.push_str("#[component(enum)]\n");
2064 if let Some(path) = &self.generator.opts.wasmtime_crate {
2065 uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n");
2066 }
2067
2068 self.push_str("#[derive(");
2069 self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", "));
2070 self.push_str(")]\n");
2071
2072 let repr = match enum_.cases.len().ilog2() {
2073 0..=7 => "u8",
2074 8..=15 => "u16",
2075 _ => "u32",
2076 };
2077 uwriteln!(self.src, "#[repr({repr})]");
2078
2079 self.push_str(&format!("pub enum {name} {{\n"));
2080 for case in enum_.cases.iter() {
2081 self.rustdoc(&case.docs);
2082 self.push_str(&format!("#[component(name = \"{}\")]", case.name));
2083 self.push_str(&case.name.to_upper_camel_case());
2084 self.push_str(",\n");
2085 }
2086 self.push_str("}\n");
2087
2088 if info.error {
2091 self.push_str("impl ");
2092 self.push_str(&name);
2093 self.push_str("{\n");
2094
2095 self.push_str("pub fn name(&self) -> &'static str {\n");
2096 self.push_str("match self {\n");
2097 for case in enum_.cases.iter() {
2098 self.push_str(&name);
2099 self.push_str("::");
2100 self.push_str(&case.name.to_upper_camel_case());
2101 self.push_str(" => \"");
2102 self.push_str(case.name.as_str());
2103 self.push_str("\",\n");
2104 }
2105 self.push_str("}\n");
2106 self.push_str("}\n");
2107
2108 self.push_str("pub fn message(&self) -> &'static str {\n");
2109 self.push_str("match self {\n");
2110 for case in enum_.cases.iter() {
2111 self.push_str(&name);
2112 self.push_str("::");
2113 self.push_str(&case.name.to_upper_camel_case());
2114 self.push_str(" => \"");
2115 if let Some(contents) = &case.docs.contents {
2116 self.push_str(contents.trim());
2117 }
2118 self.push_str("\",\n");
2119 }
2120 self.push_str("}\n");
2121 self.push_str("}\n");
2122
2123 self.push_str("}\n");
2124
2125 self.push_str("impl core::fmt::Debug for ");
2126 self.push_str(&name);
2127 self.push_str(
2128 "{\nfn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n",
2129 );
2130 self.push_str("f.debug_struct(\"");
2131 self.push_str(&name);
2132 self.push_str("\")\n");
2133 self.push_str(".field(\"code\", &(*self as i32))\n");
2134 self.push_str(".field(\"name\", &self.name())\n");
2135 self.push_str(".field(\"message\", &self.message())\n");
2136 self.push_str(".finish()\n");
2137 self.push_str("}\n");
2138 self.push_str("}\n");
2139
2140 self.push_str("impl core::fmt::Display for ");
2141 self.push_str(&name);
2142 self.push_str(
2143 "{\nfn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n",
2144 );
2145 self.push_str("write!(f, \"{} (error {})\", self.name(), *self as i32)");
2146 self.push_str("}\n");
2147 self.push_str("}\n");
2148 self.push_str("\n");
2149 self.push_str("impl core::error::Error for ");
2150 self.push_str(&name);
2151 self.push_str("{}\n");
2152 } else {
2153 self.print_rust_enum_debug(
2154 id,
2155 TypeMode::Owned,
2156 &name,
2157 enum_
2158 .cases
2159 .iter()
2160 .map(|c| (c.name.to_upper_camel_case(), None)),
2161 )
2162 }
2163 self.assert_type(id, &name);
2164 }
2165
2166 fn type_alias(&mut self, id: TypeId, _name: &str, ty: &Type, docs: &Docs) {
2167 let info = self.info(id);
2168 for (name, mode) in self.modes_of(id) {
2169 self.rustdoc(docs);
2170 self.push_str(&format!("pub type {name}"));
2171 let lt = self.lifetime_for(&info, mode);
2172 self.print_generics(lt);
2173 self.push_str(" = ");
2174 self.print_ty(ty, mode);
2175 self.push_str(";\n");
2176 let def_id = resolve_type_definition_id(self.resolve, id);
2177 if !matches!(self.resolve().types[def_id].kind, TypeDefKind::Resource) {
2178 self.assert_type(id, &name);
2179 }
2180 }
2181 }
2182
2183 fn type_list(&mut self, id: TypeId, _name: &str, ty: &Type, docs: &Docs) {
2184 let info = self.info(id);
2185 for (name, mode) in self.modes_of(id) {
2186 let lt = self.lifetime_for(&info, mode);
2187 self.rustdoc(docs);
2188 self.push_str(&format!("pub type {name}"));
2189 self.print_generics(lt);
2190 self.push_str(" = ");
2191 self.print_list(ty, mode);
2192 self.push_str(";\n");
2193 self.assert_type(id, &name);
2194 }
2195 }
2196
2197 fn type_stream(&mut self, id: TypeId, name: &str, ty: Option<&Type>, docs: &Docs) {
2198 self.rustdoc(docs);
2199 self.push_str(&format!("pub type {name}"));
2200 self.print_generics(None);
2201 self.push_str(" = ");
2202 self.print_stream(ty);
2203 self.push_str(";\n");
2204 self.assert_type(id, &name);
2205 }
2206
2207 fn type_future(&mut self, id: TypeId, name: &str, ty: Option<&Type>, docs: &Docs) {
2208 self.rustdoc(docs);
2209 self.push_str(&format!("pub type {name}"));
2210 self.print_generics(None);
2211 self.push_str(" = ");
2212 self.print_future(ty);
2213 self.push_str(";\n");
2214 self.assert_type(id, &name);
2215 }
2216
2217 fn print_result_ty(&mut self, result: Option<Type>, mode: TypeMode) {
2218 match result {
2219 Some(ty) => self.print_ty(&ty, mode),
2220 None => self.push_str("()"),
2221 }
2222 }
2223
2224 fn special_case_trappable_error(
2225 &mut self,
2226 func: &Function,
2227 ) -> Option<(&'a Result_, TypeId, String)> {
2228 let result = func.result?;
2229
2230 let id = match result {
2234 Type::Id(id) => id,
2235 _ => return None,
2236 };
2237 let result = match &self.resolve.types[id].kind {
2238 TypeDefKind::Result(r) => r,
2239 _ => return None,
2240 };
2241 let error_typeid = match result.err? {
2242 Type::Id(id) => resolve_type_definition_id(&self.resolve, id),
2243 _ => return None,
2244 };
2245
2246 let name = self.generator.trappable_errors.get(&error_typeid)?;
2247
2248 let mut path = self.path_to_root();
2249 uwrite!(path, "{name}");
2250 Some((result, error_typeid, path))
2251 }
2252
2253 fn generate_add_to_linker(&mut self, id: InterfaceId, name: &str) {
2254 let iface = &self.resolve.interfaces[id];
2255 let owner = TypeOwner::Interface(id);
2256 let wt = self.generator.wasmtime_path();
2257
2258 let mut required_conversion_traits = IndexSet::new();
2259 let extra_functions = {
2260 let mut functions = Vec::new();
2261 let mut errors_converted = IndexMap::new();
2262 let mut my_error_types = iface
2263 .types
2264 .iter()
2265 .filter(|(_, id)| self.generator.trappable_errors.contains_key(*id))
2266 .map(|(_, id)| *id)
2267 .collect::<Vec<_>>();
2268 my_error_types.extend(
2269 iface
2270 .functions
2271 .iter()
2272 .filter_map(|(_, func)| self.special_case_trappable_error(func))
2273 .map(|(_, id, _)| id),
2274 );
2275 for err_id in my_error_types {
2276 let err = &self.resolve.types[resolve_type_definition_id(self.resolve, err_id)];
2277 let err_name = err.name.as_ref().unwrap();
2278 let owner = match err.owner {
2279 TypeOwner::Interface(i) => i,
2280 _ => unimplemented!(),
2281 };
2282 match self.path_to_interface(owner) {
2283 Some(path) => {
2284 required_conversion_traits.insert(format!("{path}::Host"));
2285 }
2286 None => {
2287 if errors_converted.insert(err_name, err_id).is_none() {
2288 functions.push(ExtraTraitMethod::ErrorConvert {
2289 name: err_name,
2290 id: err_id,
2291 })
2292 }
2293 }
2294 }
2295 }
2296 functions
2297 };
2298
2299 let generated_trait = self.generate_trait(
2303 "Host",
2304 &iface
2305 .functions
2306 .iter()
2307 .filter_map(|(_, f)| {
2308 if f.kind.resource().is_none() {
2309 Some(f)
2310 } else {
2311 None
2312 }
2313 })
2314 .collect::<Vec<_>>(),
2315 &extra_functions,
2316 &get_resources(self.resolve, id).collect::<Vec<_>>(),
2317 );
2318
2319 let opt_t_send_bound = if generated_trait
2320 .all_func_flags
2321 .contains(FunctionFlags::ASYNC)
2322 {
2323 "+ Send"
2324 } else {
2325 ""
2326 };
2327
2328 let mut sync_bounds = "Host".to_string();
2329
2330 for ty in required_conversion_traits {
2331 uwrite!(sync_bounds, " + {ty}");
2332 }
2333
2334 let options_param = if self.generator.interface_link_options[&id].has_any() {
2335 "options: &LinkOptions,"
2336 } else {
2337 ""
2338 };
2339
2340 uwriteln!(
2341 self.src,
2342 "
2343 pub fn add_to_linker<T, D>(
2344 linker: &mut {wt}::component::Linker<T>,
2345 {options_param}
2346 host_getter: fn(&mut T) -> D::Data<'_>,
2347 ) -> {wt}::Result<()>
2348 where
2349 D: HostWithStore,
2350 for<'a> D::Data<'a>: {sync_bounds},
2351 T: 'static {opt_t_send_bound},
2352 {{
2353 "
2354 );
2355
2356 let gate = FeatureGate::open(&mut self.src, &iface.stability);
2357 uwriteln!(self.src, "let mut inst = linker.instance(\"{name}\")?;");
2358
2359 for (ty, _name) in get_resources(self.resolve, id) {
2360 self.generator.generate_add_resource_to_linker(
2361 self.current_interface.map(|p| p.1),
2362 Some(&mut self.src),
2363 "inst",
2364 self.resolve,
2365 ty,
2366 );
2367 }
2368
2369 for (_, func) in iface.functions.iter() {
2370 self.generate_add_function_to_linker(owner, func, "inst");
2371 }
2372 gate.close(&mut self.src);
2373 uwriteln!(self.src, "Ok(())");
2374 uwriteln!(self.src, "}}");
2375 }
2376
2377 fn import_resource_drop_flags(&mut self, name: &str) -> FunctionFlags {
2378 self.generator.opts.imports.resource_drop_flags(
2379 self.resolve,
2380 self.current_interface.map(|p| p.1),
2381 name,
2382 )
2383 }
2384
2385 fn generate_add_function_to_linker(&mut self, owner: TypeOwner, func: &Function, linker: &str) {
2386 let flags = self.generator.opts.imports.flags(
2387 self.resolve,
2388 self.current_interface.map(|p| p.1),
2389 func,
2390 );
2391 self.all_func_flags |= flags;
2392 let gate = FeatureGate::open(&mut self.src, &func.stability);
2393 uwrite!(
2394 self.src,
2395 "{linker}.{}(\"{}\", ",
2396 if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {
2397 "func_wrap_concurrent"
2398 } else if flags.contains(FunctionFlags::ASYNC) {
2399 "func_wrap_async"
2400 } else {
2401 "func_wrap"
2402 },
2403 func.name
2404 );
2405 self.generate_guest_import_closure(owner, func, flags);
2406 uwriteln!(self.src, ")?;");
2407 gate.close(&mut self.src);
2408 }
2409
2410 fn generate_guest_import_closure(
2411 &mut self,
2412 owner: TypeOwner,
2413 func: &Function,
2414 flags: FunctionFlags,
2415 ) {
2416 let wt = self.generator.wasmtime_path();
2420 if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {
2421 uwrite!(self.src, "move |caller: &{wt}::component::Accessor::<T>, (");
2422 } else {
2423 uwrite!(
2424 self.src,
2425 "move |mut caller: {wt}::StoreContextMut<'_, T>, ("
2426 );
2427 }
2428 for (i, _param) in func.params.iter().enumerate() {
2429 uwrite!(self.src, "arg{},", i);
2430 }
2431 self.src.push_str(") : (");
2432
2433 for (_, ty) in func.params.iter() {
2434 self.print_ty(ty, TypeMode::Owned);
2437 self.src.push_str(", ");
2438 }
2439 self.src.push_str(")| {\n");
2440
2441 if flags.contains(FunctionFlags::TRACING) {
2442 if flags.contains(FunctionFlags::ASYNC) {
2443 self.src.push_str("use tracing::Instrument;\n");
2444 }
2445
2446 uwrite!(
2447 self.src,
2448 "
2449 let span = tracing::span!(
2450 tracing::Level::TRACE,
2451 \"wit-bindgen import\",
2452 module = \"{}\",
2453 function = \"{}\",
2454 );
2455 ",
2456 match owner {
2457 TypeOwner::Interface(id) => self.resolve.interfaces[id]
2458 .name
2459 .as_deref()
2460 .unwrap_or("<no module>"),
2461 TypeOwner::World(id) => &self.resolve.worlds[id].name,
2462 TypeOwner::None => "<no owner>",
2463 },
2464 func.name,
2465 );
2466 }
2467
2468 if flags.contains(FunctionFlags::ASYNC) {
2469 let ctor = if flags.contains(FunctionFlags::STORE) {
2470 "pin"
2471 } else {
2472 "new"
2473 };
2474 uwriteln!(
2475 self.src,
2476 "{wt}::component::__internal::Box::{ctor}(async move {{"
2477 );
2478 } else {
2479 if flags.contains(FunctionFlags::TRACING) {
2483 self.push_str("let _enter = span.enter();\n");
2484 }
2485 }
2486
2487 if flags.contains(FunctionFlags::TRACING) {
2488 let mut event_fields = func
2489 .params
2490 .iter()
2491 .enumerate()
2492 .map(|(i, (name, ty))| {
2493 let name = to_rust_ident(&name);
2494 formatting_for_arg(&name, i, *ty, &self.resolve, flags)
2495 })
2496 .collect::<Vec<String>>();
2497 event_fields.push(format!("\"call\""));
2498 uwrite!(
2499 self.src,
2500 "tracing::event!(tracing::Level::TRACE, {});\n",
2501 event_fields.join(", ")
2502 );
2503 }
2504
2505 if flags.contains(FunctionFlags::STORE) {
2506 if flags.contains(FunctionFlags::ASYNC) {
2507 uwriteln!(self.src, "let host = &caller.with_getter(host_getter);");
2508 } else {
2509 uwriteln!(
2510 self.src,
2511 "let host = {wt}::component::Access::new(caller, host_getter);"
2512 );
2513 }
2514 } else {
2515 self.src
2516 .push_str("let host = &mut host_getter(caller.data_mut());\n");
2517 }
2518 let func_name = rust_function_name(func);
2519 let host_trait = match func.kind.resource() {
2520 None => match owner {
2521 TypeOwner::World(id) => format!(
2522 "{}Imports",
2523 rust::to_rust_upper_camel_case(&self.resolve.worlds[id].name)
2524 ),
2525 _ => "Host".to_string(),
2526 },
2527 Some(id) => {
2528 let resource = self.resolve.types[id]
2529 .name
2530 .as_ref()
2531 .unwrap()
2532 .to_upper_camel_case();
2533 format!("Host{resource}")
2534 }
2535 };
2536
2537 if flags.contains(FunctionFlags::STORE) {
2538 uwrite!(
2539 self.src,
2540 "let r = <D as {host_trait}WithStore>::{func_name}(host, "
2541 );
2542 } else {
2543 uwrite!(self.src, "let r = {host_trait}::{func_name}(host, ");
2544 }
2545
2546 for (i, _) in func.params.iter().enumerate() {
2547 uwrite!(self.src, "arg{},", i);
2548 }
2549
2550 self.src.push_str(if flags.contains(FunctionFlags::ASYNC) {
2551 ").await;\n"
2552 } else {
2553 ");\n"
2554 });
2555
2556 if flags.contains(FunctionFlags::TRACING) {
2557 uwrite!(
2558 self.src,
2559 "tracing::event!(tracing::Level::TRACE, {}, \"return\");",
2560 formatting_for_results(func.result, &self.resolve, flags)
2561 );
2562 }
2563
2564 if !flags.contains(FunctionFlags::TRAPPABLE) {
2565 if func.result.is_some() {
2566 uwrite!(self.src, "Ok((r,))\n");
2567 } else {
2568 uwrite!(self.src, "Ok(r)\n");
2569 }
2570 } else if let Some((_, err, _)) = self.special_case_trappable_error(func) {
2571 let err = &self.resolve.types[resolve_type_definition_id(self.resolve, err)];
2572 let err_name = err.name.as_ref().unwrap();
2573 let owner = match err.owner {
2574 TypeOwner::Interface(i) => i,
2575 _ => unimplemented!(),
2576 };
2577 let convert_trait = match self.path_to_interface(owner) {
2578 Some(path) => format!("{path}::Host"),
2579 None => format!("Host"),
2580 };
2581 let convert = format!("{}::convert_{}", convert_trait, err_name.to_snake_case());
2582 let convert = if flags.contains(FunctionFlags::STORE) {
2583 if flags.contains(FunctionFlags::ASYNC) {
2584 format!("host.with(|mut host| {convert}(&mut host.get(), e))?")
2585 } else {
2586 format!("{convert}(&mut host.get(), e)?")
2587 }
2588 } else {
2589 format!("{convert}(host, e)?")
2590 };
2591 uwrite!(
2592 self.src,
2593 "Ok((match r {{
2594 Ok(a) => Ok(a),
2595 Err(e) => Err({convert}),
2596 }},))"
2597 );
2598 } else if func.result.is_some() {
2599 uwrite!(self.src, "Ok((r?,))\n");
2600 } else {
2601 uwrite!(self.src, "r\n");
2602 }
2603
2604 if flags.contains(FunctionFlags::ASYNC) {
2605 if flags.contains(FunctionFlags::TRACING) {
2606 self.src.push_str("}.instrument(span))\n");
2607 } else {
2608 self.src.push_str("})\n");
2609 }
2610 }
2611
2612 self.src.push_str("}\n");
2613 }
2614
2615 fn generate_function_trait_sig(&mut self, func: &Function, flags: FunctionFlags) {
2616 let wt = self.generator.wasmtime_path();
2617 self.rustdoc(&func.docs);
2618
2619 self.push_str("fn ");
2620 self.push_str(&rust_function_name(func));
2621 if flags.contains(FunctionFlags::STORE | FunctionFlags::ASYNC) {
2622 uwrite!(
2623 self.src,
2624 "<T>(accessor: &{wt}::component::Accessor<T, Self>, "
2625 );
2626 } else if flags.contains(FunctionFlags::STORE) {
2627 uwrite!(self.src, "<T>(host: {wt}::component::Access<T, Self>, ");
2628 } else {
2629 self.push_str("(&mut self, ");
2630 }
2631 self.generate_function_params(func);
2632 self.push_str(")");
2633 self.push_str(" -> ");
2634
2635 if flags.contains(FunctionFlags::ASYNC) {
2636 uwrite!(self.src, "impl ::core::future::Future<Output = ");
2637 }
2638
2639 self.all_func_flags |= flags;
2640 self.generate_function_result(func, flags);
2641
2642 if flags.contains(FunctionFlags::ASYNC) {
2643 self.push_str("> + Send");
2644 }
2645 }
2646
2647 fn generate_function_params(&mut self, func: &Function) {
2648 for (name, param) in func.params.iter() {
2649 let name = to_rust_ident(name);
2650 self.push_str(&name);
2651 self.push_str(": ");
2652 self.print_ty(param, TypeMode::Owned);
2653 self.push_str(",");
2654 }
2655 }
2656
2657 fn generate_function_result(&mut self, func: &Function, flags: FunctionFlags) {
2658 if !flags.contains(FunctionFlags::TRAPPABLE) {
2659 self.print_result_ty(func.result, TypeMode::Owned);
2660 } else if let Some((r, _id, error_typename)) = self.special_case_trappable_error(func) {
2661 self.push_str("Result<");
2665 if let Some(ok) = r.ok {
2666 self.print_ty(&ok, TypeMode::Owned);
2667 } else {
2668 self.push_str("()");
2669 }
2670 self.push_str(",");
2671 self.push_str(&error_typename);
2672 self.push_str(">");
2673 } else {
2674 let wt = self.generator.wasmtime_path();
2677 uwrite!(self.src, "{wt}::Result<");
2678 self.print_result_ty(func.result, TypeMode::Owned);
2679 self.push_str(">");
2680 }
2681 }
2682
2683 fn extract_typed_function(&mut self, func: &Function) -> (String, String) {
2684 let snake = func_field_name(self.resolve, func);
2685 let sig = self.typedfunc_sig(func, TypeMode::AllBorrowed("'_"));
2686 let extract =
2687 format!("*_instance.get_typed_func::<{sig}>(&mut store, &self.{snake})?.func()");
2688 (snake, extract)
2689 }
2690
2691 fn define_rust_guest_export(
2692 &mut self,
2693 resolve: &Resolve,
2694 ns: Option<&WorldKey>,
2695 func: &Function,
2696 ) {
2697 let flags = self.generator.opts.exports.flags(resolve, ns, func);
2698 let (async_, async__, await_) = if flags.contains(FunctionFlags::ASYNC) {
2699 ("async", "_async", ".await")
2700 } else {
2701 ("", "", "")
2702 };
2703
2704 self.rustdoc(&func.docs);
2705 let wt = self.generator.wasmtime_path();
2706
2707 uwrite!(
2708 self.src,
2709 "pub {async_} fn call_{}",
2710 func.item_name().to_snake_case(),
2711 );
2712 if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {
2713 uwrite!(
2714 self.src,
2715 "<_T, _D>(&self, accessor: &{wt}::component::Accessor<_T, _D>, ",
2716 );
2717 } else {
2718 uwrite!(self.src, "<S: {wt}::AsContextMut>(&self, mut store: S, ",);
2719 }
2720
2721 let task_exit =
2722 flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE | FunctionFlags::TASK_EXIT);
2723
2724 let param_mode = if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {
2725 TypeMode::Owned
2726 } else {
2727 TypeMode::AllBorrowed("'_")
2728 };
2729
2730 for (i, param) in func.params.iter().enumerate() {
2731 uwrite!(self.src, "arg{}: ", i);
2732 self.print_ty(¶m.1, param_mode);
2733 self.push_str(",");
2734 }
2735
2736 uwrite!(self.src, ") -> {wt}::Result<");
2737 if task_exit {
2738 self.src.push_str("(");
2739 }
2740 self.print_result_ty(func.result, TypeMode::Owned);
2741 if task_exit {
2742 uwrite!(self.src, ", {wt}::component::TaskExit)");
2743 }
2744 uwrite!(self.src, ">");
2745
2746 if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {
2747 uwrite!(self.src, " where _T: Send, _D: {wt}::component::HasData");
2748 } else if flags.contains(FunctionFlags::ASYNC) {
2749 uwrite!(self.src, " where <S as {wt}::AsContext>::Data: Send");
2750 }
2751 uwrite!(self.src, "{{\n");
2752
2753 if flags.contains(FunctionFlags::TRACING) {
2754 if flags.contains(FunctionFlags::ASYNC) {
2755 self.src.push_str("use tracing::Instrument;\n");
2756 }
2757
2758 let ns = match ns {
2759 Some(key) => resolve.name_world_key(key),
2760 None => "default".to_string(),
2761 };
2762 self.src.push_str(&format!(
2763 "
2764 let span = tracing::span!(
2765 tracing::Level::TRACE,
2766 \"wit-bindgen export\",
2767 module = \"{ns}\",
2768 function = \"{}\",
2769 );
2770 ",
2771 func.name,
2772 ));
2773
2774 if !flags.contains(FunctionFlags::ASYNC) {
2775 self.src.push_str(
2776 "
2777 let _enter = span.enter();
2778 ",
2779 );
2780 }
2781 }
2782
2783 self.src.push_str("let callee = unsafe {\n");
2784 uwrite!(
2785 self.src,
2786 "{wt}::component::TypedFunc::<{}>",
2787 self.typedfunc_sig(func, param_mode)
2788 );
2789 let projection_to_func = if func.kind.resource().is_some() {
2790 ".funcs"
2791 } else {
2792 ""
2793 };
2794 uwriteln!(
2795 self.src,
2796 "::new_unchecked(self{projection_to_func}.{})",
2797 func_field_name(self.resolve, func),
2798 );
2799 self.src.push_str("};\n");
2800
2801 self.src.push_str("let (");
2802 if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {
2803 self.src.push_str("(");
2804 }
2805 if func.result.is_some() {
2806 uwrite!(self.src, "ret0,");
2807 }
2808
2809 if flags.contains(FunctionFlags::ASYNC | FunctionFlags::STORE) {
2810 let task_exit = if task_exit { "task_exit" } else { "_" };
2811 uwrite!(
2812 self.src,
2813 "), {task_exit}) = callee.call_concurrent(accessor, ("
2814 );
2815 } else {
2816 uwrite!(
2817 self.src,
2818 ") = callee.call{async__}(store.as_context_mut(), ("
2819 );
2820 };
2821
2822 for (i, _) in func.params.iter().enumerate() {
2823 uwrite!(self.src, "arg{}, ", i);
2824 }
2825
2826 let instrument = if flags.contains(FunctionFlags::ASYNC | FunctionFlags::TRACING) {
2827 ".instrument(span.clone())"
2828 } else {
2829 ""
2830 };
2831 uwriteln!(self.src, ")){instrument}{await_}?;");
2832
2833 let instrument = if flags.contains(FunctionFlags::ASYNC | FunctionFlags::TRACING) {
2834 ".instrument(span)"
2835 } else {
2836 ""
2837 };
2838
2839 if !flags.contains(FunctionFlags::STORE) {
2840 uwriteln!(
2841 self.src,
2842 "callee.post_return{async__}(store.as_context_mut()){instrument}{await_}?;"
2843 );
2844 }
2845
2846 self.src.push_str("Ok(");
2847 if task_exit {
2848 self.src.push_str("(");
2849 }
2850 if func.result.is_some() {
2851 self.src.push_str("ret0");
2852 } else {
2853 self.src.push_str("()");
2854 }
2855 if task_exit {
2856 self.src.push_str(", task_exit)");
2857 }
2858 self.src.push_str(")\n");
2859
2860 self.src.push_str("}\n");
2862 }
2863
2864 fn rustdoc(&mut self, docs: &Docs) {
2865 let docs = match &docs.contents {
2866 Some(docs) => docs,
2867 None => return,
2868 };
2869 for line in docs.trim().lines() {
2870 self.push_str("/// ");
2871 self.push_str(line);
2872 self.push_str("\n");
2873 }
2874 }
2875
2876 fn path_to_root(&self) -> String {
2877 let mut path_to_root = String::new();
2878 if let Some((_, key, is_export)) = self.current_interface {
2879 match key {
2880 WorldKey::Name(_) => {
2881 path_to_root.push_str("super::");
2882 }
2883 WorldKey::Interface(_) => {
2884 path_to_root.push_str("super::super::super::");
2885 }
2886 }
2887 if is_export {
2888 path_to_root.push_str("super::");
2889 }
2890 }
2891 path_to_root
2892 }
2893
2894 fn partition_concurrent_funcs<'b>(
2895 &mut self,
2896 funcs: impl IntoIterator<Item = &'b Function>,
2897 ) -> FunctionPartitioning<'b> {
2898 let key = self.current_interface.map(|p| p.1);
2899 let (with_store, without_store) = funcs
2900 .into_iter()
2901 .map(|func| {
2902 let flags = self.generator.opts.imports.flags(self.resolve, key, func);
2903 (func, flags)
2904 })
2905 .partition(|(_, flags)| flags.contains(FunctionFlags::STORE));
2906 FunctionPartitioning {
2907 with_store,
2908 without_store,
2909 }
2910 }
2911
2912 fn generate_trait(
2913 &mut self,
2914 trait_name: &str,
2915 functions: &[&Function],
2916 extra_functions: &[ExtraTraitMethod<'_>],
2917 resources: &[(TypeId, &str)],
2918 ) -> GeneratedTrait {
2919 let mut ret = GeneratedTrait::default();
2920 let wt = self.generator.wasmtime_path();
2921 let partition = self.partition_concurrent_funcs(functions.iter().copied());
2922
2923 for (_, flags) in partition.with_store.iter().chain(&partition.without_store) {
2924 ret.all_func_flags |= *flags;
2925 }
2926
2927 let mut with_store_supertraits = vec![format!("{wt}::component::HasData")];
2928 let mut without_store_supertraits = vec![];
2929 for (id, name) in resources {
2930 let camel = name.to_upper_camel_case();
2931 without_store_supertraits.push(format!("Host{camel}"));
2932 let funcs = self.partition_concurrent_funcs(get_resource_functions(self.resolve, *id));
2933 for (_, flags) in funcs.with_store.iter().chain(&funcs.without_store) {
2934 ret.all_func_flags |= *flags;
2935 }
2936 ret.all_func_flags |= self.import_resource_drop_flags(name);
2937 with_store_supertraits.push(format!("Host{camel}WithStore"));
2938 }
2939 if ret.all_func_flags.contains(FunctionFlags::ASYNC) {
2940 with_store_supertraits.push("Send".to_string());
2941 without_store_supertraits.push("Send".to_string());
2942 }
2943
2944 uwriteln!(
2945 self.src,
2946 "pub trait {trait_name}WithStore: {} {{",
2947 with_store_supertraits.join(" + "),
2948 );
2949 ret.with_store_name = Some(format!("{trait_name}WithStore"));
2950
2951 let mut extra_with_store_function = false;
2952 for extra in extra_functions {
2953 match extra {
2954 ExtraTraitMethod::ResourceDrop { name } => {
2955 let flags = self.import_resource_drop_flags(name);
2956 if !flags.contains(FunctionFlags::STORE) {
2957 continue;
2958 }
2959 let camel = name.to_upper_camel_case();
2960
2961 if flags.contains(FunctionFlags::ASYNC) {
2962 uwrite!(
2963 self.src,
2964 "
2965fn drop<T>(accessor: &{wt}::component::Accessor<T, Self>, rep: {wt}::component::Resource<{camel}>)
2966 -> impl ::core::future::Future<Output = {wt}::Result<()>> + Send where Self: Sized;
2967"
2968 );
2969 } else {
2970 uwrite!(
2971 self.src,
2972 "
2973fn drop<T>(accessor: {wt}::component::Access<T, Self>, rep: {wt}::component::Resource<{camel}>)
2974 -> {wt}::Result<()>;
2975"
2976 );
2977 }
2978
2979 extra_with_store_function = true;
2980 }
2981 ExtraTraitMethod::ErrorConvert { .. } => {}
2982 }
2983 }
2984
2985 for (func, flags) in partition.with_store.iter() {
2986 self.generate_function_trait_sig(func, *flags);
2987 self.push_str(";\n");
2988 }
2989 uwriteln!(self.src, "}}");
2990
2991 if partition.with_store.is_empty() && !extra_with_store_function {
2994 uwriteln!(self.src, "impl<_T: ?Sized> {trait_name}WithStore for _T");
2995 uwriteln!(
2996 self.src,
2997 " where _T: {}",
2998 with_store_supertraits.join(" + ")
2999 );
3000
3001 uwriteln!(self.src, "{{}}");
3002 }
3003
3004 uwriteln!(
3005 self.src,
3006 "pub trait {trait_name}: {} {{",
3007 without_store_supertraits.join(" + ")
3008 );
3009 ret.name = trait_name.to_string();
3010 for (func, flags) in partition.without_store.iter() {
3011 self.generate_function_trait_sig(func, *flags);
3012 self.push_str(";\n");
3013 }
3014
3015 for extra in extra_functions {
3016 match extra {
3017 ExtraTraitMethod::ResourceDrop { name } => {
3018 let flags = self.import_resource_drop_flags(name);
3019 ret.all_func_flags |= flags;
3020 if flags.contains(FunctionFlags::STORE) {
3021 continue;
3022 }
3023 let camel = name.to_upper_camel_case();
3024 uwrite!(
3025 self.src,
3026 "fn drop(&mut self, rep: {wt}::component::Resource<{camel}>) -> "
3027 );
3028 if flags.contains(FunctionFlags::ASYNC) {
3029 uwrite!(self.src, "impl ::core::future::Future<Output =");
3030 }
3031 uwrite!(self.src, "{wt}::Result<()>");
3032 if flags.contains(FunctionFlags::ASYNC) {
3033 uwrite!(self.src, "> + Send");
3034 }
3035 uwrite!(self.src, ";");
3036 }
3037 ExtraTraitMethod::ErrorConvert { name, id } => {
3038 let root = self.path_to_root();
3039 let custom_name = &self.generator.trappable_errors[id];
3040 let snake = name.to_snake_case();
3041 let camel = name.to_upper_camel_case();
3042 uwriteln!(
3043 self.src,
3044 "
3045fn convert_{snake}(&mut self, err: {root}{custom_name}) -> {wt}::Result<{camel}>;
3046 "
3047 );
3048 }
3049 }
3050 }
3051
3052 uwriteln!(self.src, "}}");
3053
3054 if self.generator.opts.skip_mut_forwarding_impls {
3055 return ret;
3056 }
3057
3058 let maybe_send = if ret.all_func_flags.contains(FunctionFlags::ASYNC) {
3060 "+ Send"
3061 } else {
3062 ""
3063 };
3064 uwriteln!(
3065 self.src,
3066 "impl <_T: {trait_name} + ?Sized {maybe_send}> {trait_name} for &mut _T {{"
3067 );
3068 for (func, flags) in partition.without_store.iter() {
3069 self.generate_function_trait_sig(func, *flags);
3070 uwriteln!(self.src, "{{");
3071 if flags.contains(FunctionFlags::ASYNC) {
3072 uwriteln!(self.src, "async move {{");
3073 }
3074 uwrite!(
3075 self.src,
3076 "{trait_name}::{}(*self,",
3077 rust_function_name(func)
3078 );
3079 for (name, _) in func.params.iter() {
3080 uwrite!(self.src, "{},", to_rust_ident(name));
3081 }
3082 uwrite!(self.src, ")");
3083 if flags.contains(FunctionFlags::ASYNC) {
3084 uwrite!(self.src, ".await\n}}");
3085 }
3086 uwriteln!(self.src, "}}");
3087 }
3088 for extra in extra_functions {
3089 match extra {
3090 ExtraTraitMethod::ResourceDrop { name } => {
3091 let flags = self.import_resource_drop_flags(name);
3092 if flags.contains(FunctionFlags::STORE) {
3093 continue;
3094 }
3095 let camel = name.to_upper_camel_case();
3096 let mut await_ = "";
3097 if flags.contains(FunctionFlags::ASYNC) {
3098 self.src.push_str("async ");
3099 await_ = ".await";
3100 }
3101 uwriteln!(
3102 self.src,
3103 "
3104fn drop(&mut self, rep: {wt}::component::Resource<{camel}>) -> {wt}::Result<()> {{
3105 {trait_name}::drop(*self, rep){await_}
3106}}
3107 ",
3108 );
3109 }
3110 ExtraTraitMethod::ErrorConvert { name, id } => {
3111 let root = self.path_to_root();
3112 let custom_name = &self.generator.trappable_errors[id];
3113 let snake = name.to_snake_case();
3114 let camel = name.to_upper_camel_case();
3115 uwriteln!(
3116 self.src,
3117 "
3118fn convert_{snake}(&mut self, err: {root}{custom_name}) -> {wt}::Result<{camel}> {{
3119 {trait_name}::convert_{snake}(*self, err)
3120}}
3121 ",
3122 );
3123 }
3124 }
3125 }
3126 uwriteln!(self.src, "}}");
3127
3128 ret
3129 }
3130}
3131
3132enum ExtraTraitMethod<'a> {
3133 ResourceDrop { name: &'a str },
3134 ErrorConvert { name: &'a str, id: TypeId },
3135}
3136
3137struct FunctionPartitioning<'a> {
3138 without_store: Vec<(&'a Function, FunctionFlags)>,
3139 with_store: Vec<(&'a Function, FunctionFlags)>,
3140}
3141
3142#[derive(Default)]
3143struct GeneratedTrait {
3144 name: String,
3145 with_store_name: Option<String>,
3146 all_func_flags: FunctionFlags,
3147}
3148
3149impl<'a> RustGenerator<'a> for InterfaceGenerator<'a> {
3150 fn resolve(&self) -> &'a Resolve {
3151 self.resolve
3152 }
3153
3154 fn ownership(&self) -> Ownership {
3155 self.generator.opts.ownership
3156 }
3157
3158 fn path_to_interface(&self, interface: InterfaceId) -> Option<String> {
3159 if let Some((cur, _, _)) = self.current_interface {
3160 if cur == interface {
3161 return None;
3162 }
3163 }
3164 let mut path_to_root = self.path_to_root();
3165 match &self.generator.interface_names[&interface] {
3166 InterfaceName::Remapped { name_at_root, .. } => path_to_root.push_str(name_at_root),
3167 InterfaceName::Path(path) => {
3168 for (i, name) in path.iter().enumerate() {
3169 if i > 0 {
3170 path_to_root.push_str("::");
3171 }
3172 path_to_root.push_str(name);
3173 }
3174 }
3175 }
3176 Some(path_to_root)
3177 }
3178
3179 fn push_str(&mut self, s: &str) {
3180 self.src.push_str(s);
3181 }
3182
3183 fn info(&self, ty: TypeId) -> TypeInfo {
3184 self.generator.types.get(ty)
3185 }
3186
3187 fn is_imported_interface(&self, interface: InterfaceId) -> bool {
3188 self.generator.interface_last_seen_as_import[&interface]
3189 }
3190
3191 fn wasmtime_path(&self) -> String {
3192 self.generator.wasmtime_path()
3193 }
3194}
3195
3196#[derive(Default)]
3197struct LinkOptionsBuilder {
3198 unstable_features: BTreeSet<String>,
3199}
3200impl LinkOptionsBuilder {
3201 fn has_any(&self) -> bool {
3202 !self.unstable_features.is_empty()
3203 }
3204 fn add_world(&mut self, resolve: &Resolve, id: &WorldId) {
3205 let world = &resolve.worlds[*id];
3206
3207 self.add_stability(&world.stability);
3208
3209 for (_, import) in world.imports.iter() {
3210 match import {
3211 WorldItem::Interface { id, stability } => {
3212 self.add_stability(stability);
3213 self.add_interface(resolve, id);
3214 }
3215 WorldItem::Function(f) => {
3216 self.add_stability(&f.stability);
3217 }
3218 WorldItem::Type(t) => {
3219 self.add_type(resolve, t);
3220 }
3221 }
3222 }
3223 }
3224 fn add_interface(&mut self, resolve: &Resolve, id: &InterfaceId) {
3225 let interface = &resolve.interfaces[*id];
3226
3227 self.add_stability(&interface.stability);
3228
3229 for (_, t) in interface.types.iter() {
3230 self.add_type(resolve, t);
3231 }
3232 for (_, f) in interface.functions.iter() {
3233 self.add_stability(&f.stability);
3234 }
3235 }
3236 fn add_type(&mut self, resolve: &Resolve, id: &TypeId) {
3237 let t = &resolve.types[*id];
3238 self.add_stability(&t.stability);
3239 }
3240 fn add_stability(&mut self, stability: &Stability) {
3241 match stability {
3242 Stability::Unstable { feature, .. } => {
3243 self.unstable_features.insert(feature.clone());
3244 }
3245 Stability::Stable { .. } | Stability::Unknown => {}
3246 }
3247 }
3248 fn write_struct(&self, src: &mut Source) {
3249 if !self.has_any() {
3250 return;
3251 }
3252
3253 let mut unstable_features = self.unstable_features.iter().cloned().collect::<Vec<_>>();
3254 unstable_features.sort();
3255
3256 uwriteln!(
3257 src,
3258 "
3259 /// Link-time configurations.
3260 #[derive(Clone, Debug, Default)]
3261 pub struct LinkOptions {{
3262 "
3263 );
3264
3265 for feature in unstable_features.iter() {
3266 let feature_rust_name = feature.to_snake_case();
3267 uwriteln!(src, "{feature_rust_name}: bool,");
3268 }
3269
3270 uwriteln!(src, "}}");
3271 uwriteln!(src, "impl LinkOptions {{");
3272
3273 for feature in unstable_features.iter() {
3274 let feature_rust_name = feature.to_snake_case();
3275 uwriteln!(
3276 src,
3277 "
3278 /// Enable members marked as `@unstable(feature = {feature})`
3279 pub fn {feature_rust_name}(&mut self, enabled: bool) -> &mut Self {{
3280 self.{feature_rust_name} = enabled;
3281 self
3282 }}
3283 "
3284 );
3285 }
3286
3287 uwriteln!(src, "}}");
3288 }
3289 fn write_impl_from_world(&self, src: &mut Source, path: &str) {
3290 if !self.has_any() {
3291 return;
3292 }
3293
3294 let mut unstable_features = self.unstable_features.iter().cloned().collect::<Vec<_>>();
3295 unstable_features.sort();
3296
3297 uwriteln!(
3298 src,
3299 "
3300 impl core::convert::From<LinkOptions> for {path}::LinkOptions {{
3301 fn from(src: LinkOptions) -> Self {{
3302 (&src).into()
3303 }}
3304 }}
3305
3306 impl core::convert::From<&LinkOptions> for {path}::LinkOptions {{
3307 fn from(src: &LinkOptions) -> Self {{
3308 let mut dest = Self::default();
3309 "
3310 );
3311
3312 for feature in unstable_features.iter() {
3313 let feature_rust_name = feature.to_snake_case();
3314 uwriteln!(src, "dest.{feature_rust_name}(src.{feature_rust_name});");
3315 }
3316
3317 uwriteln!(
3318 src,
3319 "
3320 dest
3321 }}
3322 }}
3323 "
3324 );
3325 }
3326}
3327
3328struct FeatureGate {
3329 close: bool,
3330}
3331impl FeatureGate {
3332 fn open(src: &mut Source, stability: &Stability) -> FeatureGate {
3333 let close = if let Stability::Unstable { feature, .. } = stability {
3334 let feature_rust_name = feature.to_snake_case();
3335 uwrite!(src, "if options.{feature_rust_name} {{");
3336 true
3337 } else {
3338 false
3339 };
3340 Self { close }
3341 }
3342
3343 fn close(self, src: &mut Source) {
3344 if self.close {
3345 uwriteln!(src, "}}");
3346 }
3347 }
3348}
3349
3350fn formatting_for_arg(
3352 name: &str,
3353 index: usize,
3354 ty: Type,
3355 resolve: &Resolve,
3356 flags: FunctionFlags,
3357) -> String {
3358 if !flags.contains(FunctionFlags::VERBOSE_TRACING) && type_contains_lists(ty, resolve) {
3359 return format!("{name} = tracing::field::debug(\"...\")");
3360 }
3361
3362 format!("{name} = tracing::field::debug(&arg{index})")
3364}
3365
3366fn formatting_for_results(result: Option<Type>, resolve: &Resolve, flags: FunctionFlags) -> String {
3368 let contains_lists = match result {
3369 Some(ty) => type_contains_lists(ty, resolve),
3370 None => false,
3371 };
3372
3373 if !flags.contains(FunctionFlags::VERBOSE_TRACING) && contains_lists {
3374 return format!("result = tracing::field::debug(\"...\")");
3375 }
3376
3377 format!("result = tracing::field::debug(&r)")
3379}
3380
3381fn type_contains_lists(ty: Type, resolve: &Resolve) -> bool {
3385 match ty {
3386 Type::Id(id) => match &resolve.types[id].kind {
3387 TypeDefKind::Resource
3388 | TypeDefKind::Unknown
3389 | TypeDefKind::Flags(_)
3390 | TypeDefKind::Handle(_)
3391 | TypeDefKind::Enum(_)
3392 | TypeDefKind::Stream(_)
3393 | TypeDefKind::Future(_) => false,
3394 TypeDefKind::Option(ty) => type_contains_lists(*ty, resolve),
3395 TypeDefKind::Result(Result_ { ok, err }) => {
3396 option_type_contains_lists(*ok, resolve)
3397 || option_type_contains_lists(*err, resolve)
3398 }
3399 TypeDefKind::Record(record) => record
3400 .fields
3401 .iter()
3402 .any(|field| type_contains_lists(field.ty, resolve)),
3403 TypeDefKind::Tuple(tuple) => tuple
3404 .types
3405 .iter()
3406 .any(|ty| type_contains_lists(*ty, resolve)),
3407 TypeDefKind::Variant(variant) => variant
3408 .cases
3409 .iter()
3410 .any(|case| option_type_contains_lists(case.ty, resolve)),
3411 TypeDefKind::Type(ty) => type_contains_lists(*ty, resolve),
3412 TypeDefKind::List(_) => true,
3413 TypeDefKind::FixedSizeList(..) => todo!(),
3414 },
3415
3416 _ => false,
3419 }
3420}
3421
3422fn option_type_contains_lists(ty: Option<Type>, resolve: &Resolve) -> bool {
3423 match ty {
3424 Some(ty) => type_contains_lists(ty, resolve),
3425 None => false,
3426 }
3427}
3428
3429fn resolve_type_definition_id(resolve: &Resolve, mut id: TypeId) -> TypeId {
3433 loop {
3434 match resolve.types[id].kind {
3435 TypeDefKind::Type(Type::Id(def_id)) => id = def_id,
3436 _ => return id,
3437 }
3438 }
3439}
3440
3441fn rust_function_name(func: &Function) -> String {
3442 match func.kind {
3443 FunctionKind::Constructor(_) => "new".to_string(),
3444 FunctionKind::Method(_)
3445 | FunctionKind::Static(_)
3446 | FunctionKind::AsyncMethod(_)
3447 | FunctionKind::AsyncStatic(_)
3448 | FunctionKind::Freestanding
3449 | FunctionKind::AsyncFreestanding => to_rust_ident(func.item_name()),
3450 }
3451}
3452
3453fn func_field_name(resolve: &Resolve, func: &Function) -> String {
3454 let mut name = String::new();
3455 match func.kind {
3456 FunctionKind::Method(id) | FunctionKind::AsyncMethod(id) => {
3457 name.push_str("method-");
3458 name.push_str(resolve.types[id].name.as_ref().unwrap());
3459 name.push_str("-");
3460 }
3461 FunctionKind::Static(id) | FunctionKind::AsyncStatic(id) => {
3462 name.push_str("static-");
3463 name.push_str(resolve.types[id].name.as_ref().unwrap());
3464 name.push_str("-");
3465 }
3466 FunctionKind::Constructor(id) => {
3467 name.push_str("constructor-");
3468 name.push_str(resolve.types[id].name.as_ref().unwrap());
3469 name.push_str("-");
3470 }
3471 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {}
3472 }
3473 name.push_str(func.item_name());
3474 name.to_snake_case()
3475}
3476
3477fn get_resources<'a>(
3478 resolve: &'a Resolve,
3479 id: InterfaceId,
3480) -> impl Iterator<Item = (TypeId, &'a str)> + 'a {
3481 resolve.interfaces[id]
3482 .types
3483 .iter()
3484 .filter_map(move |(name, ty)| match &resolve.types[*ty].kind {
3485 TypeDefKind::Resource => Some((*ty, name.as_str())),
3486 _ => None,
3487 })
3488}
3489
3490fn get_resource_functions<'a>(resolve: &'a Resolve, resource_id: TypeId) -> Vec<&'a Function> {
3491 let resource = &resolve.types[resource_id];
3492 match resource.owner {
3493 TypeOwner::World(id) => resolve.worlds[id]
3494 .imports
3495 .values()
3496 .filter_map(|item| match item {
3497 WorldItem::Function(f) => Some(f),
3498 _ => None,
3499 })
3500 .filter(|f| f.kind.resource() == Some(resource_id))
3501 .collect(),
3502 TypeOwner::Interface(id) => resolve.interfaces[id]
3503 .functions
3504 .values()
3505 .filter(|f| f.kind.resource() == Some(resource_id))
3506 .collect::<Vec<_>>(),
3507 TypeOwner::None => {
3508 panic!("A resource must be owned by a world or interface");
3509 }
3510 }
3511}
3512
3513fn get_world_resources<'a>(
3514 resolve: &'a Resolve,
3515 id: WorldId,
3516) -> impl Iterator<Item = (TypeId, &'a str)> + 'a {
3517 resolve.worlds[id]
3518 .imports
3519 .iter()
3520 .filter_map(move |(name, item)| match item {
3521 WorldItem::Type(id) => match resolve.types[*id].kind {
3522 TypeDefKind::Resource => Some(match name {
3523 WorldKey::Name(s) => (*id, s.as_str()),
3524 WorldKey::Interface(_) => unreachable!(),
3525 }),
3526 _ => None,
3527 },
3528 _ => None,
3529 })
3530}