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, &|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 }
1198
1199 fn import_interface(
1200 &mut self,
1201 resolve: &Resolve,
1202 name: &WorldKey,
1203 id: InterfaceId,
1204 _files: &mut Files,
1205 ) -> Result<()> {
1206 let mut to_define = Vec::new();
1207 for (name, ty_id) in resolve.interfaces[id].types.iter() {
1208 let full_name = full_wit_type_name(resolve, *ty_id);
1209 if let Some(type_gen) = self.with.get(&full_name) {
1210 if type_gen.generated() {
1212 to_define.push((name, ty_id));
1213 }
1214 } else {
1215 to_define.push((name, ty_id));
1216 }
1217 self.generated_types.insert(full_name);
1218 }
1219
1220 let wasm_import_module = resolve.name_world_key(name);
1221 let mut r#gen = self.interface(
1222 Identifier::Interface(id, name),
1223 &wasm_import_module,
1224 resolve,
1225 true,
1226 );
1227 let (snake, module_path) = r#gen.start_append_submodule(name);
1228 if r#gen.r#gen.name_interface(resolve, id, name, false)? {
1229 return Ok(());
1230 }
1231
1232 for (name, ty_id) in to_define {
1233 r#gen.define_type(&name, *ty_id);
1234 }
1235
1236 r#gen.generate_imports(resolve.interfaces[id].functions.values(), Some(name));
1237
1238 let docs = &resolve.interfaces[id].docs;
1239
1240 r#gen.finish_append_submodule(&snake, module_path, docs);
1241
1242 Ok(())
1243 }
1244
1245 fn import_funcs(
1246 &mut self,
1247 resolve: &Resolve,
1248 world: WorldId,
1249 funcs: &[(&str, &Function)],
1250 _files: &mut Files,
1251 ) {
1252 self.import_funcs_called = true;
1253
1254 let mut r#gen = self.interface(Identifier::World(world), "$root", resolve, true);
1255
1256 r#gen.generate_imports(funcs.iter().map(|(_, func)| *func), None);
1257
1258 let src = r#gen.finish();
1259 self.src.push_str(&src);
1260 }
1261
1262 fn export_interface(
1263 &mut self,
1264 resolve: &Resolve,
1265 name: &WorldKey,
1266 id: InterfaceId,
1267 _files: &mut Files,
1268 ) -> Result<()> {
1269 let mut to_define = Vec::new();
1270 for (ty_name, ty_id) in resolve.interfaces[id].types.iter() {
1271 let full_name = full_wit_type_name(resolve, *ty_id);
1272 to_define.push((ty_name, ty_id));
1273 self.generated_types.insert(full_name);
1274 }
1275
1276 let wasm_import_module = format!("[export]{}", resolve.name_world_key(name));
1277 let mut r#gen = self.interface(
1278 Identifier::Interface(id, name),
1279 &wasm_import_module,
1280 resolve,
1281 false,
1282 );
1283 let (snake, module_path) = r#gen.start_append_submodule(name);
1284 if r#gen.r#gen.name_interface(resolve, id, name, true)? {
1285 return Ok(());
1286 }
1287
1288 for (ty_name, ty_id) in to_define {
1289 r#gen.define_type(&ty_name, *ty_id);
1290 }
1291
1292 let macro_name =
1293 r#gen.generate_exports(Some((id, name)), resolve.interfaces[id].functions.values())?;
1294
1295 let docs = &resolve.interfaces[id].docs;
1296
1297 r#gen.finish_append_submodule(&snake, module_path, docs);
1298 self.export_macros
1299 .push((macro_name, self.interface_names[&id].path.clone()));
1300
1301 if self.opts.stubs {
1302 let world_id = self.world.unwrap();
1303 let mut r#gen = self.interface(
1304 Identifier::World(world_id),
1305 &wasm_import_module,
1306 resolve,
1307 false,
1308 );
1309 r#gen.generate_stub(Some((id, name)), resolve.interfaces[id].functions.values());
1310 let stub = r#gen.finish();
1311 self.src.push_str(&stub);
1312 }
1313 Ok(())
1314 }
1315
1316 fn export_funcs(
1317 &mut self,
1318 resolve: &Resolve,
1319 world: WorldId,
1320 funcs: &[(&str, &Function)],
1321 _files: &mut Files,
1322 ) -> Result<()> {
1323 let mut r#gen = self.interface(Identifier::World(world), "[export]$root", resolve, false);
1324 let macro_name = r#gen.generate_exports(None, funcs.iter().map(|f| f.1))?;
1325 let src = r#gen.finish();
1326 self.src.push_str(&src);
1327 self.export_macros.push((macro_name, String::new()));
1328
1329 if self.opts.stubs {
1330 let mut r#gen =
1331 self.interface(Identifier::World(world), "[export]$root", resolve, false);
1332 r#gen.generate_stub(None, funcs.iter().map(|f| f.1));
1333 let stub = r#gen.finish();
1334 self.src.push_str(&stub);
1335 }
1336 Ok(())
1337 }
1338
1339 fn import_types(
1340 &mut self,
1341 resolve: &Resolve,
1342 world: WorldId,
1343 types: &[(&str, TypeId)],
1344 _files: &mut Files,
1345 ) {
1346 let mut to_define = Vec::new();
1347 for (name, ty_id) in types {
1348 let full_name = full_wit_type_name(resolve, *ty_id);
1349 if let Some(type_gen) = self.with.get(&full_name) {
1350 if type_gen.generated() {
1352 to_define.push((name, ty_id));
1353 }
1354 } else {
1355 to_define.push((name, ty_id));
1356 }
1357 self.generated_types.insert(full_name);
1358 }
1359 let mut r#gen = self.interface(Identifier::World(world), "$root", resolve, true);
1360 for (name, ty) in to_define {
1361 r#gen.define_type(name, *ty);
1362 }
1363 let src = r#gen.finish();
1364 self.src.push_str(&src);
1365 }
1366
1367 fn finish_imports(&mut self, resolve: &Resolve, world: WorldId, files: &mut Files) {
1368 if !self.import_funcs_called {
1369 self.import_funcs(resolve, world, &[], files);
1373 }
1374 }
1375
1376 fn finish(&mut self, resolve: &Resolve, world: WorldId, files: &mut Files) -> Result<()> {
1377 let name = &resolve.worlds[world].name;
1378
1379 let imports = mem::take(&mut self.import_modules);
1380 self.emit_modules(imports);
1381 let exports = mem::take(&mut self.export_modules);
1382 self.emit_modules(exports);
1383
1384 self.finish_runtime_module();
1385 self.finish_export_macro(resolve, world);
1386
1387 let mut resolve_copy;
1426 let (resolve_to_encode, world_to_encode) = if self.opts.pub_export_macro {
1427 resolve_copy = resolve.clone();
1428 let world_copy = resolve_copy.worlds.alloc(World {
1429 exports: Default::default(),
1430 name: format!("{name}-with-all-of-its-exports-removed"),
1431 ..resolve.worlds[world].clone()
1432 });
1433 (&resolve_copy, world_copy)
1434 } else {
1435 (resolve, world)
1436 };
1437 self.emit_custom_section(
1438 resolve_to_encode,
1439 world_to_encode,
1440 "encoded world",
1441 if self.opts.disable_custom_section_link_helpers {
1442 None
1443 } else {
1444 Some("__link_custom_section_describing_imports")
1445 },
1446 );
1447
1448 if self.opts.stubs {
1449 self.src.push_str("\n#[derive(Debug)]\npub struct Stub;\n");
1450 }
1451
1452 let mut src = mem::take(&mut self.src);
1453 if self.opts.format {
1454 let syntax_tree = syn::parse_file(src.as_str()).unwrap();
1455 *src.as_mut_string() = prettyplease::unparse(&syntax_tree);
1456 }
1457
1458 let src_preamble = mem::take(&mut self.src_preamble);
1461 *src.as_mut_string() = format!("{}{}", src_preamble.as_str(), src.as_str());
1462
1463 let module_name = name.to_snake_case();
1464 files.push(&format!("{module_name}.rs"), src.as_bytes());
1465
1466 let remapped_keys = self
1467 .with
1468 .iter()
1469 .map(|(k, _)| k)
1470 .cloned()
1471 .collect::<HashSet<String>>();
1472
1473 let mut unused_keys = remapped_keys
1474 .difference(&self.generated_types)
1475 .collect::<Vec<&String>>();
1476
1477 unused_keys.sort();
1478
1479 if !unused_keys.is_empty() {
1480 bail!("unused remappings provided via `with`: {unused_keys:?}");
1481 }
1482
1483 self.opts.async_.ensure_all_used()?;
1486
1487 Ok(())
1488 }
1489}
1490
1491pub(crate) fn compute_module_path(
1492 name: &WorldKey,
1493 resolve: &Resolve,
1494 is_export: bool,
1495) -> Vec<String> {
1496 let mut path = Vec::new();
1497 if is_export {
1498 path.push("exports".to_string());
1499 }
1500 match name {
1501 WorldKey::Name(name) => {
1502 path.push(to_rust_ident(name));
1503 }
1504 WorldKey::Interface(id) => {
1505 let iface = &resolve.interfaces[*id];
1506 let pkg = iface.package.unwrap();
1507 let pkgname = resolve.packages[pkg].name.clone();
1508 path.push(to_rust_ident(&pkgname.namespace));
1509 path.push(name_package_module(resolve, pkg));
1510 path.push(to_rust_ident(iface.name.as_ref().unwrap()));
1511 }
1512 }
1513 path
1514}
1515
1516enum Identifier<'a> {
1517 World(WorldId),
1518 Interface(InterfaceId, &'a WorldKey),
1519 StreamOrFuturePayload,
1520}
1521
1522fn group_by_resource<'a>(
1523 funcs: impl Iterator<Item = &'a Function>,
1524) -> BTreeMap<Option<TypeId>, Vec<&'a Function>> {
1525 let mut by_resource = BTreeMap::<_, Vec<_>>::new();
1526 for func in funcs {
1527 by_resource
1528 .entry(func.kind.resource())
1529 .or_default()
1530 .push(func);
1531 }
1532 by_resource
1533}
1534
1535#[derive(Default, Debug, Clone, Copy)]
1536#[cfg_attr(
1537 feature = "serde",
1538 derive(serde::Deserialize),
1539 serde(rename_all = "kebab-case")
1540)]
1541pub enum Ownership {
1542 #[default]
1545 Owning,
1546
1547 Borrowing {
1551 duplicate_if_necessary: bool,
1556 },
1557}
1558
1559impl FromStr for Ownership {
1560 type Err = String;
1561
1562 fn from_str(s: &str) -> Result<Self, Self::Err> {
1563 match s {
1564 "owning" => Ok(Self::Owning),
1565 "borrowing" => Ok(Self::Borrowing {
1566 duplicate_if_necessary: false,
1567 }),
1568 "borrowing-duplicate-if-necessary" => Ok(Self::Borrowing {
1569 duplicate_if_necessary: true,
1570 }),
1571 _ => Err(format!(
1572 "unrecognized ownership: `{s}`; \
1573 expected `owning`, `borrowing`, or `borrowing-duplicate-if-necessary`"
1574 )),
1575 }
1576 }
1577}
1578
1579impl fmt::Display for Ownership {
1580 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1581 f.write_str(match self {
1582 Ownership::Owning => "owning",
1583 Ownership::Borrowing {
1584 duplicate_if_necessary: false,
1585 } => "borrowing",
1586 Ownership::Borrowing {
1587 duplicate_if_necessary: true,
1588 } => "borrowing-duplicate-if-necessary",
1589 })
1590 }
1591}
1592
1593#[derive(Debug, Clone)]
1595#[cfg_attr(
1596 feature = "serde",
1597 derive(serde::Deserialize),
1598 serde(rename_all = "kebab-case")
1599)]
1600pub enum WithOption {
1601 Path(String),
1602 Generate,
1603}
1604
1605impl std::fmt::Display for WithOption {
1606 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1607 match self {
1608 WithOption::Path(p) => f.write_fmt(format_args!("\"{p}\"")),
1609 WithOption::Generate => f.write_str("generate"),
1610 }
1611 }
1612}
1613
1614impl From<WithOption> for TypeGeneration {
1615 fn from(opt: WithOption) -> Self {
1616 match opt {
1617 WithOption::Path(p) => TypeGeneration::Remap(p),
1618 WithOption::Generate => TypeGeneration::Generate,
1619 }
1620 }
1621}
1622
1623#[derive(Default)]
1624struct FnSig {
1625 async_: bool,
1626 unsafe_: bool,
1627 private: bool,
1628 use_item_name: bool,
1629 generics: Option<String>,
1630 self_arg: Option<String>,
1631 self_is_first_param: bool,
1632}
1633
1634impl FnSig {
1635 fn update_for_func(&mut self, func: &Function) {
1636 if let FunctionKind::Method(_) | FunctionKind::AsyncMethod(_) = &func.kind {
1637 self.self_arg = Some("&self".into());
1638 self.self_is_first_param = true;
1639 }
1640 }
1641}
1642
1643pub fn to_rust_ident(name: &str) -> String {
1644 match name {
1645 "as" => "as_".into(),
1648 "break" => "break_".into(),
1649 "const" => "const_".into(),
1650 "continue" => "continue_".into(),
1651 "crate" => "crate_".into(),
1652 "else" => "else_".into(),
1653 "enum" => "enum_".into(),
1654 "extern" => "extern_".into(),
1655 "false" => "false_".into(),
1656 "fn" => "fn_".into(),
1657 "for" => "for_".into(),
1658 "if" => "if_".into(),
1659 "impl" => "impl_".into(),
1660 "in" => "in_".into(),
1661 "let" => "let_".into(),
1662 "loop" => "loop_".into(),
1663 "match" => "match_".into(),
1664 "mod" => "mod_".into(),
1665 "move" => "move_".into(),
1666 "mut" => "mut_".into(),
1667 "pub" => "pub_".into(),
1668 "ref" => "ref_".into(),
1669 "return" => "return_".into(),
1670 "self" => "self_".into(),
1671 "static" => "static_".into(),
1672 "struct" => "struct_".into(),
1673 "super" => "super_".into(),
1674 "trait" => "trait_".into(),
1675 "true" => "true_".into(),
1676 "type" => "type_".into(),
1677 "unsafe" => "unsafe_".into(),
1678 "use" => "use_".into(),
1679 "where" => "where_".into(),
1680 "while" => "while_".into(),
1681 "async" => "async_".into(),
1682 "await" => "await_".into(),
1683 "dyn" => "dyn_".into(),
1684 "abstract" => "abstract_".into(),
1685 "become" => "become_".into(),
1686 "box" => "box_".into(),
1687 "do" => "do_".into(),
1688 "final" => "final_".into(),
1689 "macro" => "macro_".into(),
1690 "override" => "override_".into(),
1691 "priv" => "priv_".into(),
1692 "typeof" => "typeof_".into(),
1693 "unsized" => "unsized_".into(),
1694 "virtual" => "virtual_".into(),
1695 "yield" => "yield_".into(),
1696 "try" => "try_".into(),
1697 s => s.to_snake_case(),
1698 }
1699}
1700
1701fn to_upper_camel_case(name: &str) -> String {
1702 match name {
1703 "guest" => "Guest_".to_string(),
1706 s => s.to_upper_camel_case(),
1707 }
1708}
1709
1710fn wasm_type(ty: WasmType) -> &'static str {
1711 match ty {
1712 WasmType::I32 => "i32",
1713 WasmType::I64 => "i64",
1714 WasmType::F32 => "f32",
1715 WasmType::F64 => "f64",
1716 WasmType::Pointer => "*mut u8",
1717 WasmType::Length => "usize",
1718
1719 WasmType::PointerOrI64 => "::core::mem::MaybeUninit::<u64>",
1725 }
1726}
1727
1728fn declare_import(
1729 wasm_import_module: &str,
1730 wasm_import_name: &str,
1731 rust_name: &str,
1732 params: &[WasmType],
1733 results: &[WasmType],
1734) -> String {
1735 let mut sig = "(".to_owned();
1736 for param in params.iter() {
1737 sig.push_str("_: ");
1738 sig.push_str(wasm_type(*param));
1739 sig.push_str(", ");
1740 }
1741 sig.push(')');
1742 assert!(results.len() < 2);
1743 for result in results.iter() {
1744 sig.push_str(" -> ");
1745 sig.push_str(wasm_type(*result));
1746 }
1747 format!(
1748 "
1749 #[cfg(target_arch = \"wasm32\")]
1750 #[link(wasm_import_module = \"{wasm_import_module}\")]
1751 unsafe extern \"C\" {{
1752 #[link_name = \"{wasm_import_name}\"]
1753 fn {rust_name}{sig};
1754 }}
1755
1756 #[cfg(not(target_arch = \"wasm32\"))]
1757 unsafe extern \"C\" fn {rust_name}{sig} {{ unreachable!() }}
1758 "
1759 )
1760}
1761
1762fn int_repr(repr: Int) -> &'static str {
1763 match repr {
1764 Int::U8 => "u8",
1765 Int::U16 => "u16",
1766 Int::U32 => "u32",
1767 Int::U64 => "u64",
1768 }
1769}
1770
1771fn bitcast(casts: &[Bitcast], operands: &[String], results: &mut Vec<String>) {
1772 for (cast, operand) in casts.iter().zip(operands) {
1773 results.push(perform_cast(operand, cast));
1774 }
1775}
1776
1777fn perform_cast(operand: &str, cast: &Bitcast) -> String {
1778 match cast {
1779 Bitcast::None => operand.to_owned(),
1780 Bitcast::I32ToI64 => format!("i64::from({operand})"),
1781 Bitcast::F32ToI32 => format!("({operand}).to_bits() as i32"),
1782 Bitcast::F64ToI64 => format!("({operand}).to_bits() as i64"),
1783 Bitcast::I64ToI32 => format!("{operand} as i32"),
1784 Bitcast::I32ToF32 => format!("f32::from_bits({operand} as u32)"),
1785 Bitcast::I64ToF64 => format!("f64::from_bits({operand} as u64)"),
1786 Bitcast::F32ToI64 => format!("i64::from(({operand}).to_bits())"),
1787 Bitcast::I64ToF32 => format!("f32::from_bits({operand} as u32)"),
1788
1789 Bitcast::I64ToP64 => format!("::core::mem::MaybeUninit::new({operand} as u64)"),
1791 Bitcast::P64ToI64 => format!("{operand}.assume_init() as i64"),
1794
1795 Bitcast::PToP64 => {
1797 format!(
1798 "{{
1799 let mut t = ::core::mem::MaybeUninit::<u64>::uninit();
1800 t.as_mut_ptr().cast::<*mut u8>().write({operand});
1801 t
1802 }}"
1803 )
1804 }
1805 Bitcast::P64ToP => {
1808 format!("{operand}.as_ptr().cast::<*mut u8>().read()")
1809 }
1810 Bitcast::I32ToP | Bitcast::LToP => {
1812 format!("{operand} as *mut u8")
1813 }
1814 Bitcast::PToI32 | Bitcast::LToI32 => {
1816 format!("{operand} as i32")
1817 }
1818 Bitcast::I32ToL | Bitcast::I64ToL | Bitcast::PToL => {
1820 format!("{operand} as usize")
1821 }
1822 Bitcast::LToI64 => {
1824 format!("{operand} as i64")
1825 }
1826 Bitcast::Sequence(sequence) => {
1827 let [first, second] = &**sequence;
1828 perform_cast(&perform_cast(operand, first), second)
1829 }
1830 }
1831}
1832
1833enum RustFlagsRepr {
1834 U8,
1835 U16,
1836 U32,
1837 U64,
1838 U128,
1839}
1840
1841impl RustFlagsRepr {
1842 fn new(f: &Flags) -> RustFlagsRepr {
1843 match f.repr() {
1844 FlagsRepr::U8 => RustFlagsRepr::U8,
1845 FlagsRepr::U16 => RustFlagsRepr::U16,
1846 FlagsRepr::U32(1) => RustFlagsRepr::U32,
1847 FlagsRepr::U32(2) => RustFlagsRepr::U64,
1848 FlagsRepr::U32(3 | 4) => RustFlagsRepr::U128,
1849 FlagsRepr::U32(n) => panic!("unsupported number of flags: {}", n * 32),
1850 }
1851 }
1852}
1853
1854impl fmt::Display for RustFlagsRepr {
1855 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1856 match self {
1857 RustFlagsRepr::U8 => "u8".fmt(f),
1858 RustFlagsRepr::U16 => "u16".fmt(f),
1859 RustFlagsRepr::U32 => "u32".fmt(f),
1860 RustFlagsRepr::U64 => "u64".fmt(f),
1861 RustFlagsRepr::U128 => "u128".fmt(f),
1862 }
1863 }
1864}
1865
1866#[derive(Debug, Clone)]
1867pub struct MissingWith(pub String);
1868
1869impl fmt::Display for MissingWith {
1870 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1871 write!(f, "missing `with` mapping for the key `{}`", self.0)
1872 }
1873}
1874
1875impl std::error::Error for MissingWith {}
1876
1877fn full_wit_type_name(resolve: &Resolve, id: TypeId) -> String {
1884 let id = dealias(resolve, id);
1885 let type_def = &resolve.types[id];
1886 let interface_name = match type_def.owner {
1887 TypeOwner::World(w) => Some(resolve.worlds[w].name.clone()),
1888 TypeOwner::Interface(id) => resolve.id_of(id),
1889 TypeOwner::None => None,
1890 };
1891 match interface_name {
1892 Some(interface_name) => format!("{}/{}", interface_name, type_def.name.clone().unwrap()),
1893 None => type_def.name.clone().unwrap(),
1894 }
1895}
1896
1897enum ConstructorReturnType {
1898 Self_,
1905
1906 Result { err: Option<Type> },
1913}
1914
1915fn classify_constructor_return_type(
1916 resolve: &Resolve,
1917 resource_id: TypeId,
1918 result: &Option<Type>,
1919) -> ConstructorReturnType {
1920 fn classify(
1921 resolve: &Resolve,
1922 resource_id: TypeId,
1923 result: &Option<Type>,
1924 ) -> Option<ConstructorReturnType> {
1925 let resource_id = dealias(resolve, resource_id);
1926 let typedef = match result.as_ref()? {
1927 Type::Id(id) => &resolve.types[dealias(resolve, *id)],
1928 _ => return None,
1929 };
1930
1931 match &typedef.kind {
1932 TypeDefKind::Handle(Handle::Own(id)) if dealias(resolve, *id) == resource_id => {
1933 Some(ConstructorReturnType::Self_)
1934 }
1935 TypeDefKind::Result(Result_ { ok, err }) => {
1936 let ok_typedef = match ok.as_ref()? {
1937 Type::Id(id) => &resolve.types[dealias(resolve, *id)],
1938 _ => return None,
1939 };
1940
1941 match &ok_typedef.kind {
1942 TypeDefKind::Handle(Handle::Own(id))
1943 if dealias(resolve, *id) == resource_id =>
1944 {
1945 Some(ConstructorReturnType::Result { err: *err })
1946 }
1947 _ => None,
1948 }
1949 }
1950 _ => None,
1951 }
1952 }
1953
1954 classify(resolve, resource_id, result).expect("invalid constructor")
1955}