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