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