1use crate::interface::InterfaceGenerator;
2use anyhow::{bail, Result};
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::str::FromStr;
10use wit_bindgen_core::abi::{Bitcast, WasmType};
11use wit_bindgen_core::{
12 dealias, name_package_module, uwrite, uwriteln, wit_parser::*, AsyncFilterSet, Files,
13 InterfaceGenerator as _, Source, Types, WorldGenerator,
14};
15
16mod bindgen;
17mod interface;
18
19struct InterfaceName {
20 remapped: bool,
23
24 path: String,
26}
27
28#[derive(Default)]
29struct RustWasm {
30 types: Types,
31 src_preamble: Source,
32 src: Source,
33 opts: Opts,
34 import_modules: Vec<(String, Vec<String>)>,
35 export_modules: Vec<(String, Vec<String>)>,
36 skip: HashSet<String>,
37 interface_names: HashMap<InterfaceId, InterfaceName>,
38 interface_last_seen_as_import: HashMap<InterfaceId, bool>,
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<String, String>,
54 stream_payloads: IndexMap<String, 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
279impl Opts {
280 pub fn build(self) -> Box<dyn WorldGenerator> {
281 let mut r = RustWasm::new();
282 r.skip = self.skip.iter().cloned().collect();
283 r.opts = self;
284 Box::new(r)
285 }
286}
287
288impl RustWasm {
289 fn new() -> RustWasm {
290 RustWasm::default()
291 }
292
293 fn interface<'a>(
294 &'a mut self,
295 identifier: Identifier<'a>,
296 wasm_import_module: &'a str,
297 resolve: &'a Resolve,
298 in_import: bool,
299 ) -> InterfaceGenerator<'a> {
300 let mut sizes = SizeAlign::default();
301 sizes.fill(resolve);
302
303 InterfaceGenerator {
304 identifier,
305 wasm_import_module,
306 src: Source::default(),
307 in_import,
308 r#gen: self,
309 sizes,
310 resolve,
311 return_pointer_area_size: Default::default(),
312 return_pointer_area_align: Default::default(),
313 needs_runtime_module: false,
314 }
315 }
316
317 fn emit_modules(&mut self, modules: Vec<(String, Vec<String>)>) {
318 #[derive(Default)]
319 struct Module {
320 submodules: BTreeMap<String, Module>,
321 contents: Vec<String>,
322 }
323 let mut map = Module::default();
324 for (module, path) in modules {
325 let mut cur = &mut map;
326 for name in path[..path.len() - 1].iter() {
327 cur = cur
328 .submodules
329 .entry(name.clone())
330 .or_insert(Module::default());
331 }
332 cur.contents.push(module);
333 }
334
335 emit(&mut self.src, map, &self.opts, true);
336 fn emit(me: &mut Source, module: Module, opts: &Opts, toplevel: bool) {
337 for (name, submodule) in module.submodules {
338 if toplevel {
339 if opts.format {
343 uwriteln!(me, "#[rustfmt::skip]");
344 }
345
346 uwriteln!(me, "#[allow(dead_code, clippy::all)]");
350 }
351
352 uwriteln!(me, "pub mod {name} {{");
353 emit(me, submodule, opts, false);
354 uwriteln!(me, "}}");
355 }
356 for submodule in module.contents {
357 uwriteln!(me, "{submodule}");
358 }
359 }
360 }
361
362 fn runtime_path(&self) -> &str {
363 self.opts
364 .runtime_path
365 .as_deref()
366 .unwrap_or("wit_bindgen::rt")
367 }
368
369 fn bitflags_path(&self) -> String {
370 self.opts
371 .bitflags_path
372 .to_owned()
373 .unwrap_or(format!("{}::bitflags", self.runtime_path()))
374 }
375
376 fn async_support_path(&self) -> String {
377 format!("{}::async_support", self.runtime_path())
378 }
379
380 fn name_interface(
381 &mut self,
382 resolve: &Resolve,
383 id: InterfaceId,
384 name: &WorldKey,
385 is_export: bool,
386 ) -> Result<bool> {
387 let with_name = resolve.name_world_key(name);
388 let remapping = if is_export {
389 &TypeGeneration::Generate
390 } else {
391 match self.with.get(&with_name) {
392 Some(remapping) => remapping,
393 None => bail!(MissingWith(with_name)),
394 }
395 };
396 self.generated_types.insert(with_name);
397 let entry = match remapping {
398 TypeGeneration::Remap(remapped_path) => {
399 let name = format!("__with_name{}", self.with_name_counter);
400 self.with_name_counter += 1;
401 uwriteln!(
402 self.src,
403 "#[allow(unfulfilled_lint_expectations, unused_imports)]"
404 );
405 uwriteln!(self.src, "use {remapped_path} as {name};");
406 InterfaceName {
407 remapped: true,
408 path: name,
409 }
410 }
411 TypeGeneration::Generate => {
412 let path = compute_module_path(name, resolve, is_export).join("::");
413
414 InterfaceName {
415 remapped: false,
416 path,
417 }
418 }
419 };
420
421 let remapped = entry.remapped;
422 self.interface_names.insert(id, entry);
423
424 Ok(remapped)
425 }
426
427 fn finish_runtime_module(&mut self) {
428 if !self.rt_module.is_empty() {
429 if self.opts.format {
431 uwriteln!(self.src, "#[rustfmt::skip]");
432 }
433
434 self.src.push_str("mod _rt {\n");
435 self.src.push_str("#![allow(dead_code, clippy::all)]\n");
436 let mut emitted = IndexSet::new();
437 while !self.rt_module.is_empty() {
438 for item in mem::take(&mut self.rt_module) {
439 if emitted.insert(item) {
440 self.emit_runtime_item(item);
441 }
442 }
443 }
444 self.src.push_str("}\n");
445 }
446
447 if !self.future_payloads.is_empty() {
448 let async_support = self.async_support_path();
449 self.src.push_str(&format!(
450 "\
451pub mod wit_future {{
452 #![allow(dead_code, unused_variables, clippy::all)]
453
454 #[doc(hidden)]
455 pub trait FuturePayload: Unpin + Sized + 'static {{
456 const VTABLE: &'static {async_support}::FutureVtable<Self>;
457 }}"
458 ));
459 for code in self.future_payloads.values() {
460 self.src.push_str(code);
461 }
462 self.src.push_str(&format!(
463 "\
464 /// Creates a new Component Model `future` with the specified payload type.
465 ///
466 /// The `default` function provided computes the default value to be sent in
467 /// this future if no other value was otherwise sent.
468 pub fn new<T: FuturePayload>(default: fn() -> T) -> ({async_support}::FutureWriter<T>, {async_support}::FutureReader<T>) {{
469 unsafe {{ {async_support}::future_new::<T>(default, T::VTABLE) }}
470 }}
471}}
472 ",
473 ));
474 }
475
476 if !self.stream_payloads.is_empty() {
477 let async_support = self.async_support_path();
478 self.src.push_str(&format!(
479 "\
480pub mod wit_stream {{
481 #![allow(dead_code, unused_variables, clippy::all)]
482
483 pub trait StreamPayload: Unpin + Sized + 'static {{
484 const VTABLE: &'static {async_support}::StreamVtable<Self>;
485 }}"
486 ));
487 for code in self.stream_payloads.values() {
488 self.src.push_str(code);
489 }
490 self.src.push_str(
491 &format!("\
492 /// Creates a new Component Model `stream` with the specified payload type.
493 pub fn new<T: StreamPayload>() -> ({async_support}::StreamWriter<T>, {async_support}::StreamReader<T>) {{
494 unsafe {{ {async_support}::stream_new::<T>(T::VTABLE) }}
495 }}
496}}
497 "),
498 );
499 }
500 }
501
502 fn emit_runtime_item(&mut self, item: RuntimeItem) {
503 match item {
504 RuntimeItem::AllocCrate => {
505 uwriteln!(self.src, "extern crate alloc as alloc_crate;");
506 }
507 RuntimeItem::StdAllocModule => {
508 self.rt_module.insert(RuntimeItem::AllocCrate);
509 uwriteln!(self.src, "pub use alloc_crate::alloc;");
510 }
511 RuntimeItem::StringType => {
512 self.rt_module.insert(RuntimeItem::AllocCrate);
513 uwriteln!(self.src, "pub use alloc_crate::string::String;");
514 }
515 RuntimeItem::BoxType => {
516 self.rt_module.insert(RuntimeItem::AllocCrate);
517 uwriteln!(self.src, "pub use alloc_crate::boxed::Box;");
518 }
519 RuntimeItem::VecType => {
520 self.rt_module.insert(RuntimeItem::AllocCrate);
521 uwriteln!(self.src, "pub use alloc_crate::vec::Vec;");
522 }
523 RuntimeItem::CabiDealloc => {
524 self.rt_module.insert(RuntimeItem::StdAllocModule);
525 self.src.push_str(
526 "\
527pub unsafe fn cabi_dealloc(ptr: *mut u8, size: usize, align: usize) {
528 if size == 0 {
529 return;
530 }
531 unsafe {
532 let layout = alloc::Layout::from_size_align_unchecked(size, align);
533 alloc::dealloc(ptr, layout);
534 }
535}
536 ",
537 );
538 }
539
540 RuntimeItem::StringLift => {
541 self.rt_module.insert(RuntimeItem::StringType);
542 self.src.push_str(
543 "\
544pub unsafe fn string_lift(bytes: Vec<u8>) -> String {
545 if cfg!(debug_assertions) {
546 String::from_utf8(bytes).unwrap()
547 } else {
548 unsafe { String::from_utf8_unchecked(bytes) }
549 }
550}
551 ",
552 );
553 }
554
555 RuntimeItem::InvalidEnumDiscriminant => {
556 self.src.push_str(
557 "\
558pub unsafe fn invalid_enum_discriminant<T>() -> T {
559 if cfg!(debug_assertions) {
560 panic!(\"invalid enum discriminant\")
561 } else {
562 unsafe { core::hint::unreachable_unchecked() }
563 }
564}
565 ",
566 );
567 }
568
569 RuntimeItem::CharLift => {
570 self.src.push_str(
571 "\
572pub unsafe fn char_lift(val: u32) -> char {
573 if cfg!(debug_assertions) {
574 core::char::from_u32(val).unwrap()
575 } else {
576 unsafe { core::char::from_u32_unchecked(val) }
577 }
578}
579 ",
580 );
581 }
582
583 RuntimeItem::BoolLift => {
584 self.src.push_str(
585 "\
586pub unsafe fn bool_lift(val: u8) -> bool {
587 if cfg!(debug_assertions) {
588 match val {
589 0 => false,
590 1 => true,
591 _ => panic!(\"invalid bool discriminant\"),
592 }
593 } else {
594 val != 0
595 }
596}
597 ",
598 );
599 }
600
601 RuntimeItem::RunCtorsOnce => {
602 let rt = self.runtime_path();
603 self.src.push_str(&format!(
604 r#"
605#[cfg(target_arch = "wasm32")]
606pub fn run_ctors_once() {{
607 {rt}::run_ctors_once();
608}}
609 "#,
610 ));
611 }
612
613 RuntimeItem::AsI32 => {
614 self.emit_runtime_as_trait(
615 "i32",
616 &["i32", "u32", "i16", "u16", "i8", "u8", "char", "usize"],
617 );
618 }
619
620 RuntimeItem::AsI64 => {
621 self.emit_runtime_as_trait("i64", &["i64", "u64"]);
622 }
623
624 RuntimeItem::AsF32 => {
625 self.emit_runtime_as_trait("f32", &["f32"]);
626 }
627
628 RuntimeItem::AsF64 => {
629 self.emit_runtime_as_trait("f64", &["f64"]);
630 }
631
632 RuntimeItem::ResourceType => {
633 self.src.push_str(
634 r#"
635
636use core::fmt;
637use core::marker;
638use core::sync::atomic::{AtomicU32, Ordering::Relaxed};
639
640/// A type which represents a component model resource, either imported or
641/// exported into this component.
642///
643/// This is a low-level wrapper which handles the lifetime of the resource
644/// (namely this has a destructor). The `T` provided defines the component model
645/// intrinsics that this wrapper uses.
646///
647/// One of the chief purposes of this type is to provide `Deref` implementations
648/// to access the underlying data when it is owned.
649///
650/// This type is primarily used in generated code for exported and imported
651/// resources.
652#[repr(transparent)]
653pub struct Resource<T: WasmResource> {
654 // NB: This would ideally be `u32` but it is not. The fact that this has
655 // interior mutability is not exposed in the API of this type except for the
656 // `take_handle` method which is supposed to in theory be private.
657 //
658 // This represents, almost all the time, a valid handle value. When it's
659 // invalid it's stored as `u32::MAX`.
660 handle: AtomicU32,
661 _marker: marker::PhantomData<T>,
662}
663
664/// A trait which all wasm resources implement, namely providing the ability to
665/// drop a resource.
666///
667/// This generally is implemented by generated code, not user-facing code.
668#[allow(clippy::missing_safety_doc)]
669pub unsafe trait WasmResource {
670 /// Invokes the `[resource-drop]...` intrinsic.
671 unsafe fn drop(handle: u32);
672}
673
674impl<T: WasmResource> Resource<T> {
675 #[doc(hidden)]
676 pub unsafe fn from_handle(handle: u32) -> Self {
677 debug_assert!(handle != 0 && handle != u32::MAX);
678 Self {
679 handle: AtomicU32::new(handle),
680 _marker: marker::PhantomData,
681 }
682 }
683
684 /// Takes ownership of the handle owned by `resource`.
685 ///
686 /// Note that this ideally would be `into_handle` taking `Resource<T>` by
687 /// ownership. The code generator does not enable that in all situations,
688 /// unfortunately, so this is provided instead.
689 ///
690 /// Also note that `take_handle` is in theory only ever called on values
691 /// owned by a generated function. For example a generated function might
692 /// take `Resource<T>` as an argument but then call `take_handle` on a
693 /// reference to that argument. In that sense the dynamic nature of
694 /// `take_handle` should only be exposed internally to generated code, not
695 /// to user code.
696 #[doc(hidden)]
697 pub fn take_handle(resource: &Resource<T>) -> u32 {
698 resource.handle.swap(u32::MAX, Relaxed)
699 }
700
701 #[doc(hidden)]
702 pub fn handle(resource: &Resource<T>) -> u32 {
703 resource.handle.load(Relaxed)
704 }
705}
706
707impl<T: WasmResource> fmt::Debug for Resource<T> {
708 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
709 f.debug_struct("Resource")
710 .field("handle", &self.handle)
711 .finish()
712 }
713}
714
715impl<T: WasmResource> Drop for Resource<T> {
716 fn drop(&mut self) {
717 unsafe {
718 match self.handle.load(Relaxed) {
719 // If this handle was "taken" then don't do anything in the
720 // destructor.
721 u32::MAX => {}
722
723 // ... but otherwise do actually destroy it with the imported
724 // component model intrinsic as defined through `T`.
725 other => T::drop(other),
726 }
727 }
728 }
729}
730 "#,
731 );
732 }
733 }
734 }
735
736 fn emit_runtime_as_trait(&mut self, ty: &str, to_convert: &[&str]) {
741 let upcase = ty.to_uppercase();
742 self.src.push_str(&format!(
743 r#"
744pub fn as_{ty}<T: As{upcase}>(t: T) -> {ty} {{
745 t.as_{ty}()
746}}
747
748pub trait As{upcase} {{
749 fn as_{ty}(self) -> {ty};
750}}
751
752impl<'a, T: Copy + As{upcase}> As{upcase} for &'a T {{
753 fn as_{ty}(self) -> {ty} {{
754 (*self).as_{ty}()
755 }}
756}}
757 "#
758 ));
759
760 for to_convert in to_convert {
761 self.src.push_str(&format!(
762 r#"
763impl As{upcase} for {to_convert} {{
764 #[inline]
765 fn as_{ty}(self) -> {ty} {{
766 self as {ty}
767 }}
768}}
769 "#
770 ));
771 }
772 }
773
774 fn finish_export_macro(&mut self, resolve: &Resolve, world_id: WorldId) {
780 if self.export_macros.is_empty() {
781 return;
782 }
783 let world = &resolve.worlds[world_id];
784 let world_name = world.name.to_snake_case();
785
786 let default_bindings_module = self
787 .opts
788 .default_bindings_module
789 .clone()
790 .unwrap_or("self".to_string());
791 let (macro_export, use_vis) = if self.opts.pub_export_macro {
792 ("#[macro_export]", "pub")
793 } else {
794 ("", "pub(crate)")
795 };
796 let export_macro_name = self
797 .opts
798 .export_macro_name
799 .as_deref()
800 .unwrap_or("export")
801 .to_string();
802 uwriteln!(
803 self.src,
804 r#"
805/// Generates `#[unsafe(no_mangle)]` functions to export the specified type as
806/// the root implementation of all generated traits.
807///
808/// For more information see the documentation of `wit_bindgen::generate!`.
809///
810/// ```rust
811/// # macro_rules! {export_macro_name} {{ ($($t:tt)*) => (); }}
812/// # trait Guest {{}}
813/// struct MyType;
814///
815/// impl Guest for MyType {{
816/// // ...
817/// }}
818///
819/// {export_macro_name}!(MyType);
820/// ```
821#[allow(unused_macros)]
822#[doc(hidden)]
823{macro_export}
824macro_rules! __export_{world_name}_impl {{
825 ($ty:ident) => ({default_bindings_module}::{export_macro_name}!($ty with_types_in {default_bindings_module}););
826 ($ty:ident with_types_in $($path_to_types_root:tt)*) => ("#
827 );
828 for (name, path_to_types) in self.export_macros.iter() {
829 let mut path = "$($path_to_types_root)*".to_string();
830 if !path_to_types.is_empty() {
831 path.push_str("::");
832 path.push_str(path_to_types)
833 }
834 uwriteln!(self.src, "{path}::{name}!($ty with_types_in {path});");
835 }
836
837 if self.opts.pub_export_macro {
839 uwriteln!(self.src, "const _: () = {{");
840 self.emit_custom_section(resolve, world_id, "imports and exports", None);
841 uwriteln!(self.src, "}};");
842 }
843
844 uwriteln!(self.src, ")\n}}");
845
846 uwriteln!(
847 self.src,
848 "#[doc(inline)]\n\
849 {use_vis} use __export_{world_name}_impl as {export_macro_name};"
850 );
851
852 if self.opts.stubs {
853 uwriteln!(self.src, "export!(Stub);");
854 }
855 }
856
857 fn emit_custom_section(
868 &mut self,
869 resolve: &Resolve,
870 world_id: WorldId,
871 section_suffix: &str,
872 func_name: Option<&str>,
873 ) {
874 if self.opts.format {
876 uwriteln!(self.src, "#[rustfmt::skip]");
877 }
878 self.src.push_str("\n#[cfg(target_arch = \"wasm32\")]\n");
879
880 let opts_suffix = self.opts.type_section_suffix.as_deref().unwrap_or("");
885 let world = &resolve.worlds[world_id];
886 let world_name = &world.name;
887 let pkg = &resolve.packages[world.package.unwrap()].name;
888 let version = env!("CARGO_PKG_VERSION");
889 self.src.push_str(&format!(
890 "#[unsafe(link_section = \"component-type:wit-bindgen:{version}:\
891 {pkg}:{world_name}:{section_suffix}{opts_suffix}\")]\n"
892 ));
893
894 let mut producers = wasm_metadata::Producers::empty();
895 producers.add(
896 "processed-by",
897 env!("CARGO_PKG_NAME"),
898 env!("CARGO_PKG_VERSION"),
899 );
900
901 let component_type = wit_component::metadata::encode(
902 resolve,
903 world_id,
904 wit_component::StringEncoding::UTF8,
905 Some(&producers),
906 )
907 .unwrap();
908
909 self.src.push_str("#[doc(hidden)]\n");
910 self.src.push_str("#[allow(clippy::octal_escapes)]\n");
911 self.src.push_str(&format!(
912 "pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; {}] = *b\"\\\n",
913 component_type.len()
914 ));
915 let old_indent = self.src.set_indent(0);
916 let mut line_length = 0;
917 let s = self.src.as_mut_string();
918 for byte in component_type.iter() {
919 if line_length >= 80 {
920 s.push_str("\\\n");
921 line_length = 0;
922 }
923 match byte {
924 b'\\' => {
925 s.push_str("\\\\");
926 line_length += 2;
927 }
928 b'"' => {
929 s.push_str("\\\"");
930 line_length += 2;
931 }
932 b if b.is_ascii_alphanumeric() || b.is_ascii_punctuation() => {
933 s.push(char::from(*byte));
934 line_length += 1;
935 }
936 0 => {
937 s.push_str("\\0");
938 line_length += 2;
939 }
940 _ => {
941 uwrite!(s, "\\x{:02x}", byte);
942 line_length += 4;
943 }
944 }
945 }
946
947 self.src.push_str("\";\n");
948 self.src.set_indent(old_indent);
949
950 if let Some(func_name) = func_name {
951 let rt = self.runtime_path().to_string();
952 uwriteln!(
953 self.src,
954 "
955 #[inline(never)]
956 #[doc(hidden)]
957 pub fn {func_name}() {{
958 {rt}::maybe_link_cabi_realloc();
959 }}
960 ",
961 );
962 }
963 }
964
965 fn is_async(
966 &mut self,
967 resolve: &Resolve,
968 interface: Option<&WorldKey>,
969 func: &Function,
970 is_import: bool,
971 ) -> bool {
972 self.opts
973 .async_
974 .is_async(resolve, interface, func, is_import)
975 }
976}
977
978impl WorldGenerator for RustWasm {
979 fn preprocess(&mut self, resolve: &Resolve, world: WorldId) {
980 wit_bindgen_core::generated_preamble(&mut self.src_preamble, env!("CARGO_PKG_VERSION"));
981
982 uwriteln!(self.src_preamble, "// Options used:");
985 if self.opts.std_feature {
986 uwriteln!(self.src_preamble, "// * std_feature");
987 }
988 if self.opts.raw_strings {
989 uwriteln!(self.src_preamble, "// * raw_strings");
990 }
991 if !self.opts.skip.is_empty() {
992 uwriteln!(self.src_preamble, "// * skip: {:?}", self.opts.skip);
993 }
994 if self.opts.stubs {
995 uwriteln!(self.src_preamble, "// * stubs");
996 }
997 if let Some(export_prefix) = &self.opts.export_prefix {
998 uwriteln!(
999 self.src_preamble,
1000 "// * export_prefix: {:?}",
1001 export_prefix
1002 );
1003 }
1004 if let Some(runtime_path) = &self.opts.runtime_path {
1005 uwriteln!(self.src_preamble, "// * runtime_path: {:?}", runtime_path);
1006 }
1007 if let Some(bitflags_path) = &self.opts.bitflags_path {
1008 uwriteln!(
1009 self.src_preamble,
1010 "// * bitflags_path: {:?}",
1011 bitflags_path
1012 );
1013 }
1014 if !matches!(self.opts.ownership, Ownership::Owning) {
1015 uwriteln!(
1016 self.src_preamble,
1017 "// * ownership: {:?}",
1018 self.opts.ownership
1019 );
1020 }
1021 if !self.opts.additional_derive_attributes.is_empty() {
1022 uwriteln!(
1023 self.src_preamble,
1024 "// * additional derives {:?}",
1025 self.opts.additional_derive_attributes
1026 );
1027 }
1028 if !self.opts.additional_derive_ignore.is_empty() {
1029 uwriteln!(
1030 self.src_preamble,
1031 "// * additional derives ignored {:?}",
1032 self.opts.additional_derive_ignore
1033 );
1034 }
1035 for (k, v) in self.opts.with.iter() {
1036 uwriteln!(self.src_preamble, "// * with {k:?} = {v}");
1037 }
1038 if let Some(type_section_suffix) = &self.opts.type_section_suffix {
1039 uwriteln!(
1040 self.src_preamble,
1041 "// * type_section_suffix: {:?}",
1042 type_section_suffix
1043 );
1044 }
1045 if let Some(default) = &self.opts.default_bindings_module {
1046 uwriteln!(
1047 self.src_preamble,
1048 "// * default-bindings-module: {default:?}"
1049 );
1050 }
1051 if self.opts.disable_run_ctors_once_workaround {
1052 uwriteln!(
1053 self.src_preamble,
1054 "// * disable-run-ctors-once-workaround"
1055 );
1056 }
1057 if let Some(s) = &self.opts.export_macro_name {
1058 uwriteln!(self.src_preamble, "// * export-macro-name: {s}");
1059 }
1060 if self.opts.pub_export_macro {
1061 uwriteln!(self.src_preamble, "// * pub-export-macro");
1062 }
1063 if self.opts.generate_unused_types {
1064 uwriteln!(self.src_preamble, "// * generate_unused_types");
1065 }
1066 if self.opts.disable_custom_section_link_helpers {
1067 uwriteln!(
1068 self.src_preamble,
1069 "// * disable_custom_section_link_helpers"
1070 );
1071 }
1072 for opt in self.opts.async_.debug_opts() {
1073 uwriteln!(self.src_preamble, "// * async: {opt}");
1074 }
1075 self.types.analyze(resolve);
1076 self.world = Some(world);
1077
1078 let world = &resolve.worlds[world];
1079 for (key, item) in world.imports.iter() {
1082 if let WorldItem::Interface { id, .. } = item {
1083 if resolve.interfaces[*id].package == world.package {
1084 let name = resolve.name_world_key(key);
1085 if self.with.get(&name).is_none() {
1086 self.with.insert(name, TypeGeneration::Generate);
1087 }
1088 }
1089 }
1090 }
1091
1092 for (k, v) in self.opts.with.iter() {
1093 self.with.insert(k.clone(), v.clone().into());
1094 }
1095 self.with.generate_by_default = self.opts.generate_all;
1096 }
1097
1098 fn import_interface(
1099 &mut self,
1100 resolve: &Resolve,
1101 name: &WorldKey,
1102 id: InterfaceId,
1103 _files: &mut Files,
1104 ) -> Result<()> {
1105 let mut to_define = Vec::new();
1106 for (name, ty_id) in resolve.interfaces[id].types.iter() {
1107 let full_name = full_wit_type_name(resolve, *ty_id);
1108 if let Some(type_gen) = self.with.get(&full_name) {
1109 if type_gen.generated() {
1111 to_define.push((name, ty_id));
1112 }
1113 } else {
1114 to_define.push((name, ty_id));
1115 }
1116 self.generated_types.insert(full_name);
1117 }
1118
1119 self.interface_last_seen_as_import.insert(id, true);
1120 let wasm_import_module = resolve.name_world_key(name);
1121 let mut r#gen = self.interface(
1122 Identifier::Interface(id, name),
1123 &wasm_import_module,
1124 resolve,
1125 true,
1126 );
1127 let (snake, module_path) = r#gen.start_append_submodule(name);
1128 if r#gen.r#gen.name_interface(resolve, id, name, false)? {
1129 return Ok(());
1130 }
1131
1132 for (name, ty_id) in to_define {
1133 r#gen.define_type(&name, *ty_id);
1134 }
1135
1136 r#gen.generate_imports(resolve.interfaces[id].functions.values(), Some(name));
1137
1138 let docs = &resolve.interfaces[id].docs;
1139
1140 r#gen.finish_append_submodule(&snake, module_path, docs);
1141
1142 Ok(())
1143 }
1144
1145 fn import_funcs(
1146 &mut self,
1147 resolve: &Resolve,
1148 world: WorldId,
1149 funcs: &[(&str, &Function)],
1150 _files: &mut Files,
1151 ) {
1152 self.import_funcs_called = true;
1153
1154 let mut r#gen = self.interface(Identifier::World(world), "$root", resolve, true);
1155
1156 r#gen.generate_imports(funcs.iter().map(|(_, func)| *func), None);
1157
1158 let src = r#gen.finish();
1159 self.src.push_str(&src);
1160 }
1161
1162 fn export_interface(
1163 &mut self,
1164 resolve: &Resolve,
1165 name: &WorldKey,
1166 id: InterfaceId,
1167 _files: &mut Files,
1168 ) -> Result<()> {
1169 let mut to_define = Vec::new();
1170 for (name, ty_id) in resolve.interfaces[id].types.iter() {
1171 let full_name = full_wit_type_name(resolve, *ty_id);
1172 to_define.push((name, ty_id));
1173 self.generated_types.insert(full_name);
1174 }
1175
1176 self.interface_last_seen_as_import.insert(id, false);
1177 let wasm_import_module = format!("[export]{}", resolve.name_world_key(name));
1178 let mut r#gen = self.interface(
1179 Identifier::Interface(id, name),
1180 &wasm_import_module,
1181 resolve,
1182 false,
1183 );
1184 let (snake, module_path) = r#gen.start_append_submodule(name);
1185 if r#gen.r#gen.name_interface(resolve, id, name, true)? {
1186 return Ok(());
1187 }
1188
1189 for (name, ty_id) in to_define {
1190 r#gen.define_type(&name, *ty_id);
1191 }
1192
1193 let macro_name =
1194 r#gen.generate_exports(Some((id, name)), resolve.interfaces[id].functions.values())?;
1195
1196 let docs = &resolve.interfaces[id].docs;
1197
1198 r#gen.finish_append_submodule(&snake, module_path, docs);
1199 self.export_macros
1200 .push((macro_name, self.interface_names[&id].path.clone()));
1201
1202 if self.opts.stubs {
1203 let world_id = self.world.unwrap();
1204 let mut r#gen = self.interface(
1205 Identifier::World(world_id),
1206 &wasm_import_module,
1207 resolve,
1208 false,
1209 );
1210 r#gen.generate_stub(Some((id, name)), resolve.interfaces[id].functions.values());
1211 let stub = r#gen.finish();
1212 self.src.push_str(&stub);
1213 }
1214 Ok(())
1215 }
1216
1217 fn export_funcs(
1218 &mut self,
1219 resolve: &Resolve,
1220 world: WorldId,
1221 funcs: &[(&str, &Function)],
1222 _files: &mut Files,
1223 ) -> Result<()> {
1224 let mut r#gen = self.interface(Identifier::World(world), "[export]$root", resolve, false);
1225 let macro_name = r#gen.generate_exports(None, funcs.iter().map(|f| f.1))?;
1226 let src = r#gen.finish();
1227 self.src.push_str(&src);
1228 self.export_macros.push((macro_name, String::new()));
1229
1230 if self.opts.stubs {
1231 let mut r#gen =
1232 self.interface(Identifier::World(world), "[export]$root", resolve, false);
1233 r#gen.generate_stub(None, funcs.iter().map(|f| f.1));
1234 let stub = r#gen.finish();
1235 self.src.push_str(&stub);
1236 }
1237 Ok(())
1238 }
1239
1240 fn import_types(
1241 &mut self,
1242 resolve: &Resolve,
1243 world: WorldId,
1244 types: &[(&str, TypeId)],
1245 _files: &mut Files,
1246 ) {
1247 let mut to_define = Vec::new();
1248 for (name, ty_id) in types {
1249 let full_name = full_wit_type_name(resolve, *ty_id);
1250 if let Some(type_gen) = self.with.get(&full_name) {
1251 if type_gen.generated() {
1253 to_define.push((name, ty_id));
1254 }
1255 } else {
1256 to_define.push((name, ty_id));
1257 }
1258 self.generated_types.insert(full_name);
1259 }
1260 let mut r#gen = self.interface(Identifier::World(world), "$root", resolve, true);
1261 for (name, ty) in to_define {
1262 r#gen.define_type(name, *ty);
1263 }
1264 let src = r#gen.finish();
1265 self.src.push_str(&src);
1266 }
1267
1268 fn finish_imports(&mut self, resolve: &Resolve, world: WorldId, files: &mut Files) {
1269 if !self.import_funcs_called {
1270 self.import_funcs(resolve, world, &[], files);
1274 }
1275 }
1276
1277 fn finish(&mut self, resolve: &Resolve, world: WorldId, files: &mut Files) -> Result<()> {
1278 let name = &resolve.worlds[world].name;
1279
1280 let imports = mem::take(&mut self.import_modules);
1281 self.emit_modules(imports);
1282 let exports = mem::take(&mut self.export_modules);
1283 self.emit_modules(exports);
1284
1285 self.finish_runtime_module();
1286 self.finish_export_macro(resolve, world);
1287
1288 let mut resolve_copy;
1327 let (resolve_to_encode, world_to_encode) = if self.opts.pub_export_macro {
1328 resolve_copy = resolve.clone();
1329 let world_copy = resolve_copy.worlds.alloc(World {
1330 exports: Default::default(),
1331 name: format!("{name}-with-all-of-its-exports-removed"),
1332 ..resolve.worlds[world].clone()
1333 });
1334 (&resolve_copy, world_copy)
1335 } else {
1336 (resolve, world)
1337 };
1338 self.emit_custom_section(
1339 resolve_to_encode,
1340 world_to_encode,
1341 "encoded world",
1342 if self.opts.disable_custom_section_link_helpers {
1343 None
1344 } else {
1345 Some("__link_custom_section_describing_imports")
1346 },
1347 );
1348
1349 if self.opts.stubs {
1350 self.src.push_str("\n#[derive(Debug)]\npub struct Stub;\n");
1351 }
1352
1353 let mut src = mem::take(&mut self.src);
1354 if self.opts.format {
1355 let syntax_tree = syn::parse_file(src.as_str()).unwrap();
1356 *src.as_mut_string() = prettyplease::unparse(&syntax_tree);
1357 }
1358
1359 let src_preamble = mem::take(&mut self.src_preamble);
1362 *src.as_mut_string() = format!("{}{}", src_preamble.as_str(), src.as_str());
1363
1364 let module_name = name.to_snake_case();
1365 files.push(&format!("{module_name}.rs"), src.as_bytes());
1366
1367 let remapped_keys = self
1368 .with
1369 .iter()
1370 .map(|(k, _)| k)
1371 .cloned()
1372 .collect::<HashSet<String>>();
1373
1374 let mut unused_keys = remapped_keys
1375 .difference(&self.generated_types)
1376 .collect::<Vec<&String>>();
1377
1378 unused_keys.sort();
1379
1380 if !unused_keys.is_empty() {
1381 bail!("unused remappings provided via `with`: {unused_keys:?}");
1382 }
1383
1384 self.opts.async_.ensure_all_used()?;
1387
1388 Ok(())
1389 }
1390}
1391
1392fn compute_module_path(name: &WorldKey, resolve: &Resolve, is_export: bool) -> Vec<String> {
1393 let mut path = Vec::new();
1394 if is_export {
1395 path.push("exports".to_string());
1396 }
1397 match name {
1398 WorldKey::Name(name) => {
1399 path.push(to_rust_ident(name));
1400 }
1401 WorldKey::Interface(id) => {
1402 let iface = &resolve.interfaces[*id];
1403 let pkg = iface.package.unwrap();
1404 let pkgname = resolve.packages[pkg].name.clone();
1405 path.push(to_rust_ident(&pkgname.namespace));
1406 path.push(name_package_module(resolve, pkg));
1407 path.push(to_rust_ident(iface.name.as_ref().unwrap()));
1408 }
1409 }
1410 path
1411}
1412
1413enum Identifier<'a> {
1414 World(WorldId),
1415 Interface(InterfaceId, &'a WorldKey),
1416 StreamOrFuturePayload,
1417}
1418
1419fn group_by_resource<'a>(
1420 funcs: impl Iterator<Item = &'a Function>,
1421) -> BTreeMap<Option<TypeId>, Vec<&'a Function>> {
1422 let mut by_resource = BTreeMap::<_, Vec<_>>::new();
1423 for func in funcs {
1424 by_resource
1425 .entry(func.kind.resource())
1426 .or_default()
1427 .push(func);
1428 }
1429 by_resource
1430}
1431
1432#[derive(Default, Debug, Clone, Copy)]
1433#[cfg_attr(
1434 feature = "serde",
1435 derive(serde::Deserialize),
1436 serde(rename_all = "kebab-case")
1437)]
1438pub enum Ownership {
1439 #[default]
1442 Owning,
1443
1444 Borrowing {
1448 duplicate_if_necessary: bool,
1453 },
1454}
1455
1456impl FromStr for Ownership {
1457 type Err = String;
1458
1459 fn from_str(s: &str) -> Result<Self, Self::Err> {
1460 match s {
1461 "owning" => Ok(Self::Owning),
1462 "borrowing" => Ok(Self::Borrowing {
1463 duplicate_if_necessary: false,
1464 }),
1465 "borrowing-duplicate-if-necessary" => Ok(Self::Borrowing {
1466 duplicate_if_necessary: true,
1467 }),
1468 _ => Err(format!(
1469 "unrecognized ownership: `{s}`; \
1470 expected `owning`, `borrowing`, or `borrowing-duplicate-if-necessary`"
1471 )),
1472 }
1473 }
1474}
1475
1476impl fmt::Display for Ownership {
1477 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1478 f.write_str(match self {
1479 Ownership::Owning => "owning",
1480 Ownership::Borrowing {
1481 duplicate_if_necessary: false,
1482 } => "borrowing",
1483 Ownership::Borrowing {
1484 duplicate_if_necessary: true,
1485 } => "borrowing-duplicate-if-necessary",
1486 })
1487 }
1488}
1489
1490#[derive(Debug, Clone)]
1492#[cfg_attr(
1493 feature = "serde",
1494 derive(serde::Deserialize),
1495 serde(rename_all = "kebab-case")
1496)]
1497pub enum WithOption {
1498 Path(String),
1499 Generate,
1500}
1501
1502impl std::fmt::Display for WithOption {
1503 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1504 match self {
1505 WithOption::Path(p) => f.write_fmt(format_args!("\"{p}\"")),
1506 WithOption::Generate => f.write_str("generate"),
1507 }
1508 }
1509}
1510
1511impl From<WithOption> for TypeGeneration {
1512 fn from(opt: WithOption) -> Self {
1513 match opt {
1514 WithOption::Path(p) => TypeGeneration::Remap(p),
1515 WithOption::Generate => TypeGeneration::Generate,
1516 }
1517 }
1518}
1519
1520#[derive(Default)]
1521struct FnSig {
1522 async_: bool,
1523 unsafe_: bool,
1524 private: bool,
1525 use_item_name: bool,
1526 generics: Option<String>,
1527 self_arg: Option<String>,
1528 self_is_first_param: bool,
1529}
1530
1531impl FnSig {
1532 fn update_for_func(&mut self, func: &Function) {
1533 if let FunctionKind::Method(_) | FunctionKind::AsyncMethod(_) = &func.kind {
1534 self.self_arg = Some("&self".into());
1535 self.self_is_first_param = true;
1536 }
1537 }
1538}
1539
1540pub fn to_rust_ident(name: &str) -> String {
1541 match name {
1542 "as" => "as_".into(),
1545 "break" => "break_".into(),
1546 "const" => "const_".into(),
1547 "continue" => "continue_".into(),
1548 "crate" => "crate_".into(),
1549 "else" => "else_".into(),
1550 "enum" => "enum_".into(),
1551 "extern" => "extern_".into(),
1552 "false" => "false_".into(),
1553 "fn" => "fn_".into(),
1554 "for" => "for_".into(),
1555 "if" => "if_".into(),
1556 "impl" => "impl_".into(),
1557 "in" => "in_".into(),
1558 "let" => "let_".into(),
1559 "loop" => "loop_".into(),
1560 "match" => "match_".into(),
1561 "mod" => "mod_".into(),
1562 "move" => "move_".into(),
1563 "mut" => "mut_".into(),
1564 "pub" => "pub_".into(),
1565 "ref" => "ref_".into(),
1566 "return" => "return_".into(),
1567 "self" => "self_".into(),
1568 "static" => "static_".into(),
1569 "struct" => "struct_".into(),
1570 "super" => "super_".into(),
1571 "trait" => "trait_".into(),
1572 "true" => "true_".into(),
1573 "type" => "type_".into(),
1574 "unsafe" => "unsafe_".into(),
1575 "use" => "use_".into(),
1576 "where" => "where_".into(),
1577 "while" => "while_".into(),
1578 "async" => "async_".into(),
1579 "await" => "await_".into(),
1580 "dyn" => "dyn_".into(),
1581 "abstract" => "abstract_".into(),
1582 "become" => "become_".into(),
1583 "box" => "box_".into(),
1584 "do" => "do_".into(),
1585 "final" => "final_".into(),
1586 "macro" => "macro_".into(),
1587 "override" => "override_".into(),
1588 "priv" => "priv_".into(),
1589 "typeof" => "typeof_".into(),
1590 "unsized" => "unsized_".into(),
1591 "virtual" => "virtual_".into(),
1592 "yield" => "yield_".into(),
1593 "try" => "try_".into(),
1594 s => s.to_snake_case(),
1595 }
1596}
1597
1598fn to_upper_camel_case(name: &str) -> String {
1599 match name {
1600 "guest" => "Guest_".to_string(),
1603 s => s.to_upper_camel_case(),
1604 }
1605}
1606
1607fn wasm_type(ty: WasmType) -> &'static str {
1608 match ty {
1609 WasmType::I32 => "i32",
1610 WasmType::I64 => "i64",
1611 WasmType::F32 => "f32",
1612 WasmType::F64 => "f64",
1613 WasmType::Pointer => "*mut u8",
1614 WasmType::Length => "usize",
1615
1616 WasmType::PointerOrI64 => "::core::mem::MaybeUninit::<u64>",
1622 }
1623}
1624
1625fn declare_import(
1626 wasm_import_module: &str,
1627 wasm_import_name: &str,
1628 rust_name: &str,
1629 params: &[WasmType],
1630 results: &[WasmType],
1631) -> String {
1632 let mut sig = "(".to_owned();
1633 for param in params.iter() {
1634 sig.push_str("_: ");
1635 sig.push_str(wasm_type(*param));
1636 sig.push_str(", ");
1637 }
1638 sig.push(')');
1639 assert!(results.len() < 2);
1640 for result in results.iter() {
1641 sig.push_str(" -> ");
1642 sig.push_str(wasm_type(*result));
1643 }
1644 format!(
1645 "
1646 #[cfg(target_arch = \"wasm32\")]
1647 #[link(wasm_import_module = \"{wasm_import_module}\")]
1648 unsafe extern \"C\" {{
1649 #[link_name = \"{wasm_import_name}\"]
1650 fn {rust_name}{sig};
1651 }}
1652
1653 #[cfg(not(target_arch = \"wasm32\"))]
1654 unsafe extern \"C\" fn {rust_name}{sig} {{ unreachable!() }}
1655 "
1656 )
1657}
1658
1659fn int_repr(repr: Int) -> &'static str {
1660 match repr {
1661 Int::U8 => "u8",
1662 Int::U16 => "u16",
1663 Int::U32 => "u32",
1664 Int::U64 => "u64",
1665 }
1666}
1667
1668fn bitcast(casts: &[Bitcast], operands: &[String], results: &mut Vec<String>) {
1669 for (cast, operand) in casts.iter().zip(operands) {
1670 results.push(perform_cast(operand, cast));
1671 }
1672}
1673
1674fn perform_cast(operand: &str, cast: &Bitcast) -> String {
1675 match cast {
1676 Bitcast::None => operand.to_owned(),
1677 Bitcast::I32ToI64 => format!("i64::from({})", operand),
1678 Bitcast::F32ToI32 => format!("({}).to_bits() as i32", operand),
1679 Bitcast::F64ToI64 => format!("({}).to_bits() as i64", operand),
1680 Bitcast::I64ToI32 => format!("{} as i32", operand),
1681 Bitcast::I32ToF32 => format!("f32::from_bits({} as u32)", operand),
1682 Bitcast::I64ToF64 => format!("f64::from_bits({} as u64)", operand),
1683 Bitcast::F32ToI64 => format!("i64::from(({}).to_bits())", operand),
1684 Bitcast::I64ToF32 => format!("f32::from_bits({} as u32)", operand),
1685
1686 Bitcast::I64ToP64 => format!("::core::mem::MaybeUninit::new({} as u64)", operand),
1688 Bitcast::P64ToI64 => format!("{}.assume_init() as i64", operand),
1691
1692 Bitcast::PToP64 => {
1694 format!(
1695 "{{
1696 let mut t = ::core::mem::MaybeUninit::<u64>::uninit();
1697 t.as_mut_ptr().cast::<*mut u8>().write({});
1698 t
1699 }}",
1700 operand
1701 )
1702 }
1703 Bitcast::P64ToP => {
1706 format!("{}.as_ptr().cast::<*mut u8>().read()", operand)
1707 }
1708 Bitcast::I32ToP | Bitcast::LToP => {
1710 format!("{} as *mut u8", operand)
1711 }
1712 Bitcast::PToI32 | Bitcast::LToI32 => {
1714 format!("{} as i32", operand)
1715 }
1716 Bitcast::I32ToL | Bitcast::I64ToL | Bitcast::PToL => {
1718 format!("{} as usize", operand)
1719 }
1720 Bitcast::LToI64 => {
1722 format!("{} as i64", operand)
1723 }
1724 Bitcast::Sequence(sequence) => {
1725 let [first, second] = &**sequence;
1726 perform_cast(&perform_cast(operand, first), second)
1727 }
1728 }
1729}
1730
1731enum RustFlagsRepr {
1732 U8,
1733 U16,
1734 U32,
1735 U64,
1736 U128,
1737}
1738
1739impl RustFlagsRepr {
1740 fn new(f: &Flags) -> RustFlagsRepr {
1741 match f.repr() {
1742 FlagsRepr::U8 => RustFlagsRepr::U8,
1743 FlagsRepr::U16 => RustFlagsRepr::U16,
1744 FlagsRepr::U32(1) => RustFlagsRepr::U32,
1745 FlagsRepr::U32(2) => RustFlagsRepr::U64,
1746 FlagsRepr::U32(3 | 4) => RustFlagsRepr::U128,
1747 FlagsRepr::U32(n) => panic!("unsupported number of flags: {}", n * 32),
1748 }
1749 }
1750}
1751
1752impl fmt::Display for RustFlagsRepr {
1753 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1754 match self {
1755 RustFlagsRepr::U8 => "u8".fmt(f),
1756 RustFlagsRepr::U16 => "u16".fmt(f),
1757 RustFlagsRepr::U32 => "u32".fmt(f),
1758 RustFlagsRepr::U64 => "u64".fmt(f),
1759 RustFlagsRepr::U128 => "u128".fmt(f),
1760 }
1761 }
1762}
1763
1764#[derive(Debug, Clone)]
1765pub struct MissingWith(pub String);
1766
1767impl fmt::Display for MissingWith {
1768 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1769 write!(f, "missing `with` mapping for the key `{}`", self.0)
1770 }
1771}
1772
1773impl std::error::Error for MissingWith {}
1774
1775fn full_wit_type_name(resolve: &Resolve, id: TypeId) -> String {
1782 let id = dealias(resolve, id);
1783 let type_def = &resolve.types[id];
1784 let interface_name = match type_def.owner {
1785 TypeOwner::World(w) => Some(resolve.worlds[w].name.clone()),
1786 TypeOwner::Interface(id) => resolve.id_of(id),
1787 TypeOwner::None => None,
1788 };
1789 match interface_name {
1790 Some(interface_name) => format!("{}/{}", interface_name, type_def.name.clone().unwrap()),
1791 None => type_def.name.clone().unwrap(),
1792 }
1793}
1794
1795enum ConstructorReturnType {
1796 Self_,
1803
1804 Result { err: Option<Type> },
1811}
1812
1813fn classify_constructor_return_type(
1814 resolve: &Resolve,
1815 resource_id: TypeId,
1816 result: &Option<Type>,
1817) -> ConstructorReturnType {
1818 fn classify(
1819 resolve: &Resolve,
1820 resource_id: TypeId,
1821 result: &Option<Type>,
1822 ) -> Option<ConstructorReturnType> {
1823 let resource_id = dealias(resolve, resource_id);
1824 let typedef = match result.as_ref()? {
1825 Type::Id(id) => &resolve.types[dealias(resolve, *id)],
1826 _ => return None,
1827 };
1828
1829 match &typedef.kind {
1830 TypeDefKind::Handle(Handle::Own(id)) if dealias(resolve, *id) == resource_id => {
1831 Some(ConstructorReturnType::Self_)
1832 }
1833 TypeDefKind::Result(Result_ { ok, err }) => {
1834 let ok_typedef = match ok.as_ref()? {
1835 Type::Id(id) => &resolve.types[dealias(resolve, *id)],
1836 _ => return None,
1837 };
1838
1839 match &ok_typedef.kind {
1840 TypeDefKind::Handle(Handle::Own(id))
1841 if dealias(resolve, *id) == resource_id =>
1842 {
1843 Some(ConstructorReturnType::Result { err: *err })
1844 }
1845 _ => None,
1846 }
1847 }
1848 _ => None,
1849 }
1850 }
1851
1852 classify(resolve, resource_id, result).expect("invalid constructor")
1853}