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