1use crate::interface::InterfaceGenerator;
2use anyhow::{Result, bail};
3use core::panic;
4use heck::*;
5use indexmap::{IndexMap, IndexSet};
6use std::collections::{BTreeMap, HashMap, HashSet};
7use std::fmt::{self, Write as _};
8use std::mem;
9use std::path::{Path, PathBuf};
10use std::str::FromStr;
11use wit_bindgen_core::abi::{Bitcast, WasmType};
12use wit_bindgen_core::{
13 AsyncFilterSet, Files, InterfaceGenerator as _, Source, Types, WorldGenerator, dealias,
14 name_package_module, uwrite, uwriteln, wit_parser::*,
15};
16
17mod bindgen;
18mod interface;
19
20struct InterfaceName {
21 remapped: bool,
24
25 path: String,
27}
28
29#[derive(Default)]
30pub struct RustWasm {
31 types: Types,
32 src_preamble: Source,
33 src: Source,
34 opts: Opts,
35 import_modules: Vec<(String, Vec<String>)>,
36 export_modules: Vec<(String, Vec<String>)>,
37 skip: HashSet<String>,
38 interface_names: HashMap<InterfaceId, InterfaceName>,
39 exported_resources: HashSet<TypeId>,
40 import_funcs_called: bool,
41 with_name_counter: usize,
42 generated_types: HashSet<String>,
45 world: Option<WorldId>,
46
47 rt_module: IndexSet<RuntimeItem>,
48 export_macros: Vec<(String, String)>,
49
50 with: GenerationConfiguration,
52
53 future_payloads: IndexMap<Option<Type>, String>,
54 stream_payloads: IndexMap<Option<Type>, String>,
55}
56
57#[derive(Default)]
58struct GenerationConfiguration {
59 map: HashMap<String, TypeGeneration>,
60 generate_by_default: bool,
61}
62
63impl GenerationConfiguration {
64 fn get(&self, key: &str) -> Option<&TypeGeneration> {
65 self.map.get(key).or_else(|| {
66 self.generate_by_default
67 .then_some(&TypeGeneration::Generate)
68 })
69 }
70
71 fn insert(&mut self, name: String, generate: TypeGeneration) {
72 self.map.insert(name, generate);
73 }
74
75 fn iter(&self) -> impl Iterator<Item = (&String, &TypeGeneration)> {
76 self.map.iter()
77 }
78}
79
80enum TypeGeneration {
82 Remap(String),
84 Generate,
86}
87
88impl TypeGeneration {
89 fn generated(&self) -> bool {
91 match self {
92 TypeGeneration::Generate => true,
93 TypeGeneration::Remap(_) => false,
94 }
95 }
96}
97
98#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
99enum RuntimeItem {
100 AllocCrate,
101 StringType,
102 StdAllocModule,
103 VecType,
104 StringLift,
105 InvalidEnumDiscriminant,
106 CharLift,
107 BoolLift,
108 CabiDealloc,
109 RunCtorsOnce,
110 AsI32,
111 AsI64,
112 AsF32,
113 AsF64,
114 ResourceType,
115 BoxType,
116 WitMapTrait,
117}
118
119#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
120#[cfg_attr(
121 feature = "serde",
122 derive(serde::Deserialize),
123 serde(rename_all = "kebab-case")
124)]
125pub enum ExportKey {
126 World,
127 Name(String),
128}
129
130#[cfg(feature = "clap")]
131fn parse_with(s: &str) -> Result<(String, WithOption), String> {
132 let (k, v) = s.split_once('=').ok_or_else(|| {
133 format!("expected string of form `<key>=<value>[,<key>=<value>...]`; got `{s}`")
134 })?;
135 let v = match v {
136 "generate" => WithOption::Generate,
137 other => WithOption::Path(other.to_string()),
138 };
139 Ok((k.to_string(), v))
140}
141
142#[derive(Default, Debug, Clone)]
143#[cfg_attr(feature = "clap", derive(clap::Parser))]
144#[cfg_attr(
145 feature = "serde",
146 derive(serde::Deserialize),
147 serde(default, rename_all = "kebab-case")
148)]
149pub struct Opts {
150 #[cfg_attr(feature = "clap", arg(long))]
152 pub format: bool,
153
154 #[cfg_attr(feature = "clap", arg(long))]
157 pub std_feature: bool,
158
159 #[cfg_attr(feature = "clap", arg(long))]
164 pub raw_strings: bool,
165
166 #[cfg_attr(feature = "clap", arg(long, value_name = "NAME"))]
168 pub skip: Vec<String>,
169
170 #[cfg_attr(feature = "clap", arg(long))]
173 pub stubs: bool,
174
175 #[cfg_attr(feature = "clap", arg(long, value_name = "STRING"))]
179 pub export_prefix: Option<String>,
180
181 #[cfg_attr(feature = "clap", arg(long, default_value_t = Ownership::Owning))]
195 pub ownership: Ownership,
196
197 #[cfg_attr(feature = "clap", arg(long, value_name = "PATH"))]
201 pub runtime_path: Option<String>,
202
203 #[cfg_attr(feature = "clap", arg(long, value_name = "PATH"))]
213 pub map_type: Option<String>,
214
215 #[cfg_attr(feature = "clap", arg(long))]
219 pub bitflags_path: Option<String>,
220
221 #[cfg_attr(feature = "clap", arg(long, short = 'd', value_name = "DERIVE"))]
226 pub additional_derive_attributes: Vec<String>,
227
228 #[cfg_attr(feature = "clap", arg(long, value_name = "NAME"))]
235 pub additional_derive_ignore: Vec<String>,
236
237 #[cfg_attr(feature = "clap", arg(long, value_parser = parse_with, value_delimiter = ','))]
244 pub with: Vec<(String, WithOption)>,
245
246 #[cfg_attr(feature = "clap", arg(long))]
249 pub generate_all: bool,
250
251 #[cfg_attr(feature = "clap", arg(long, value_name = "STRING"))]
254 pub type_section_suffix: Option<String>,
255
256 #[cfg_attr(feature = "clap", arg(long))]
259 pub disable_run_ctors_once_workaround: bool,
260
261 #[cfg_attr(feature = "clap", arg(long, value_name = "NAME"))]
264 pub default_bindings_module: Option<String>,
265
266 #[cfg_attr(feature = "clap", arg(long, value_name = "NAME"))]
268 pub export_macro_name: Option<String>,
269
270 #[cfg_attr(feature = "clap", arg(long))]
273 pub pub_export_macro: bool,
274
275 #[cfg_attr(feature = "clap", arg(long))]
277 pub generate_unused_types: bool,
278
279 #[cfg_attr(feature = "clap", arg(long))]
285 pub disable_custom_section_link_helpers: bool,
286
287 #[cfg_attr(feature = "clap", clap(flatten))]
288 #[cfg_attr(feature = "serde", serde(flatten))]
289 pub async_: AsyncFilterSet,
290
291 #[cfg_attr(
299 feature = "clap",
300 arg(long, require_equals = true, value_name = "true|false")
301 )]
302 pub merge_structurally_equal_types: Option<Option<bool>>,
303
304 #[cfg_attr(feature = "clap", arg(long))]
306 pub enable_method_chaining: bool,
307}
308
309impl Opts {
310 pub fn build(self) -> RustWasm {
311 let mut r = RustWasm::new();
312 r.skip = self.skip.iter().cloned().collect();
313 r.opts = self;
314 r
315 }
316
317 fn merge_structurally_equal_types(&self) -> bool {
318 const DEFAULT: bool = false;
319 match self.merge_structurally_equal_types {
320 None => DEFAULT,
322 Some(None) => true,
324 Some(Some(val)) => val,
326 }
327 }
328}
329
330impl RustWasm {
331 pub fn generate_to_out_dir(mut self, world: Option<&str>) -> Result<PathBuf> {
339 let mut resolve = Resolve::default();
340 println!("cargo:rerun-if-changed=wit/");
341 let (pkg, _files) = resolve.push_path("wit")?;
342 let main_packages = vec![pkg];
343 let world = resolve.select_world(&main_packages, world)?;
344
345 let mut files = Files::default();
346 self.generate(&mut resolve, world, &mut files)?;
347 let out_dir = std::env::var("OUT_DIR").expect("cargo sets OUT_DIR");
348 let (name, contents) = files
349 .iter()
350 .next()
351 .expect("exactly one file should be generated");
352 let dst = Path::new(&out_dir).join(name);
353 std::fs::write(&dst, contents)?;
354 Ok(dst)
355 }
356
357 fn new() -> RustWasm {
358 RustWasm::default()
359 }
360
361 fn interface<'a>(
362 &'a mut self,
363 identifier: Identifier<'a>,
364 wasm_import_module: &'a str,
365 resolve: &'a Resolve,
366 in_import: bool,
367 ) -> InterfaceGenerator<'a> {
368 let mut sizes = SizeAlign::default();
369 sizes.fill(resolve);
370
371 InterfaceGenerator {
372 identifier,
373 wasm_import_module,
374 src: Source::default(),
375 in_import,
376 r#gen: self,
377 sizes,
378 resolve,
379 return_pointer_area_size: Default::default(),
380 return_pointer_area_align: Default::default(),
381 needs_runtime_module: false,
382 needs_wit_map: false,
383 }
384 }
385
386 fn emit_modules(&mut self, modules: Vec<(String, Vec<String>)>) {
387 #[derive(Default)]
388 struct Module {
389 submodules: BTreeMap<String, Module>,
390 contents: Vec<String>,
391 }
392 let mut map = Module::default();
393 for (module, path) in modules {
394 let mut cur = &mut map;
395 for name in path[..path.len() - 1].iter() {
396 cur = cur
397 .submodules
398 .entry(name.clone())
399 .or_insert(Module::default());
400 }
401 cur.contents.push(module);
402 }
403
404 emit(&mut self.src, map, &self.opts, true);
405 fn emit(me: &mut Source, module: Module, opts: &Opts, toplevel: bool) {
406 for (name, submodule) in module.submodules {
407 if toplevel {
408 if opts.format {
412 uwriteln!(me, "#[rustfmt::skip]");
413 }
414
415 uwriteln!(me, "#[allow(dead_code, clippy::all)]");
419 }
420
421 uwriteln!(me, "pub mod {name} {{");
422 emit(me, submodule, opts, false);
423 uwriteln!(me, "}}");
424 }
425 for submodule in module.contents {
426 uwriteln!(me, "{submodule}");
427 }
428 }
429 }
430
431 fn runtime_path(&self) -> &str {
432 self.opts
433 .runtime_path
434 .as_deref()
435 .unwrap_or("wit_bindgen::rt")
436 }
437
438 fn map_type_path(&self) -> String {
439 self.opts
440 .map_type
441 .clone()
442 .unwrap_or_else(|| format!("{}::Map", self.runtime_path()))
443 }
444
445 fn wit_map_path(&self) -> String {
446 format!("{}::WitMap", self.runtime_path())
447 }
448
449 fn bitflags_path(&self) -> String {
450 self.opts
451 .bitflags_path
452 .to_owned()
453 .unwrap_or(format!("{}::bitflags", self.runtime_path()))
454 }
455
456 fn async_support_path(&self) -> String {
457 format!("{}::async_support", self.runtime_path())
458 }
459
460 fn name_interface(
461 &mut self,
462 resolve: &Resolve,
463 id: InterfaceId,
464 name: &WorldKey,
465 is_export: bool,
466 ) -> Result<bool> {
467 let with_name = resolve.name_world_key(name);
468 let remapping = if is_export {
469 &TypeGeneration::Generate
470 } else {
471 match self.with.get(&with_name) {
472 Some(remapping) => remapping,
473 None => bail!(MissingWith(with_name)),
474 }
475 };
476 self.generated_types.insert(with_name);
477 let entry = match remapping {
478 TypeGeneration::Remap(remapped_path) => {
479 let name = format!("__with_name{}", self.with_name_counter);
480 self.with_name_counter += 1;
481 uwriteln!(
482 self.src,
483 "#[allow(unfulfilled_lint_expectations, unused_imports)]"
484 );
485 uwriteln!(self.src, "use {remapped_path} as {name};");
486 InterfaceName {
487 remapped: true,
488 path: name,
489 }
490 }
491 TypeGeneration::Generate => {
492 let path = compute_module_path(name, resolve, is_export).join("::");
493
494 InterfaceName {
495 remapped: false,
496 path,
497 }
498 }
499 };
500
501 let remapped = entry.remapped;
502 let prev = self.interface_names.insert(id, entry);
503 assert!(prev.is_none());
504
505 Ok(remapped)
506 }
507
508 fn finish_runtime_module(&mut self) {
509 if !self.rt_module.is_empty() {
510 if self.opts.format {
512 uwriteln!(self.src, "#[rustfmt::skip]");
513 }
514
515 self.src.push_str("mod _rt {\n");
516 self.src
517 .push_str("#![allow(dead_code, unused_imports, clippy::all)]\n");
518 let mut emitted = IndexSet::new();
519 while !self.rt_module.is_empty() {
520 for item in mem::take(&mut self.rt_module) {
521 if emitted.insert(item) {
522 self.emit_runtime_item(item);
523 }
524 }
525 }
526 self.src.push_str("}\n");
527 }
528
529 if !self.future_payloads.is_empty() {
530 let async_support = self.async_support_path();
531 self.src.push_str(&format!(
532 "\
533pub mod wit_future {{
534 #![allow(dead_code, unused_variables, clippy::all)]
535
536 #[doc(hidden)]
537 pub trait FuturePayload: Unpin + Sized + 'static {{
538 const VTABLE: &'static {async_support}::FutureVtable<Self>;
539 }}"
540 ));
541 for code in self.future_payloads.values() {
542 self.src.push_str(code);
543 }
544 self.src.push_str(&format!(
545 "\
546 /// Creates a new Component Model `future` with the specified payload type.
547 ///
548 /// The `default` function provided computes the default value to be sent in
549 /// this future if no other value was otherwise sent.
550 pub fn new<T: FuturePayload>(default: fn() -> T) -> ({async_support}::FutureWriter<T>, {async_support}::FutureReader<T>) {{
551 unsafe {{ {async_support}::future_new::<T>(default, T::VTABLE) }}
552 }}
553}}
554 ",
555 ));
556 }
557
558 if !self.stream_payloads.is_empty() {
559 let async_support = self.async_support_path();
560 self.src.push_str(&format!(
561 "\
562pub mod wit_stream {{
563 #![allow(dead_code, unused_variables, clippy::all)]
564
565 pub trait StreamPayload: Unpin + Sized + 'static {{
566 const VTABLE: &'static {async_support}::StreamVtable<Self>;
567 }}"
568 ));
569 for code in self.stream_payloads.values() {
570 self.src.push_str(code);
571 }
572 self.src.push_str(
573 &format!("\
574 /// Creates a new Component Model `stream` with the specified payload type.
575 pub fn new<T: StreamPayload>() -> ({async_support}::StreamWriter<T>, {async_support}::StreamReader<T>) {{
576 unsafe {{ {async_support}::stream_new::<T>(T::VTABLE) }}
577 }}
578}}
579 "),
580 );
581 }
582 }
583
584 fn emit_runtime_item(&mut self, item: RuntimeItem) {
585 match item {
586 RuntimeItem::AllocCrate => {
587 uwriteln!(self.src, "extern crate alloc as alloc_crate;");
588 }
589 RuntimeItem::StdAllocModule => {
590 self.rt_module.insert(RuntimeItem::AllocCrate);
591 uwriteln!(self.src, "pub use alloc_crate::alloc;");
592 }
593 RuntimeItem::StringType => {
594 self.rt_module.insert(RuntimeItem::AllocCrate);
595 uwriteln!(self.src, "pub use alloc_crate::string::String;");
596 }
597 RuntimeItem::BoxType => {
598 self.rt_module.insert(RuntimeItem::AllocCrate);
599 uwriteln!(self.src, "pub use alloc_crate::boxed::Box;");
600 }
601 RuntimeItem::VecType => {
602 self.rt_module.insert(RuntimeItem::AllocCrate);
603 uwriteln!(self.src, "pub use alloc_crate::vec::Vec;");
604 }
605 RuntimeItem::CabiDealloc => {
606 self.rt_module.insert(RuntimeItem::StdAllocModule);
607 self.src.push_str(
608 "\
609pub unsafe fn cabi_dealloc(ptr: *mut u8, size: usize, align: usize) {
610 if size == 0 {
611 return;
612 }
613 unsafe {
614 let layout = alloc::Layout::from_size_align_unchecked(size, align);
615 alloc::dealloc(ptr, layout);
616 }
617}
618 ",
619 );
620 }
621
622 RuntimeItem::StringLift => {
623 self.rt_module.insert(RuntimeItem::StringType);
624 self.src.push_str(
625 "\
626pub unsafe fn string_lift(bytes: Vec<u8>) -> String {
627 if cfg!(debug_assertions) {
628 String::from_utf8(bytes).unwrap()
629 } else {
630 unsafe { String::from_utf8_unchecked(bytes) }
631 }
632}
633 ",
634 );
635 }
636
637 RuntimeItem::InvalidEnumDiscriminant => {
638 self.src.push_str(
639 "\
640pub unsafe fn invalid_enum_discriminant<T>() -> T {
641 if cfg!(debug_assertions) {
642 panic!(\"invalid enum discriminant\")
643 } else {
644 unsafe { core::hint::unreachable_unchecked() }
645 }
646}
647 ",
648 );
649 }
650
651 RuntimeItem::CharLift => {
652 self.src.push_str(
653 "\
654pub unsafe fn char_lift(val: u32) -> char {
655 if cfg!(debug_assertions) {
656 core::char::from_u32(val).unwrap()
657 } else {
658 unsafe { core::char::from_u32_unchecked(val) }
659 }
660}
661 ",
662 );
663 }
664
665 RuntimeItem::BoolLift => {
666 self.src.push_str(
667 "\
668pub unsafe fn bool_lift(val: u8) -> bool {
669 if cfg!(debug_assertions) {
670 match val {
671 0 => false,
672 1 => true,
673 _ => panic!(\"invalid bool discriminant\"),
674 }
675 } else {
676 val != 0
677 }
678}
679 ",
680 );
681 }
682
683 RuntimeItem::RunCtorsOnce => {
684 let rt = self.runtime_path();
685 self.src.push_str(&format!(
686 r#"
687#[cfg(target_arch = "wasm32")]
688pub fn run_ctors_once() {{
689 {rt}::run_ctors_once();
690}}
691 "#,
692 ));
693 }
694
695 RuntimeItem::AsI32 => {
696 self.emit_runtime_as_trait(
697 "i32",
698 &["i32", "u32", "i16", "u16", "i8", "u8", "char", "usize"],
699 );
700 }
701
702 RuntimeItem::AsI64 => {
703 self.emit_runtime_as_trait("i64", &["i64", "u64"]);
704 }
705
706 RuntimeItem::AsF32 => {
707 self.emit_runtime_as_trait("f32", &["f32"]);
708 }
709
710 RuntimeItem::AsF64 => {
711 self.emit_runtime_as_trait("f64", &["f64"]);
712 }
713
714 RuntimeItem::WitMapTrait => {
715 let rt = self.runtime_path().to_string();
716 uwriteln!(self.src, "pub use {rt}::WitMap;");
717 }
718
719 RuntimeItem::ResourceType => {
720 self.src.push_str(
721 r#"
722
723use core::fmt;
724use core::marker;
725use core::sync::atomic::{AtomicU32, Ordering::Relaxed};
726
727/// A type which represents a component model resource, either imported or
728/// exported into this component.
729///
730/// This is a low-level wrapper which handles the lifetime of the resource
731/// (namely this has a destructor). The `T` provided defines the component model
732/// intrinsics that this wrapper uses.
733///
734/// One of the chief purposes of this type is to provide `Deref` implementations
735/// to access the underlying data when it is owned.
736///
737/// This type is primarily used in generated code for exported and imported
738/// resources.
739#[repr(transparent)]
740pub struct Resource<T: WasmResource> {
741 // NB: This would ideally be `u32` but it is not. The fact that this has
742 // interior mutability is not exposed in the API of this type except for the
743 // `take_handle` method which is supposed to in theory be private.
744 //
745 // This represents, almost all the time, a valid handle value. When it's
746 // invalid it's stored as `u32::MAX`.
747 handle: AtomicU32,
748 _marker: marker::PhantomData<T>,
749}
750
751/// A trait which all wasm resources implement, namely providing the ability to
752/// drop a resource.
753///
754/// This generally is implemented by generated code, not user-facing code.
755#[allow(clippy::missing_safety_doc)]
756pub unsafe trait WasmResource {
757 /// Invokes the `[resource-drop]...` intrinsic.
758 unsafe fn drop(handle: u32);
759}
760
761impl<T: WasmResource> Resource<T> {
762 #[doc(hidden)]
763 pub unsafe fn from_handle(handle: u32) -> Self {
764 debug_assert!(handle != 0 && handle != u32::MAX);
765 Self {
766 handle: AtomicU32::new(handle),
767 _marker: marker::PhantomData,
768 }
769 }
770
771 /// Takes ownership of the handle owned by `resource`.
772 ///
773 /// Note that this ideally would be `into_handle` taking `Resource<T>` by
774 /// ownership. The code generator does not enable that in all situations,
775 /// unfortunately, so this is provided instead.
776 ///
777 /// Also note that `take_handle` is in theory only ever called on values
778 /// owned by a generated function. For example a generated function might
779 /// take `Resource<T>` as an argument but then call `take_handle` on a
780 /// reference to that argument. In that sense the dynamic nature of
781 /// `take_handle` should only be exposed internally to generated code, not
782 /// to user code.
783 #[doc(hidden)]
784 pub fn take_handle(resource: &Resource<T>) -> u32 {
785 resource.handle.swap(u32::MAX, Relaxed)
786 }
787
788 #[doc(hidden)]
789 pub fn handle(resource: &Resource<T>) -> u32 {
790 resource.handle.load(Relaxed)
791 }
792}
793
794impl<T: WasmResource> fmt::Debug for Resource<T> {
795 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
796 f.debug_struct("Resource")
797 .field("handle", &self.handle)
798 .finish()
799 }
800}
801
802impl<T: WasmResource> Drop for Resource<T> {
803 fn drop(&mut self) {
804 unsafe {
805 match self.handle.load(Relaxed) {
806 // If this handle was "taken" then don't do anything in the
807 // destructor.
808 u32::MAX => {}
809
810 // ... but otherwise do actually destroy it with the imported
811 // component model intrinsic as defined through `T`.
812 other => T::drop(other),
813 }
814 }
815 }
816}
817 "#,
818 );
819 }
820 }
821 }
822
823 fn emit_runtime_as_trait(&mut self, ty: &str, to_convert: &[&str]) {
828 let upcase = ty.to_uppercase();
829 self.src.push_str(&format!(
830 r#"
831pub fn as_{ty}<T: As{upcase}>(t: T) -> {ty} {{
832 t.as_{ty}()
833}}
834
835pub trait As{upcase} {{
836 fn as_{ty}(self) -> {ty};
837}}
838
839impl<'a, T: Copy + As{upcase}> As{upcase} for &'a T {{
840 fn as_{ty}(self) -> {ty} {{
841 (*self).as_{ty}()
842 }}
843}}
844 "#
845 ));
846
847 for to_convert in to_convert {
848 self.src.push_str(&format!(
849 r#"
850impl As{upcase} for {to_convert} {{
851 #[inline]
852 fn as_{ty}(self) -> {ty} {{
853 self as {ty}
854 }}
855}}
856 "#
857 ));
858 }
859 }
860
861 fn finish_export_macro(&mut self, resolve: &Resolve, world_id: WorldId) {
867 if self.export_macros.is_empty() {
868 return;
869 }
870 let world = &resolve.worlds[world_id];
871 let world_name = world.name.to_snake_case();
872
873 let default_bindings_module = self
874 .opts
875 .default_bindings_module
876 .clone()
877 .unwrap_or("self".to_string());
878 let (macro_export, use_vis) = if self.opts.pub_export_macro {
879 ("#[macro_export]", "pub")
880 } else {
881 ("", "pub(crate)")
882 };
883 let export_macro_name = self
884 .opts
885 .export_macro_name
886 .as_deref()
887 .unwrap_or("export")
888 .to_string();
889 uwriteln!(
890 self.src,
891 r#"
892/// Generates `#[unsafe(no_mangle)]` functions to export the specified type as
893/// the root implementation of all generated traits.
894///
895/// For more information see the documentation of `wit_bindgen::generate!`.
896///
897/// ```rust
898/// # macro_rules! {export_macro_name} {{ ($($t:tt)*) => (); }}
899/// # trait Guest {{}}
900/// struct MyType;
901///
902/// impl Guest for MyType {{
903/// // ...
904/// }}
905///
906/// {export_macro_name}!(MyType);
907/// ```
908#[allow(unused_macros)]
909#[doc(hidden)]
910{macro_export}
911macro_rules! __export_{world_name}_impl {{
912 ($ty:ident) => ({default_bindings_module}::{export_macro_name}!($ty with_types_in {default_bindings_module}););
913 ($ty:ident with_types_in $($path_to_types_root:tt)*) => ("#
914 );
915 for (name, path_to_types) in self.export_macros.iter() {
916 let mut path = "$($path_to_types_root)*".to_string();
917 if !path_to_types.is_empty() {
918 path.push_str("::");
919 path.push_str(path_to_types)
920 }
921 uwriteln!(self.src, "{path}::{name}!($ty with_types_in {path});");
922 }
923
924 if self.opts.pub_export_macro {
926 uwriteln!(self.src, "const _: () = {{");
927 self.emit_custom_section(resolve, world_id, "imports and exports", None);
928 uwriteln!(self.src, "}};");
929 }
930
931 uwriteln!(self.src, ")\n}}");
932
933 uwriteln!(
934 self.src,
935 "#[doc(inline)]\n\
936 {use_vis} use __export_{world_name}_impl as {export_macro_name};"
937 );
938
939 if self.opts.stubs {
940 uwriteln!(self.src, "export!(Stub);");
941 }
942 }
943
944 fn emit_custom_section(
955 &mut self,
956 resolve: &Resolve,
957 world_id: WorldId,
958 section_suffix: &str,
959 func_name: Option<&str>,
960 ) {
961 if self.opts.format {
963 uwriteln!(self.src, "#[rustfmt::skip]");
964 }
965 self.src.push_str("\n#[cfg(target_arch = \"wasm32\")]\n");
966
967 let opts_suffix = self.opts.type_section_suffix.as_deref().unwrap_or("");
972 let world = &resolve.worlds[world_id];
973 let world_name = &world.name;
974 let pkg = &resolve.packages[world.package.unwrap()].name;
975 let version = env!("CARGO_PKG_VERSION");
976 self.src.push_str(&format!(
977 "#[unsafe(link_section = \"component-type:wit-bindgen:{version}:\
978 {pkg}:{world_name}:{section_suffix}{opts_suffix}\")]\n"
979 ));
980
981 let mut producers = wasm_metadata::Producers::empty();
982 producers.add(
983 "processed-by",
984 env!("CARGO_PKG_NAME"),
985 env!("CARGO_PKG_VERSION"),
986 );
987
988 let component_type = wit_component::metadata::encode(
989 resolve,
990 world_id,
991 wit_component::StringEncoding::UTF8,
992 Some(&producers),
993 )
994 .unwrap();
995
996 self.src.push_str("#[doc(hidden)]\n");
997 self.src.push_str("#[allow(clippy::octal_escapes)]\n");
998 self.src.push_str(&format!(
999 "pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; {}] = *b\"\\\n",
1000 component_type.len()
1001 ));
1002 let old_indent = self.src.set_indent(0);
1003 let mut line_length = 0;
1004 let s = self.src.as_mut_string();
1005 for byte in component_type.iter() {
1006 if line_length >= 80 {
1007 s.push_str("\\\n");
1008 line_length = 0;
1009 }
1010 match byte {
1011 b'\\' => {
1012 s.push_str("\\\\");
1013 line_length += 2;
1014 }
1015 b'"' => {
1016 s.push_str("\\\"");
1017 line_length += 2;
1018 }
1019 b if b.is_ascii_alphanumeric() || b.is_ascii_punctuation() => {
1020 s.push(char::from(*byte));
1021 line_length += 1;
1022 }
1023 0 => {
1024 s.push_str("\\0");
1025 line_length += 2;
1026 }
1027 _ => {
1028 uwrite!(s, "\\x{:02x}", byte);
1029 line_length += 4;
1030 }
1031 }
1032 }
1033
1034 self.src.push_str("\";\n");
1035 self.src.set_indent(old_indent);
1036
1037 if let Some(func_name) = func_name {
1038 let rt = self.runtime_path().to_string();
1039 uwriteln!(
1040 self.src,
1041 "
1042 #[inline(never)]
1043 #[doc(hidden)]
1044 pub fn {func_name}() {{
1045 {rt}::maybe_link_cabi_realloc();
1046 }}
1047 ",
1048 );
1049 }
1050 }
1051
1052 fn is_async(
1053 &mut self,
1054 resolve: &Resolve,
1055 interface: Option<&WorldKey>,
1056 func: &Function,
1057 is_import: bool,
1058 ) -> bool {
1059 self.opts
1060 .async_
1061 .is_async(resolve, interface, func, is_import)
1062 }
1063
1064 fn should_return_self(&self, func: &Function) -> bool {
1065 self.opts.enable_method_chaining
1066 && func.result.is_none()
1067 && matches!(&func.kind, FunctionKind::Method(_))
1068 }
1069}
1070
1071impl WorldGenerator for RustWasm {
1072 fn preprocess(&mut self, resolve: &Resolve, world: WorldId) -> Result<()> {
1073 wit_bindgen_core::generated_preamble(&mut self.src_preamble, env!("CARGO_PKG_VERSION"));
1074
1075 uwriteln!(self.src_preamble, "// Options used:");
1078 if self.opts.std_feature {
1079 uwriteln!(self.src_preamble, "// * std_feature");
1080 }
1081 if self.opts.raw_strings {
1082 uwriteln!(self.src_preamble, "// * raw_strings");
1083 }
1084 if !self.opts.skip.is_empty() {
1085 uwriteln!(self.src_preamble, "// * skip: {:?}", self.opts.skip);
1086 }
1087 if self.opts.stubs {
1088 uwriteln!(self.src_preamble, "// * stubs");
1089 }
1090 if let Some(export_prefix) = &self.opts.export_prefix {
1091 uwriteln!(
1092 self.src_preamble,
1093 "// * export_prefix: {:?}",
1094 export_prefix
1095 );
1096 }
1097 if let Some(runtime_path) = &self.opts.runtime_path {
1098 uwriteln!(self.src_preamble, "// * runtime_path: {:?}", runtime_path);
1099 }
1100 if let Some(map_type) = &self.opts.map_type {
1101 uwriteln!(self.src_preamble, "// * map_type: {:?}", map_type);
1102 }
1103 if let Some(bitflags_path) = &self.opts.bitflags_path {
1104 uwriteln!(
1105 self.src_preamble,
1106 "// * bitflags_path: {:?}",
1107 bitflags_path
1108 );
1109 }
1110 if !matches!(self.opts.ownership, Ownership::Owning) {
1111 uwriteln!(
1112 self.src_preamble,
1113 "// * ownership: {:?}",
1114 self.opts.ownership
1115 );
1116 }
1117 if !self.opts.additional_derive_attributes.is_empty() {
1118 uwriteln!(
1119 self.src_preamble,
1120 "// * additional derives {:?}",
1121 self.opts.additional_derive_attributes
1122 );
1123 }
1124 if !self.opts.additional_derive_ignore.is_empty() {
1125 uwriteln!(
1126 self.src_preamble,
1127 "// * additional derives ignored {:?}",
1128 self.opts.additional_derive_ignore
1129 );
1130 }
1131 for (k, v) in self.opts.with.iter() {
1132 uwriteln!(self.src_preamble, "// * with {k:?} = {v}");
1133 }
1134 if let Some(type_section_suffix) = &self.opts.type_section_suffix {
1135 uwriteln!(
1136 self.src_preamble,
1137 "// * type_section_suffix: {:?}",
1138 type_section_suffix
1139 );
1140 }
1141 if let Some(default) = &self.opts.default_bindings_module {
1142 uwriteln!(
1143 self.src_preamble,
1144 "// * default-bindings-module: {default:?}"
1145 );
1146 }
1147 if self.opts.disable_run_ctors_once_workaround {
1148 uwriteln!(
1149 self.src_preamble,
1150 "// * disable-run-ctors-once-workaround"
1151 );
1152 }
1153 if self.opts.merge_structurally_equal_types() {
1154 uwriteln!(self.src_preamble, "// * merge_structurally_equal_types");
1155 }
1156 if let Some(s) = &self.opts.export_macro_name {
1157 uwriteln!(self.src_preamble, "// * export-macro-name: {s}");
1158 }
1159 if self.opts.pub_export_macro {
1160 uwriteln!(self.src_preamble, "// * pub-export-macro");
1161 }
1162 if self.opts.generate_unused_types {
1163 uwriteln!(self.src_preamble, "// * generate_unused_types");
1164 }
1165 if self.opts.disable_custom_section_link_helpers {
1166 uwriteln!(
1167 self.src_preamble,
1168 "// * disable_custom_section_link_helpers"
1169 );
1170 }
1171 for opt in self.opts.async_.debug_opts() {
1172 uwriteln!(self.src_preamble, "// * async: {opt}");
1173 }
1174 self.types.analyze(resolve);
1175 self.types.collect_equal_types(resolve, world, &|a| {
1176 if self.opts.merge_structurally_equal_types() {
1179 return true;
1180 }
1181
1182 match resolve.types[a].kind {
1183 TypeDefKind::Type(_)
1187 | TypeDefKind::Handle(_)
1188 | TypeDefKind::List(_)
1189 | TypeDefKind::Tuple(_)
1190 | TypeDefKind::Option(_)
1191 | TypeDefKind::Result(_)
1192 | TypeDefKind::Future(_)
1193 | TypeDefKind::Stream(_)
1194 | TypeDefKind::Map(..)
1195 | TypeDefKind::FixedLengthList(..) => true,
1196
1197 TypeDefKind::Record(_)
1201 | TypeDefKind::Variant(_)
1202 | TypeDefKind::Enum(_)
1203 | TypeDefKind::Flags(_)
1204 | TypeDefKind::Resource
1205 | TypeDefKind::Unknown => false,
1206 }
1207 });
1208 self.world = Some(world);
1209
1210 let world = &resolve.worlds[world];
1211 for (key, item) in world.imports.iter() {
1214 if let WorldItem::Interface { id, .. } = item {
1215 if resolve.interfaces[*id].package == world.package {
1216 let name = resolve.name_world_key(key);
1217 if self.with.get(&name).is_none() {
1218 self.with.insert(name, TypeGeneration::Generate);
1219 }
1220 }
1221 }
1222 }
1223
1224 for item in world.exports.values() {
1225 let WorldItem::Interface { id, .. } = item else {
1226 continue;
1227 };
1228 for id in resolve.interfaces[*id].types.values().copied() {
1229 let TypeDefKind::Resource = &resolve.types[id].kind else {
1230 continue;
1231 };
1232 assert!(self.exported_resources.insert(id));
1233 }
1234 }
1235
1236 for (k, v) in self.opts.with.iter() {
1237 self.with.insert(k.clone(), v.clone().into());
1238 }
1239 self.with.generate_by_default = self.opts.generate_all;
1240 for (key, item) in world.imports.iter() {
1241 if let WorldItem::Interface { id, .. } = item {
1242 self.name_interface(resolve, *id, &key, false)?;
1243 }
1244 }
1245 for (key, item) in world.exports.iter() {
1246 if let WorldItem::Interface { id, .. } = item {
1247 self.name_interface(resolve, *id, &key, true)?;
1248 }
1249 }
1250 Ok(())
1251 }
1252
1253 fn import_interface(
1254 &mut self,
1255 resolve: &Resolve,
1256 name: &WorldKey,
1257 id: InterfaceId,
1258 _files: &mut Files,
1259 ) -> Result<()> {
1260 let mut to_define = Vec::new();
1261 for (name, ty_id) in resolve.interfaces[id].types.iter() {
1262 let full_name = full_wit_type_name(resolve, *ty_id);
1263 if let Some(type_gen) = self.with.get(&full_name) {
1264 if type_gen.generated() {
1266 to_define.push((name, ty_id));
1267 }
1268 } else {
1269 to_define.push((name, ty_id));
1270 }
1271 self.generated_types.insert(full_name);
1272 }
1273
1274 let wasm_import_module = resolve.name_world_key(name);
1275 let mut r#gen = self.interface(
1276 Identifier::Interface(id, name),
1277 &wasm_import_module,
1278 resolve,
1279 true,
1280 );
1281 let (snake, module_path) = r#gen.start_append_submodule(name);
1282 if r#gen.r#gen.interface_names[&id].remapped {
1283 return Ok(());
1284 }
1285
1286 for (name, ty_id) in to_define {
1287 r#gen.define_type(&name, *ty_id);
1288 }
1289
1290 r#gen.generate_imports(resolve.interfaces[id].functions.values(), Some(name));
1291
1292 let docs = &resolve.interfaces[id].docs;
1293
1294 r#gen.finish_append_submodule(&snake, module_path, docs);
1295
1296 Ok(())
1297 }
1298
1299 fn import_funcs(
1300 &mut self,
1301 resolve: &Resolve,
1302 world: WorldId,
1303 funcs: &[(&str, &Function)],
1304 _files: &mut Files,
1305 ) {
1306 self.import_funcs_called = true;
1307
1308 let mut r#gen = self.interface(Identifier::World(world), "$root", resolve, true);
1309
1310 r#gen.generate_imports(funcs.iter().map(|(_, func)| *func), None);
1311
1312 let src = r#gen.finish();
1313 self.src.push_str(&src);
1314 }
1315
1316 fn export_interface(
1317 &mut self,
1318 resolve: &Resolve,
1319 name: &WorldKey,
1320 id: InterfaceId,
1321 _files: &mut Files,
1322 ) -> Result<()> {
1323 let mut to_define = Vec::new();
1324 for (ty_name, ty_id) in resolve.interfaces[id].types.iter() {
1325 let full_name = full_wit_type_name(resolve, *ty_id);
1326 to_define.push((ty_name, ty_id));
1327 self.generated_types.insert(full_name);
1328 }
1329
1330 let wasm_import_module = format!("[export]{}", resolve.name_world_key(name));
1331 let mut r#gen = self.interface(
1332 Identifier::Interface(id, name),
1333 &wasm_import_module,
1334 resolve,
1335 false,
1336 );
1337 let (snake, module_path) = r#gen.start_append_submodule(name);
1338 if r#gen.r#gen.interface_names[&id].remapped {
1339 return Ok(());
1340 }
1341
1342 for (ty_name, ty_id) in to_define {
1343 r#gen.define_type(&ty_name, *ty_id);
1344 }
1345
1346 let macro_name =
1347 r#gen.generate_exports(Some((id, name)), resolve.interfaces[id].functions.values())?;
1348
1349 let docs = &resolve.interfaces[id].docs;
1350
1351 r#gen.finish_append_submodule(&snake, module_path, docs);
1352 self.export_macros
1353 .push((macro_name, self.interface_names[&id].path.clone()));
1354
1355 if self.opts.stubs {
1356 let world_id = self.world.unwrap();
1357 let mut r#gen = self.interface(
1358 Identifier::World(world_id),
1359 &wasm_import_module,
1360 resolve,
1361 false,
1362 );
1363 r#gen.generate_stub(Some((id, name)), resolve.interfaces[id].functions.values());
1364 let stub = r#gen.finish();
1365 self.src.push_str(&stub);
1366 }
1367 Ok(())
1368 }
1369
1370 fn export_funcs(
1371 &mut self,
1372 resolve: &Resolve,
1373 world: WorldId,
1374 funcs: &[(&str, &Function)],
1375 _files: &mut Files,
1376 ) -> Result<()> {
1377 let mut r#gen = self.interface(Identifier::World(world), "[export]$root", resolve, false);
1378 let macro_name = r#gen.generate_exports(None, funcs.iter().map(|f| f.1))?;
1379 let src = r#gen.finish();
1380 self.src.push_str(&src);
1381 self.export_macros.push((macro_name, String::new()));
1382
1383 if self.opts.stubs {
1384 let mut r#gen =
1385 self.interface(Identifier::World(world), "[export]$root", resolve, false);
1386 r#gen.generate_stub(None, funcs.iter().map(|f| f.1));
1387 let stub = r#gen.finish();
1388 self.src.push_str(&stub);
1389 }
1390 Ok(())
1391 }
1392
1393 fn import_types(
1394 &mut self,
1395 resolve: &Resolve,
1396 world: WorldId,
1397 types: &[(&str, TypeId)],
1398 _files: &mut Files,
1399 ) {
1400 let mut to_define = Vec::new();
1401 for (name, ty_id) in types {
1402 let full_name = full_wit_type_name(resolve, *ty_id);
1403 if let Some(type_gen) = self.with.get(&full_name) {
1404 if type_gen.generated() {
1406 to_define.push((name, ty_id));
1407 }
1408 } else {
1409 to_define.push((name, ty_id));
1410 }
1411 self.generated_types.insert(full_name);
1412 }
1413 let mut r#gen = self.interface(Identifier::World(world), "$root", resolve, true);
1414 for (name, ty) in to_define {
1415 r#gen.define_type(name, *ty);
1416 }
1417 let src = r#gen.finish();
1418 self.src.push_str(&src);
1419 }
1420
1421 fn finish_imports(&mut self, resolve: &Resolve, world: WorldId, files: &mut Files) {
1422 if !self.import_funcs_called {
1423 self.import_funcs(resolve, world, &[], files);
1427 }
1428 }
1429
1430 fn finish(&mut self, resolve: &Resolve, world: WorldId, files: &mut Files) -> Result<()> {
1431 let name = &resolve.worlds[world].name;
1432
1433 let imports = mem::take(&mut self.import_modules);
1434 self.emit_modules(imports);
1435 let exports = mem::take(&mut self.export_modules);
1436 self.emit_modules(exports);
1437
1438 self.finish_runtime_module();
1439 self.finish_export_macro(resolve, world);
1440
1441 let mut resolve_copy;
1480 let (resolve_to_encode, world_to_encode) = if self.opts.pub_export_macro {
1481 resolve_copy = resolve.clone();
1482 let world_copy = resolve_copy.worlds.alloc(World {
1483 exports: Default::default(),
1484 name: format!("{name}-with-all-of-its-exports-removed"),
1485 ..resolve.worlds[world].clone()
1486 });
1487 (&resolve_copy, world_copy)
1488 } else {
1489 (resolve, world)
1490 };
1491 self.emit_custom_section(
1492 resolve_to_encode,
1493 world_to_encode,
1494 "encoded world",
1495 if self.opts.disable_custom_section_link_helpers {
1496 None
1497 } else {
1498 Some("__link_custom_section_describing_imports")
1499 },
1500 );
1501
1502 if self.opts.stubs {
1503 self.src.push_str("\n#[derive(Debug)]\npub struct Stub;\n");
1504 }
1505
1506 let mut src = mem::take(&mut self.src);
1507 if self.opts.format {
1508 let syntax_tree = syn::parse_file(src.as_str()).unwrap();
1509 *src.as_mut_string() = prettyplease::unparse(&syntax_tree);
1510 }
1511
1512 let src_preamble = mem::take(&mut self.src_preamble);
1515 *src.as_mut_string() = format!("{}{}", src_preamble.as_str(), src.as_str());
1516
1517 let module_name = name.to_snake_case();
1518 files.push(&format!("{module_name}.rs"), src.as_bytes());
1519
1520 let remapped_keys = self
1521 .with
1522 .iter()
1523 .map(|(k, _)| k)
1524 .cloned()
1525 .collect::<HashSet<String>>();
1526
1527 let mut unused_keys = remapped_keys
1528 .difference(&self.generated_types)
1529 .collect::<Vec<&String>>();
1530
1531 unused_keys.sort();
1532
1533 if !unused_keys.is_empty() {
1534 bail!("unused remappings provided via `with`: {unused_keys:?}");
1535 }
1536
1537 self.opts.async_.ensure_all_used()?;
1540
1541 Ok(())
1542 }
1543}
1544
1545pub(crate) fn compute_module_path(
1546 name: &WorldKey,
1547 resolve: &Resolve,
1548 is_export: bool,
1549) -> Vec<String> {
1550 let mut path = Vec::new();
1551 if is_export {
1552 path.push("exports".to_string());
1553 }
1554 match name {
1555 WorldKey::Name(name) => {
1556 path.push(to_rust_ident(name));
1557 }
1558 WorldKey::Interface(id) => {
1559 let iface = &resolve.interfaces[*id];
1560 let pkg = iface.package.unwrap();
1561 let pkgname = resolve.packages[pkg].name.clone();
1562 path.push(to_rust_ident(&pkgname.namespace));
1563 path.push(name_package_module(resolve, pkg));
1564 path.push(to_rust_ident(iface.name.as_ref().unwrap()));
1565 }
1566 }
1567 path
1568}
1569
1570enum Identifier<'a> {
1571 World(WorldId),
1572 Interface(InterfaceId, &'a WorldKey),
1573 StreamOrFuturePayload,
1574}
1575
1576fn group_by_resource<'a>(
1577 funcs: impl Iterator<Item = &'a Function>,
1578) -> BTreeMap<Option<TypeId>, Vec<&'a Function>> {
1579 let mut by_resource = BTreeMap::<_, Vec<_>>::new();
1580 for func in funcs {
1581 by_resource
1582 .entry(func.kind.resource())
1583 .or_default()
1584 .push(func);
1585 }
1586 by_resource
1587}
1588
1589#[derive(Default, Debug, Clone, Copy)]
1590#[cfg_attr(
1591 feature = "serde",
1592 derive(serde::Deserialize),
1593 serde(rename_all = "kebab-case")
1594)]
1595pub enum Ownership {
1596 #[default]
1599 Owning,
1600
1601 Borrowing {
1605 duplicate_if_necessary: bool,
1610 },
1611}
1612
1613impl FromStr for Ownership {
1614 type Err = String;
1615
1616 fn from_str(s: &str) -> Result<Self, Self::Err> {
1617 match s {
1618 "owning" => Ok(Self::Owning),
1619 "borrowing" => Ok(Self::Borrowing {
1620 duplicate_if_necessary: false,
1621 }),
1622 "borrowing-duplicate-if-necessary" => Ok(Self::Borrowing {
1623 duplicate_if_necessary: true,
1624 }),
1625 _ => Err(format!(
1626 "unrecognized ownership: `{s}`; \
1627 expected `owning`, `borrowing`, or `borrowing-duplicate-if-necessary`"
1628 )),
1629 }
1630 }
1631}
1632
1633impl fmt::Display for Ownership {
1634 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1635 f.write_str(match self {
1636 Ownership::Owning => "owning",
1637 Ownership::Borrowing {
1638 duplicate_if_necessary: false,
1639 } => "borrowing",
1640 Ownership::Borrowing {
1641 duplicate_if_necessary: true,
1642 } => "borrowing-duplicate-if-necessary",
1643 })
1644 }
1645}
1646
1647#[derive(Debug, Clone)]
1649#[cfg_attr(
1650 feature = "serde",
1651 derive(serde::Deserialize),
1652 serde(rename_all = "kebab-case")
1653)]
1654pub enum WithOption {
1655 Path(String),
1656 Generate,
1657}
1658
1659impl std::fmt::Display for WithOption {
1660 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1661 match self {
1662 WithOption::Path(p) => f.write_fmt(format_args!("\"{p}\"")),
1663 WithOption::Generate => f.write_str("generate"),
1664 }
1665 }
1666}
1667
1668impl From<WithOption> for TypeGeneration {
1669 fn from(opt: WithOption) -> Self {
1670 match opt {
1671 WithOption::Path(p) => TypeGeneration::Remap(p),
1672 WithOption::Generate => TypeGeneration::Generate,
1673 }
1674 }
1675}
1676
1677#[derive(Default)]
1678struct FnSig {
1679 async_: bool,
1680 unsafe_: bool,
1681 private: bool,
1682 use_item_name: bool,
1683 generics: Option<String>,
1684 self_arg: Option<String>,
1685 self_is_first_param: bool,
1686}
1687
1688impl FnSig {
1689 fn update_for_func(&mut self, func: &Function) {
1690 if let FunctionKind::Method(_) | FunctionKind::AsyncMethod(_) = &func.kind {
1691 self.self_arg = Some("&self".into());
1692 self.self_is_first_param = true;
1693 }
1694 }
1695}
1696
1697pub fn to_rust_ident(name: &str) -> String {
1698 match name {
1699 "as" => "as_".into(),
1702 "break" => "break_".into(),
1703 "const" => "const_".into(),
1704 "continue" => "continue_".into(),
1705 "crate" => "crate_".into(),
1706 "else" => "else_".into(),
1707 "enum" => "enum_".into(),
1708 "extern" => "extern_".into(),
1709 "false" => "false_".into(),
1710 "fn" => "fn_".into(),
1711 "for" => "for_".into(),
1712 "if" => "if_".into(),
1713 "impl" => "impl_".into(),
1714 "in" => "in_".into(),
1715 "let" => "let_".into(),
1716 "loop" => "loop_".into(),
1717 "match" => "match_".into(),
1718 "mod" => "mod_".into(),
1719 "move" => "move_".into(),
1720 "mut" => "mut_".into(),
1721 "pub" => "pub_".into(),
1722 "ref" => "ref_".into(),
1723 "return" => "return_".into(),
1724 "self" => "self_".into(),
1725 "static" => "static_".into(),
1726 "struct" => "struct_".into(),
1727 "super" => "super_".into(),
1728 "trait" => "trait_".into(),
1729 "true" => "true_".into(),
1730 "type" => "type_".into(),
1731 "unsafe" => "unsafe_".into(),
1732 "use" => "use_".into(),
1733 "where" => "where_".into(),
1734 "while" => "while_".into(),
1735 "async" => "async_".into(),
1736 "await" => "await_".into(),
1737 "dyn" => "dyn_".into(),
1738 "abstract" => "abstract_".into(),
1739 "become" => "become_".into(),
1740 "box" => "box_".into(),
1741 "do" => "do_".into(),
1742 "final" => "final_".into(),
1743 "macro" => "macro_".into(),
1744 "override" => "override_".into(),
1745 "priv" => "priv_".into(),
1746 "typeof" => "typeof_".into(),
1747 "unsized" => "unsized_".into(),
1748 "virtual" => "virtual_".into(),
1749 "yield" => "yield_".into(),
1750 "try" => "try_".into(),
1751 s => s.to_snake_case(),
1752 }
1753}
1754
1755fn to_upper_camel_case(name: &str) -> String {
1756 match name {
1757 "guest" => "Guest_".to_string(),
1760 s => s.to_upper_camel_case(),
1761 }
1762}
1763
1764fn wasm_type(ty: WasmType) -> &'static str {
1765 match ty {
1766 WasmType::I32 => "i32",
1767 WasmType::I64 => "i64",
1768 WasmType::F32 => "f32",
1769 WasmType::F64 => "f64",
1770 WasmType::Pointer => "*mut u8",
1771 WasmType::Length => "usize",
1772
1773 WasmType::PointerOrI64 => "::core::mem::MaybeUninit::<u64>",
1779 }
1780}
1781
1782fn declare_import(
1783 wasm_import_module: &str,
1784 wasm_import_name: &str,
1785 rust_name: &str,
1786 params: &[WasmType],
1787 results: &[WasmType],
1788) -> String {
1789 let mut sig = "(".to_owned();
1790 for param in params.iter() {
1791 sig.push_str("_: ");
1792 sig.push_str(wasm_type(*param));
1793 sig.push_str(", ");
1794 }
1795 sig.push(')');
1796 assert!(results.len() < 2);
1797 for result in results.iter() {
1798 sig.push_str(" -> ");
1799 sig.push_str(wasm_type(*result));
1800 }
1801 format!(
1802 "
1803 #[cfg(target_arch = \"wasm32\")]
1804 #[link(wasm_import_module = \"{wasm_import_module}\")]
1805 unsafe extern \"C\" {{
1806 #[link_name = \"{wasm_import_name}\"]
1807 fn {rust_name}{sig};
1808 }}
1809
1810 #[cfg(not(target_arch = \"wasm32\"))]
1811 unsafe extern \"C\" fn {rust_name}{sig} {{ unreachable!() }}
1812 "
1813 )
1814}
1815
1816fn int_repr(repr: Int) -> &'static str {
1817 match repr {
1818 Int::U8 => "u8",
1819 Int::U16 => "u16",
1820 Int::U32 => "u32",
1821 Int::U64 => "u64",
1822 }
1823}
1824
1825fn bitcast(casts: &[Bitcast], operands: &[String], results: &mut Vec<String>) {
1826 for (cast, operand) in casts.iter().zip(operands) {
1827 results.push(perform_cast(operand, cast));
1828 }
1829}
1830
1831fn perform_cast(operand: &str, cast: &Bitcast) -> String {
1832 match cast {
1833 Bitcast::None => operand.to_owned(),
1834 Bitcast::I32ToI64 => format!("i64::from({operand})"),
1835 Bitcast::F32ToI32 => format!("({operand}).to_bits() as i32"),
1836 Bitcast::F64ToI64 => format!("({operand}).to_bits() as i64"),
1837 Bitcast::I64ToI32 => format!("{operand} as i32"),
1838 Bitcast::I32ToF32 => format!("f32::from_bits({operand} as u32)"),
1839 Bitcast::I64ToF64 => format!("f64::from_bits({operand} as u64)"),
1840 Bitcast::F32ToI64 => format!("i64::from(({operand}).to_bits())"),
1841 Bitcast::I64ToF32 => format!("f32::from_bits({operand} as u32)"),
1842
1843 Bitcast::I64ToP64 => format!("::core::mem::MaybeUninit::new({operand} as u64)"),
1845 Bitcast::P64ToI64 => format!("{operand}.assume_init() as i64"),
1848
1849 Bitcast::PToP64 => {
1851 format!(
1852 "{{
1853 let mut t = ::core::mem::MaybeUninit::<u64>::uninit();
1854 t.as_mut_ptr().cast::<*mut u8>().write({operand});
1855 t
1856 }}"
1857 )
1858 }
1859 Bitcast::P64ToP => {
1862 format!("{operand}.as_ptr().cast::<*mut u8>().read()")
1863 }
1864 Bitcast::I32ToP | Bitcast::LToP => {
1866 format!("{operand} as *mut u8")
1867 }
1868 Bitcast::PToI32 | Bitcast::LToI32 => {
1870 format!("{operand} as i32")
1871 }
1872 Bitcast::I32ToL | Bitcast::I64ToL | Bitcast::PToL => {
1874 format!("{operand} as usize")
1875 }
1876 Bitcast::LToI64 => {
1878 format!("{operand} as i64")
1879 }
1880 Bitcast::Sequence(sequence) => {
1881 let [first, second] = &**sequence;
1882 perform_cast(&perform_cast(operand, first), second)
1883 }
1884 }
1885}
1886
1887enum RustFlagsRepr {
1888 U8,
1889 U16,
1890 U32,
1891 U64,
1892 U128,
1893}
1894
1895impl RustFlagsRepr {
1896 fn new(f: &Flags) -> RustFlagsRepr {
1897 match f.repr() {
1898 FlagsRepr::U8 => RustFlagsRepr::U8,
1899 FlagsRepr::U16 => RustFlagsRepr::U16,
1900 FlagsRepr::U32(1) => RustFlagsRepr::U32,
1901 FlagsRepr::U32(2) => RustFlagsRepr::U64,
1902 FlagsRepr::U32(3 | 4) => RustFlagsRepr::U128,
1903 FlagsRepr::U32(n) => panic!("unsupported number of flags: {}", n * 32),
1904 }
1905 }
1906}
1907
1908impl fmt::Display for RustFlagsRepr {
1909 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1910 match self {
1911 RustFlagsRepr::U8 => "u8".fmt(f),
1912 RustFlagsRepr::U16 => "u16".fmt(f),
1913 RustFlagsRepr::U32 => "u32".fmt(f),
1914 RustFlagsRepr::U64 => "u64".fmt(f),
1915 RustFlagsRepr::U128 => "u128".fmt(f),
1916 }
1917 }
1918}
1919
1920#[derive(Debug, Clone)]
1921pub struct MissingWith(pub String);
1922
1923impl fmt::Display for MissingWith {
1924 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1925 write!(f, "missing `with` mapping for the key `{}`", self.0)
1926 }
1927}
1928
1929impl std::error::Error for MissingWith {}
1930
1931fn full_wit_type_name(resolve: &Resolve, id: TypeId) -> String {
1938 let id = dealias(resolve, id);
1939 let type_def = &resolve.types[id];
1940 let interface_name = match type_def.owner {
1941 TypeOwner::World(w) => Some(resolve.worlds[w].name.clone()),
1942 TypeOwner::Interface(id) => resolve.id_of(id),
1943 TypeOwner::None => None,
1944 };
1945 match interface_name {
1946 Some(interface_name) => format!("{}/{}", interface_name, type_def.name.clone().unwrap()),
1947 None => type_def.name.clone().unwrap(),
1948 }
1949}
1950
1951enum ConstructorReturnType {
1952 Self_,
1959
1960 Result { err: Option<Type> },
1967}
1968
1969fn classify_constructor_return_type(
1970 resolve: &Resolve,
1971 resource_id: TypeId,
1972 result: &Option<Type>,
1973) -> ConstructorReturnType {
1974 fn classify(
1975 resolve: &Resolve,
1976 resource_id: TypeId,
1977 result: &Option<Type>,
1978 ) -> Option<ConstructorReturnType> {
1979 let resource_id = dealias(resolve, resource_id);
1980 let typedef = match result.as_ref()? {
1981 Type::Id(id) => &resolve.types[dealias(resolve, *id)],
1982 _ => return None,
1983 };
1984
1985 match &typedef.kind {
1986 TypeDefKind::Handle(Handle::Own(id)) if dealias(resolve, *id) == resource_id => {
1987 Some(ConstructorReturnType::Self_)
1988 }
1989 TypeDefKind::Result(Result_ { ok, err }) => {
1990 let ok_typedef = match ok.as_ref()? {
1991 Type::Id(id) => &resolve.types[dealias(resolve, *id)],
1992 _ => return None,
1993 };
1994
1995 match &ok_typedef.kind {
1996 TypeDefKind::Handle(Handle::Own(id))
1997 if dealias(resolve, *id) == resource_id =>
1998 {
1999 Some(ConstructorReturnType::Result { err: *err })
2000 }
2001 _ => None,
2002 }
2003 }
2004 _ => None,
2005 }
2006 }
2007
2008 classify(resolve, resource_id, result).expect("invalid constructor")
2009}