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) {
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).unwrap();
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).unwrap();
1248 }
1249 }
1250 }
1251
1252 fn import_interface(
1253 &mut self,
1254 resolve: &Resolve,
1255 name: &WorldKey,
1256 id: InterfaceId,
1257 _files: &mut Files,
1258 ) -> Result<()> {
1259 let mut to_define = Vec::new();
1260 for (name, ty_id) in resolve.interfaces[id].types.iter() {
1261 let full_name = full_wit_type_name(resolve, *ty_id);
1262 if let Some(type_gen) = self.with.get(&full_name) {
1263 if type_gen.generated() {
1265 to_define.push((name, ty_id));
1266 }
1267 } else {
1268 to_define.push((name, ty_id));
1269 }
1270 self.generated_types.insert(full_name);
1271 }
1272
1273 let wasm_import_module = resolve.name_world_key(name);
1274 let mut r#gen = self.interface(
1275 Identifier::Interface(id, name),
1276 &wasm_import_module,
1277 resolve,
1278 true,
1279 );
1280 let (snake, module_path) = r#gen.start_append_submodule(name);
1281 if r#gen.r#gen.interface_names[&id].remapped {
1282 return Ok(());
1283 }
1284
1285 for (name, ty_id) in to_define {
1286 r#gen.define_type(&name, *ty_id);
1287 }
1288
1289 r#gen.generate_imports(resolve.interfaces[id].functions.values(), Some(name));
1290
1291 let docs = &resolve.interfaces[id].docs;
1292
1293 r#gen.finish_append_submodule(&snake, module_path, docs);
1294
1295 Ok(())
1296 }
1297
1298 fn import_funcs(
1299 &mut self,
1300 resolve: &Resolve,
1301 world: WorldId,
1302 funcs: &[(&str, &Function)],
1303 _files: &mut Files,
1304 ) {
1305 self.import_funcs_called = true;
1306
1307 let mut r#gen = self.interface(Identifier::World(world), "$root", resolve, true);
1308
1309 r#gen.generate_imports(funcs.iter().map(|(_, func)| *func), None);
1310
1311 let src = r#gen.finish();
1312 self.src.push_str(&src);
1313 }
1314
1315 fn export_interface(
1316 &mut self,
1317 resolve: &Resolve,
1318 name: &WorldKey,
1319 id: InterfaceId,
1320 _files: &mut Files,
1321 ) -> Result<()> {
1322 let mut to_define = Vec::new();
1323 for (ty_name, ty_id) in resolve.interfaces[id].types.iter() {
1324 let full_name = full_wit_type_name(resolve, *ty_id);
1325 to_define.push((ty_name, ty_id));
1326 self.generated_types.insert(full_name);
1327 }
1328
1329 let wasm_import_module = format!("[export]{}", resolve.name_world_key(name));
1330 let mut r#gen = self.interface(
1331 Identifier::Interface(id, name),
1332 &wasm_import_module,
1333 resolve,
1334 false,
1335 );
1336 let (snake, module_path) = r#gen.start_append_submodule(name);
1337 if r#gen.r#gen.interface_names[&id].remapped {
1338 return Ok(());
1339 }
1340
1341 for (ty_name, ty_id) in to_define {
1342 r#gen.define_type(&ty_name, *ty_id);
1343 }
1344
1345 let macro_name =
1346 r#gen.generate_exports(Some((id, name)), resolve.interfaces[id].functions.values())?;
1347
1348 let docs = &resolve.interfaces[id].docs;
1349
1350 r#gen.finish_append_submodule(&snake, module_path, docs);
1351 self.export_macros
1352 .push((macro_name, self.interface_names[&id].path.clone()));
1353
1354 if self.opts.stubs {
1355 let world_id = self.world.unwrap();
1356 let mut r#gen = self.interface(
1357 Identifier::World(world_id),
1358 &wasm_import_module,
1359 resolve,
1360 false,
1361 );
1362 r#gen.generate_stub(Some((id, name)), resolve.interfaces[id].functions.values());
1363 let stub = r#gen.finish();
1364 self.src.push_str(&stub);
1365 }
1366 Ok(())
1367 }
1368
1369 fn export_funcs(
1370 &mut self,
1371 resolve: &Resolve,
1372 world: WorldId,
1373 funcs: &[(&str, &Function)],
1374 _files: &mut Files,
1375 ) -> Result<()> {
1376 let mut r#gen = self.interface(Identifier::World(world), "[export]$root", resolve, false);
1377 let macro_name = r#gen.generate_exports(None, funcs.iter().map(|f| f.1))?;
1378 let src = r#gen.finish();
1379 self.src.push_str(&src);
1380 self.export_macros.push((macro_name, String::new()));
1381
1382 if self.opts.stubs {
1383 let mut r#gen =
1384 self.interface(Identifier::World(world), "[export]$root", resolve, false);
1385 r#gen.generate_stub(None, funcs.iter().map(|f| f.1));
1386 let stub = r#gen.finish();
1387 self.src.push_str(&stub);
1388 }
1389 Ok(())
1390 }
1391
1392 fn import_types(
1393 &mut self,
1394 resolve: &Resolve,
1395 world: WorldId,
1396 types: &[(&str, TypeId)],
1397 _files: &mut Files,
1398 ) {
1399 let mut to_define = Vec::new();
1400 for (name, ty_id) in types {
1401 let full_name = full_wit_type_name(resolve, *ty_id);
1402 if let Some(type_gen) = self.with.get(&full_name) {
1403 if type_gen.generated() {
1405 to_define.push((name, ty_id));
1406 }
1407 } else {
1408 to_define.push((name, ty_id));
1409 }
1410 self.generated_types.insert(full_name);
1411 }
1412 let mut r#gen = self.interface(Identifier::World(world), "$root", resolve, true);
1413 for (name, ty) in to_define {
1414 r#gen.define_type(name, *ty);
1415 }
1416 let src = r#gen.finish();
1417 self.src.push_str(&src);
1418 }
1419
1420 fn finish_imports(&mut self, resolve: &Resolve, world: WorldId, files: &mut Files) {
1421 if !self.import_funcs_called {
1422 self.import_funcs(resolve, world, &[], files);
1426 }
1427 }
1428
1429 fn finish(&mut self, resolve: &Resolve, world: WorldId, files: &mut Files) -> Result<()> {
1430 let name = &resolve.worlds[world].name;
1431
1432 let imports = mem::take(&mut self.import_modules);
1433 self.emit_modules(imports);
1434 let exports = mem::take(&mut self.export_modules);
1435 self.emit_modules(exports);
1436
1437 self.finish_runtime_module();
1438 self.finish_export_macro(resolve, world);
1439
1440 let mut resolve_copy;
1479 let (resolve_to_encode, world_to_encode) = if self.opts.pub_export_macro {
1480 resolve_copy = resolve.clone();
1481 let world_copy = resolve_copy.worlds.alloc(World {
1482 exports: Default::default(),
1483 name: format!("{name}-with-all-of-its-exports-removed"),
1484 ..resolve.worlds[world].clone()
1485 });
1486 (&resolve_copy, world_copy)
1487 } else {
1488 (resolve, world)
1489 };
1490 self.emit_custom_section(
1491 resolve_to_encode,
1492 world_to_encode,
1493 "encoded world",
1494 if self.opts.disable_custom_section_link_helpers {
1495 None
1496 } else {
1497 Some("__link_custom_section_describing_imports")
1498 },
1499 );
1500
1501 if self.opts.stubs {
1502 self.src.push_str("\n#[derive(Debug)]\npub struct Stub;\n");
1503 }
1504
1505 let mut src = mem::take(&mut self.src);
1506 if self.opts.format {
1507 let syntax_tree = syn::parse_file(src.as_str()).unwrap();
1508 *src.as_mut_string() = prettyplease::unparse(&syntax_tree);
1509 }
1510
1511 let src_preamble = mem::take(&mut self.src_preamble);
1514 *src.as_mut_string() = format!("{}{}", src_preamble.as_str(), src.as_str());
1515
1516 let module_name = name.to_snake_case();
1517 files.push(&format!("{module_name}.rs"), src.as_bytes());
1518
1519 let remapped_keys = self
1520 .with
1521 .iter()
1522 .map(|(k, _)| k)
1523 .cloned()
1524 .collect::<HashSet<String>>();
1525
1526 let mut unused_keys = remapped_keys
1527 .difference(&self.generated_types)
1528 .collect::<Vec<&String>>();
1529
1530 unused_keys.sort();
1531
1532 if !unused_keys.is_empty() {
1533 bail!("unused remappings provided via `with`: {unused_keys:?}");
1534 }
1535
1536 self.opts.async_.ensure_all_used()?;
1539
1540 Ok(())
1541 }
1542}
1543
1544pub(crate) fn compute_module_path(
1545 name: &WorldKey,
1546 resolve: &Resolve,
1547 is_export: bool,
1548) -> Vec<String> {
1549 let mut path = Vec::new();
1550 if is_export {
1551 path.push("exports".to_string());
1552 }
1553 match name {
1554 WorldKey::Name(name) => {
1555 path.push(to_rust_ident(name));
1556 }
1557 WorldKey::Interface(id) => {
1558 let iface = &resolve.interfaces[*id];
1559 let pkg = iface.package.unwrap();
1560 let pkgname = resolve.packages[pkg].name.clone();
1561 path.push(to_rust_ident(&pkgname.namespace));
1562 path.push(name_package_module(resolve, pkg));
1563 path.push(to_rust_ident(iface.name.as_ref().unwrap()));
1564 }
1565 }
1566 path
1567}
1568
1569enum Identifier<'a> {
1570 World(WorldId),
1571 Interface(InterfaceId, &'a WorldKey),
1572 StreamOrFuturePayload,
1573}
1574
1575fn group_by_resource<'a>(
1576 funcs: impl Iterator<Item = &'a Function>,
1577) -> BTreeMap<Option<TypeId>, Vec<&'a Function>> {
1578 let mut by_resource = BTreeMap::<_, Vec<_>>::new();
1579 for func in funcs {
1580 by_resource
1581 .entry(func.kind.resource())
1582 .or_default()
1583 .push(func);
1584 }
1585 by_resource
1586}
1587
1588#[derive(Default, Debug, Clone, Copy)]
1589#[cfg_attr(
1590 feature = "serde",
1591 derive(serde::Deserialize),
1592 serde(rename_all = "kebab-case")
1593)]
1594pub enum Ownership {
1595 #[default]
1598 Owning,
1599
1600 Borrowing {
1604 duplicate_if_necessary: bool,
1609 },
1610}
1611
1612impl FromStr for Ownership {
1613 type Err = String;
1614
1615 fn from_str(s: &str) -> Result<Self, Self::Err> {
1616 match s {
1617 "owning" => Ok(Self::Owning),
1618 "borrowing" => Ok(Self::Borrowing {
1619 duplicate_if_necessary: false,
1620 }),
1621 "borrowing-duplicate-if-necessary" => Ok(Self::Borrowing {
1622 duplicate_if_necessary: true,
1623 }),
1624 _ => Err(format!(
1625 "unrecognized ownership: `{s}`; \
1626 expected `owning`, `borrowing`, or `borrowing-duplicate-if-necessary`"
1627 )),
1628 }
1629 }
1630}
1631
1632impl fmt::Display for Ownership {
1633 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1634 f.write_str(match self {
1635 Ownership::Owning => "owning",
1636 Ownership::Borrowing {
1637 duplicate_if_necessary: false,
1638 } => "borrowing",
1639 Ownership::Borrowing {
1640 duplicate_if_necessary: true,
1641 } => "borrowing-duplicate-if-necessary",
1642 })
1643 }
1644}
1645
1646#[derive(Debug, Clone)]
1648#[cfg_attr(
1649 feature = "serde",
1650 derive(serde::Deserialize),
1651 serde(rename_all = "kebab-case")
1652)]
1653pub enum WithOption {
1654 Path(String),
1655 Generate,
1656}
1657
1658impl std::fmt::Display for WithOption {
1659 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1660 match self {
1661 WithOption::Path(p) => f.write_fmt(format_args!("\"{p}\"")),
1662 WithOption::Generate => f.write_str("generate"),
1663 }
1664 }
1665}
1666
1667impl From<WithOption> for TypeGeneration {
1668 fn from(opt: WithOption) -> Self {
1669 match opt {
1670 WithOption::Path(p) => TypeGeneration::Remap(p),
1671 WithOption::Generate => TypeGeneration::Generate,
1672 }
1673 }
1674}
1675
1676#[derive(Default)]
1677struct FnSig {
1678 async_: bool,
1679 unsafe_: bool,
1680 private: bool,
1681 use_item_name: bool,
1682 generics: Option<String>,
1683 self_arg: Option<String>,
1684 self_is_first_param: bool,
1685}
1686
1687impl FnSig {
1688 fn update_for_func(&mut self, func: &Function) {
1689 if let FunctionKind::Method(_) | FunctionKind::AsyncMethod(_) = &func.kind {
1690 self.self_arg = Some("&self".into());
1691 self.self_is_first_param = true;
1692 }
1693 }
1694}
1695
1696pub fn to_rust_ident(name: &str) -> String {
1697 match name {
1698 "as" => "as_".into(),
1701 "break" => "break_".into(),
1702 "const" => "const_".into(),
1703 "continue" => "continue_".into(),
1704 "crate" => "crate_".into(),
1705 "else" => "else_".into(),
1706 "enum" => "enum_".into(),
1707 "extern" => "extern_".into(),
1708 "false" => "false_".into(),
1709 "fn" => "fn_".into(),
1710 "for" => "for_".into(),
1711 "if" => "if_".into(),
1712 "impl" => "impl_".into(),
1713 "in" => "in_".into(),
1714 "let" => "let_".into(),
1715 "loop" => "loop_".into(),
1716 "match" => "match_".into(),
1717 "mod" => "mod_".into(),
1718 "move" => "move_".into(),
1719 "mut" => "mut_".into(),
1720 "pub" => "pub_".into(),
1721 "ref" => "ref_".into(),
1722 "return" => "return_".into(),
1723 "self" => "self_".into(),
1724 "static" => "static_".into(),
1725 "struct" => "struct_".into(),
1726 "super" => "super_".into(),
1727 "trait" => "trait_".into(),
1728 "true" => "true_".into(),
1729 "type" => "type_".into(),
1730 "unsafe" => "unsafe_".into(),
1731 "use" => "use_".into(),
1732 "where" => "where_".into(),
1733 "while" => "while_".into(),
1734 "async" => "async_".into(),
1735 "await" => "await_".into(),
1736 "dyn" => "dyn_".into(),
1737 "abstract" => "abstract_".into(),
1738 "become" => "become_".into(),
1739 "box" => "box_".into(),
1740 "do" => "do_".into(),
1741 "final" => "final_".into(),
1742 "macro" => "macro_".into(),
1743 "override" => "override_".into(),
1744 "priv" => "priv_".into(),
1745 "typeof" => "typeof_".into(),
1746 "unsized" => "unsized_".into(),
1747 "virtual" => "virtual_".into(),
1748 "yield" => "yield_".into(),
1749 "try" => "try_".into(),
1750 s => s.to_snake_case(),
1751 }
1752}
1753
1754fn to_upper_camel_case(name: &str) -> String {
1755 match name {
1756 "guest" => "Guest_".to_string(),
1759 s => s.to_upper_camel_case(),
1760 }
1761}
1762
1763fn wasm_type(ty: WasmType) -> &'static str {
1764 match ty {
1765 WasmType::I32 => "i32",
1766 WasmType::I64 => "i64",
1767 WasmType::F32 => "f32",
1768 WasmType::F64 => "f64",
1769 WasmType::Pointer => "*mut u8",
1770 WasmType::Length => "usize",
1771
1772 WasmType::PointerOrI64 => "::core::mem::MaybeUninit::<u64>",
1778 }
1779}
1780
1781fn declare_import(
1782 wasm_import_module: &str,
1783 wasm_import_name: &str,
1784 rust_name: &str,
1785 params: &[WasmType],
1786 results: &[WasmType],
1787) -> String {
1788 let mut sig = "(".to_owned();
1789 for param in params.iter() {
1790 sig.push_str("_: ");
1791 sig.push_str(wasm_type(*param));
1792 sig.push_str(", ");
1793 }
1794 sig.push(')');
1795 assert!(results.len() < 2);
1796 for result in results.iter() {
1797 sig.push_str(" -> ");
1798 sig.push_str(wasm_type(*result));
1799 }
1800 format!(
1801 "
1802 #[cfg(target_arch = \"wasm32\")]
1803 #[link(wasm_import_module = \"{wasm_import_module}\")]
1804 unsafe extern \"C\" {{
1805 #[link_name = \"{wasm_import_name}\"]
1806 fn {rust_name}{sig};
1807 }}
1808
1809 #[cfg(not(target_arch = \"wasm32\"))]
1810 unsafe extern \"C\" fn {rust_name}{sig} {{ unreachable!() }}
1811 "
1812 )
1813}
1814
1815fn int_repr(repr: Int) -> &'static str {
1816 match repr {
1817 Int::U8 => "u8",
1818 Int::U16 => "u16",
1819 Int::U32 => "u32",
1820 Int::U64 => "u64",
1821 }
1822}
1823
1824fn bitcast(casts: &[Bitcast], operands: &[String], results: &mut Vec<String>) {
1825 for (cast, operand) in casts.iter().zip(operands) {
1826 results.push(perform_cast(operand, cast));
1827 }
1828}
1829
1830fn perform_cast(operand: &str, cast: &Bitcast) -> String {
1831 match cast {
1832 Bitcast::None => operand.to_owned(),
1833 Bitcast::I32ToI64 => format!("i64::from({operand})"),
1834 Bitcast::F32ToI32 => format!("({operand}).to_bits() as i32"),
1835 Bitcast::F64ToI64 => format!("({operand}).to_bits() as i64"),
1836 Bitcast::I64ToI32 => format!("{operand} as i32"),
1837 Bitcast::I32ToF32 => format!("f32::from_bits({operand} as u32)"),
1838 Bitcast::I64ToF64 => format!("f64::from_bits({operand} as u64)"),
1839 Bitcast::F32ToI64 => format!("i64::from(({operand}).to_bits())"),
1840 Bitcast::I64ToF32 => format!("f32::from_bits({operand} as u32)"),
1841
1842 Bitcast::I64ToP64 => format!("::core::mem::MaybeUninit::new({operand} as u64)"),
1844 Bitcast::P64ToI64 => format!("{operand}.assume_init() as i64"),
1847
1848 Bitcast::PToP64 => {
1850 format!(
1851 "{{
1852 let mut t = ::core::mem::MaybeUninit::<u64>::uninit();
1853 t.as_mut_ptr().cast::<*mut u8>().write({operand});
1854 t
1855 }}"
1856 )
1857 }
1858 Bitcast::P64ToP => {
1861 format!("{operand}.as_ptr().cast::<*mut u8>().read()")
1862 }
1863 Bitcast::I32ToP | Bitcast::LToP => {
1865 format!("{operand} as *mut u8")
1866 }
1867 Bitcast::PToI32 | Bitcast::LToI32 => {
1869 format!("{operand} as i32")
1870 }
1871 Bitcast::I32ToL | Bitcast::I64ToL | Bitcast::PToL => {
1873 format!("{operand} as usize")
1874 }
1875 Bitcast::LToI64 => {
1877 format!("{operand} as i64")
1878 }
1879 Bitcast::Sequence(sequence) => {
1880 let [first, second] = &**sequence;
1881 perform_cast(&perform_cast(operand, first), second)
1882 }
1883 }
1884}
1885
1886enum RustFlagsRepr {
1887 U8,
1888 U16,
1889 U32,
1890 U64,
1891 U128,
1892}
1893
1894impl RustFlagsRepr {
1895 fn new(f: &Flags) -> RustFlagsRepr {
1896 match f.repr() {
1897 FlagsRepr::U8 => RustFlagsRepr::U8,
1898 FlagsRepr::U16 => RustFlagsRepr::U16,
1899 FlagsRepr::U32(1) => RustFlagsRepr::U32,
1900 FlagsRepr::U32(2) => RustFlagsRepr::U64,
1901 FlagsRepr::U32(3 | 4) => RustFlagsRepr::U128,
1902 FlagsRepr::U32(n) => panic!("unsupported number of flags: {}", n * 32),
1903 }
1904 }
1905}
1906
1907impl fmt::Display for RustFlagsRepr {
1908 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1909 match self {
1910 RustFlagsRepr::U8 => "u8".fmt(f),
1911 RustFlagsRepr::U16 => "u16".fmt(f),
1912 RustFlagsRepr::U32 => "u32".fmt(f),
1913 RustFlagsRepr::U64 => "u64".fmt(f),
1914 RustFlagsRepr::U128 => "u128".fmt(f),
1915 }
1916 }
1917}
1918
1919#[derive(Debug, Clone)]
1920pub struct MissingWith(pub String);
1921
1922impl fmt::Display for MissingWith {
1923 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1924 write!(f, "missing `with` mapping for the key `{}`", self.0)
1925 }
1926}
1927
1928impl std::error::Error for MissingWith {}
1929
1930fn full_wit_type_name(resolve: &Resolve, id: TypeId) -> String {
1937 let id = dealias(resolve, id);
1938 let type_def = &resolve.types[id];
1939 let interface_name = match type_def.owner {
1940 TypeOwner::World(w) => Some(resolve.worlds[w].name.clone()),
1941 TypeOwner::Interface(id) => resolve.id_of(id),
1942 TypeOwner::None => None,
1943 };
1944 match interface_name {
1945 Some(interface_name) => format!("{}/{}", interface_name, type_def.name.clone().unwrap()),
1946 None => type_def.name.clone().unwrap(),
1947 }
1948}
1949
1950enum ConstructorReturnType {
1951 Self_,
1958
1959 Result { err: Option<Type> },
1966}
1967
1968fn classify_constructor_return_type(
1969 resolve: &Resolve,
1970 resource_id: TypeId,
1971 result: &Option<Type>,
1972) -> ConstructorReturnType {
1973 fn classify(
1974 resolve: &Resolve,
1975 resource_id: TypeId,
1976 result: &Option<Type>,
1977 ) -> Option<ConstructorReturnType> {
1978 let resource_id = dealias(resolve, resource_id);
1979 let typedef = match result.as_ref()? {
1980 Type::Id(id) => &resolve.types[dealias(resolve, *id)],
1981 _ => return None,
1982 };
1983
1984 match &typedef.kind {
1985 TypeDefKind::Handle(Handle::Own(id)) if dealias(resolve, *id) == resource_id => {
1986 Some(ConstructorReturnType::Self_)
1987 }
1988 TypeDefKind::Result(Result_ { ok, err }) => {
1989 let ok_typedef = match ok.as_ref()? {
1990 Type::Id(id) => &resolve.types[dealias(resolve, *id)],
1991 _ => return None,
1992 };
1993
1994 match &ok_typedef.kind {
1995 TypeDefKind::Handle(Handle::Own(id))
1996 if dealias(resolve, *id) == resource_id =>
1997 {
1998 Some(ConstructorReturnType::Result { err: *err })
1999 }
2000 _ => None,
2001 }
2002 }
2003 _ => None,
2004 }
2005 }
2006
2007 classify(resolve, resource_id, result).expect("invalid constructor")
2008}