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