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 = ','))]
230 pub with: Vec<(String, WithOption)>,
231
232 #[cfg_attr(feature = "clap", arg(long))]
235 pub generate_all: bool,
236
237 #[cfg_attr(feature = "clap", arg(long, value_name = "STRING"))]
240 pub type_section_suffix: Option<String>,
241
242 #[cfg_attr(feature = "clap", arg(long))]
245 pub disable_run_ctors_once_workaround: bool,
246
247 #[cfg_attr(feature = "clap", arg(long, value_name = "NAME"))]
250 pub default_bindings_module: Option<String>,
251
252 #[cfg_attr(feature = "clap", arg(long, value_name = "NAME"))]
254 pub export_macro_name: Option<String>,
255
256 #[cfg_attr(feature = "clap", arg(long))]
259 pub pub_export_macro: bool,
260
261 #[cfg_attr(feature = "clap", arg(long))]
263 pub generate_unused_types: bool,
264
265 #[cfg_attr(feature = "clap", arg(long))]
271 pub disable_custom_section_link_helpers: bool,
272
273 #[cfg_attr(feature = "clap", clap(flatten))]
274 #[cfg_attr(feature = "serde", serde(flatten))]
275 pub async_: AsyncFilterSet,
276}
277
278impl Opts {
279 pub fn build(self) -> Box<dyn WorldGenerator> {
280 let mut r = RustWasm::new();
281 r.skip = self.skip.iter().cloned().collect();
282 r.opts = self;
283 Box::new(r)
284 }
285}
286
287impl RustWasm {
288 fn new() -> RustWasm {
289 RustWasm::default()
290 }
291
292 fn interface<'a>(
293 &'a mut self,
294 identifier: Identifier<'a>,
295 wasm_import_module: &'a str,
296 resolve: &'a Resolve,
297 in_import: bool,
298 ) -> InterfaceGenerator<'a> {
299 let mut sizes = SizeAlign::default();
300 sizes.fill(resolve);
301
302 InterfaceGenerator {
303 identifier,
304 wasm_import_module,
305 src: Source::default(),
306 in_import,
307 r#gen: self,
308 sizes,
309 resolve,
310 return_pointer_area_size: Default::default(),
311 return_pointer_area_align: Default::default(),
312 needs_runtime_module: false,
313 }
314 }
315
316 fn emit_modules(&mut self, modules: Vec<(String, Vec<String>)>) {
317 #[derive(Default)]
318 struct Module {
319 submodules: BTreeMap<String, Module>,
320 contents: Vec<String>,
321 }
322 let mut map = Module::default();
323 for (module, path) in modules {
324 let mut cur = &mut map;
325 for name in path[..path.len() - 1].iter() {
326 cur = cur
327 .submodules
328 .entry(name.clone())
329 .or_insert(Module::default());
330 }
331 cur.contents.push(module);
332 }
333
334 emit(&mut self.src, map, &self.opts, true);
335 fn emit(me: &mut Source, module: Module, opts: &Opts, toplevel: bool) {
336 for (name, submodule) in module.submodules {
337 if toplevel {
338 if opts.format {
342 uwriteln!(me, "#[rustfmt::skip]");
343 }
344
345 uwriteln!(me, "#[allow(dead_code, clippy::all)]");
349 }
350
351 uwriteln!(me, "pub mod {name} {{");
352 emit(me, submodule, opts, false);
353 uwriteln!(me, "}}");
354 }
355 for submodule in module.contents {
356 uwriteln!(me, "{submodule}");
357 }
358 }
359 }
360
361 fn runtime_path(&self) -> &str {
362 self.opts
363 .runtime_path
364 .as_deref()
365 .unwrap_or("wit_bindgen::rt")
366 }
367
368 fn bitflags_path(&self) -> String {
369 self.opts
370 .bitflags_path
371 .to_owned()
372 .unwrap_or(format!("{}::bitflags", self.runtime_path()))
373 }
374
375 fn async_support_path(&self) -> String {
376 format!("{}::async_support", self.runtime_path())
377 }
378
379 fn name_interface(
380 &mut self,
381 resolve: &Resolve,
382 id: InterfaceId,
383 name: &WorldKey,
384 is_export: bool,
385 ) -> Result<bool> {
386 let with_name = resolve.name_world_key(name);
387 let Some(remapping) = self.with.get(&with_name) else {
388 bail!(MissingWith(with_name));
389 };
390 self.generated_types.insert(with_name);
391 let entry = match remapping {
392 TypeGeneration::Remap(remapped_path) => {
393 let name = format!("__with_name{}", self.with_name_counter);
394 self.with_name_counter += 1;
395 uwriteln!(self.src, "use {remapped_path} as {name};");
396 InterfaceName {
397 remapped: true,
398 path: name,
399 }
400 }
401 TypeGeneration::Generate => {
402 let path = compute_module_path(name, resolve, is_export).join("::");
403
404 InterfaceName {
405 remapped: false,
406 path,
407 }
408 }
409 };
410
411 let remapped = entry.remapped;
412 self.interface_names.insert(id, entry);
413
414 Ok(remapped)
415 }
416
417 fn finish_runtime_module(&mut self) {
418 if !self.rt_module.is_empty() {
419 if self.opts.format {
421 uwriteln!(self.src, "#[rustfmt::skip]");
422 }
423
424 self.src.push_str("mod _rt {\n");
425 self.src.push_str("#![allow(dead_code, clippy::all)]\n");
426 let mut emitted = IndexSet::new();
427 while !self.rt_module.is_empty() {
428 for item in mem::take(&mut self.rt_module) {
429 if emitted.insert(item) {
430 self.emit_runtime_item(item);
431 }
432 }
433 }
434 self.src.push_str("}\n");
435 }
436
437 if !self.future_payloads.is_empty() {
438 let async_support = self.async_support_path();
439 self.src.push_str(&format!(
440 "\
441pub mod wit_future {{
442 #![allow(dead_code, unused_variables, clippy::all)]
443
444 #[doc(hidden)]
445 pub trait FuturePayload: Unpin + Sized + 'static {{
446 const VTABLE: &'static {async_support}::FutureVtable<Self>;
447 }}"
448 ));
449 for code in self.future_payloads.values() {
450 self.src.push_str(code);
451 }
452 self.src.push_str(&format!(
453 "\
454 /// Creates a new Component Model `future` with the specified payload type.
455 ///
456 /// The `default` function provided computes the default value to be sent in
457 /// this future if no other value was otherwise sent.
458 pub fn new<T: FuturePayload>(default: fn() -> T) -> ({async_support}::FutureWriter<T>, {async_support}::FutureReader<T>) {{
459 unsafe {{ {async_support}::future_new::<T>(default, T::VTABLE) }}
460 }}
461}}
462 ",
463 ));
464 }
465
466 if !self.stream_payloads.is_empty() {
467 let async_support = self.async_support_path();
468 self.src.push_str(&format!(
469 "\
470pub mod wit_stream {{
471 #![allow(dead_code, unused_variables, clippy::all)]
472
473 pub trait StreamPayload: Unpin + Sized + 'static {{
474 const VTABLE: &'static {async_support}::StreamVtable<Self>;
475 }}"
476 ));
477 for code in self.stream_payloads.values() {
478 self.src.push_str(code);
479 }
480 self.src.push_str(
481 &format!("\
482 /// Creates a new Component Model `stream` with the specified payload type.
483 pub fn new<T: StreamPayload>() -> ({async_support}::StreamWriter<T>, {async_support}::StreamReader<T>) {{
484 unsafe {{ {async_support}::stream_new::<T>(T::VTABLE) }}
485 }}
486}}
487 "),
488 );
489 }
490 }
491
492 fn emit_runtime_item(&mut self, item: RuntimeItem) {
493 match item {
494 RuntimeItem::AllocCrate => {
495 uwriteln!(self.src, "extern crate alloc as alloc_crate;");
496 }
497 RuntimeItem::StdAllocModule => {
498 self.rt_module.insert(RuntimeItem::AllocCrate);
499 uwriteln!(self.src, "pub use alloc_crate::alloc;");
500 }
501 RuntimeItem::StringType => {
502 self.rt_module.insert(RuntimeItem::AllocCrate);
503 uwriteln!(self.src, "pub use alloc_crate::string::String;");
504 }
505 RuntimeItem::BoxType => {
506 self.rt_module.insert(RuntimeItem::AllocCrate);
507 uwriteln!(self.src, "pub use alloc_crate::boxed::Box;");
508 }
509 RuntimeItem::VecType => {
510 self.rt_module.insert(RuntimeItem::AllocCrate);
511 uwriteln!(self.src, "pub use alloc_crate::vec::Vec;");
512 }
513 RuntimeItem::CabiDealloc => {
514 self.rt_module.insert(RuntimeItem::StdAllocModule);
515 self.src.push_str(
516 "\
517pub unsafe fn cabi_dealloc(ptr: *mut u8, size: usize, align: usize) {
518 if size == 0 {
519 return;
520 }
521 unsafe {
522 let layout = alloc::Layout::from_size_align_unchecked(size, align);
523 alloc::dealloc(ptr, layout);
524 }
525}
526 ",
527 );
528 }
529
530 RuntimeItem::StringLift => {
531 self.rt_module.insert(RuntimeItem::StringType);
532 self.src.push_str(
533 "\
534pub unsafe fn string_lift(bytes: Vec<u8>) -> String {
535 if cfg!(debug_assertions) {
536 String::from_utf8(bytes).unwrap()
537 } else {
538 unsafe { String::from_utf8_unchecked(bytes) }
539 }
540}
541 ",
542 );
543 }
544
545 RuntimeItem::InvalidEnumDiscriminant => {
546 self.src.push_str(
547 "\
548pub unsafe fn invalid_enum_discriminant<T>() -> T {
549 if cfg!(debug_assertions) {
550 panic!(\"invalid enum discriminant\")
551 } else {
552 unsafe { core::hint::unreachable_unchecked() }
553 }
554}
555 ",
556 );
557 }
558
559 RuntimeItem::CharLift => {
560 self.src.push_str(
561 "\
562pub unsafe fn char_lift(val: u32) -> char {
563 if cfg!(debug_assertions) {
564 core::char::from_u32(val).unwrap()
565 } else {
566 unsafe { core::char::from_u32_unchecked(val) }
567 }
568}
569 ",
570 );
571 }
572
573 RuntimeItem::BoolLift => {
574 self.src.push_str(
575 "\
576pub unsafe fn bool_lift(val: u8) -> bool {
577 if cfg!(debug_assertions) {
578 match val {
579 0 => false,
580 1 => true,
581 _ => panic!(\"invalid bool discriminant\"),
582 }
583 } else {
584 val != 0
585 }
586}
587 ",
588 );
589 }
590
591 RuntimeItem::RunCtorsOnce => {
592 let rt = self.runtime_path();
593 self.src.push_str(&format!(
594 r#"
595#[cfg(target_arch = "wasm32")]
596pub fn run_ctors_once() {{
597 {rt}::run_ctors_once();
598}}
599 "#,
600 ));
601 }
602
603 RuntimeItem::AsI32 => {
604 self.emit_runtime_as_trait(
605 "i32",
606 &["i32", "u32", "i16", "u16", "i8", "u8", "char", "usize"],
607 );
608 }
609
610 RuntimeItem::AsI64 => {
611 self.emit_runtime_as_trait("i64", &["i64", "u64"]);
612 }
613
614 RuntimeItem::AsF32 => {
615 self.emit_runtime_as_trait("f32", &["f32"]);
616 }
617
618 RuntimeItem::AsF64 => {
619 self.emit_runtime_as_trait("f64", &["f64"]);
620 }
621
622 RuntimeItem::ResourceType => {
623 self.src.push_str(
624 r#"
625
626use core::fmt;
627use core::marker;
628use core::sync::atomic::{AtomicU32, Ordering::Relaxed};
629
630/// A type which represents a component model resource, either imported or
631/// exported into this component.
632///
633/// This is a low-level wrapper which handles the lifetime of the resource
634/// (namely this has a destructor). The `T` provided defines the component model
635/// intrinsics that this wrapper uses.
636///
637/// One of the chief purposes of this type is to provide `Deref` implementations
638/// to access the underlying data when it is owned.
639///
640/// This type is primarily used in generated code for exported and imported
641/// resources.
642#[repr(transparent)]
643pub struct Resource<T: WasmResource> {
644 // NB: This would ideally be `u32` but it is not. The fact that this has
645 // interior mutability is not exposed in the API of this type except for the
646 // `take_handle` method which is supposed to in theory be private.
647 //
648 // This represents, almost all the time, a valid handle value. When it's
649 // invalid it's stored as `u32::MAX`.
650 handle: AtomicU32,
651 _marker: marker::PhantomData<T>,
652}
653
654/// A trait which all wasm resources implement, namely providing the ability to
655/// drop a resource.
656///
657/// This generally is implemented by generated code, not user-facing code.
658#[allow(clippy::missing_safety_doc)]
659pub unsafe trait WasmResource {
660 /// Invokes the `[resource-drop]...` intrinsic.
661 unsafe fn drop(handle: u32);
662}
663
664impl<T: WasmResource> Resource<T> {
665 #[doc(hidden)]
666 pub unsafe fn from_handle(handle: u32) -> Self {
667 debug_assert!(handle != 0 && handle != u32::MAX);
668 Self {
669 handle: AtomicU32::new(handle),
670 _marker: marker::PhantomData,
671 }
672 }
673
674 /// Takes ownership of the handle owned by `resource`.
675 ///
676 /// Note that this ideally would be `into_handle` taking `Resource<T>` by
677 /// ownership. The code generator does not enable that in all situations,
678 /// unfortunately, so this is provided instead.
679 ///
680 /// Also note that `take_handle` is in theory only ever called on values
681 /// owned by a generated function. For example a generated function might
682 /// take `Resource<T>` as an argument but then call `take_handle` on a
683 /// reference to that argument. In that sense the dynamic nature of
684 /// `take_handle` should only be exposed internally to generated code, not
685 /// to user code.
686 #[doc(hidden)]
687 pub fn take_handle(resource: &Resource<T>) -> u32 {
688 resource.handle.swap(u32::MAX, Relaxed)
689 }
690
691 #[doc(hidden)]
692 pub fn handle(resource: &Resource<T>) -> u32 {
693 resource.handle.load(Relaxed)
694 }
695}
696
697impl<T: WasmResource> fmt::Debug for Resource<T> {
698 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
699 f.debug_struct("Resource")
700 .field("handle", &self.handle)
701 .finish()
702 }
703}
704
705impl<T: WasmResource> Drop for Resource<T> {
706 fn drop(&mut self) {
707 unsafe {
708 match self.handle.load(Relaxed) {
709 // If this handle was "taken" then don't do anything in the
710 // destructor.
711 u32::MAX => {}
712
713 // ... but otherwise do actually destroy it with the imported
714 // component model intrinsic as defined through `T`.
715 other => T::drop(other),
716 }
717 }
718 }
719}
720 "#,
721 );
722 }
723 }
724 }
725
726 fn emit_runtime_as_trait(&mut self, ty: &str, to_convert: &[&str]) {
731 let upcase = ty.to_uppercase();
732 self.src.push_str(&format!(
733 r#"
734pub fn as_{ty}<T: As{upcase}>(t: T) -> {ty} {{
735 t.as_{ty}()
736}}
737
738pub trait As{upcase} {{
739 fn as_{ty}(self) -> {ty};
740}}
741
742impl<'a, T: Copy + As{upcase}> As{upcase} for &'a T {{
743 fn as_{ty}(self) -> {ty} {{
744 (*self).as_{ty}()
745 }}
746}}
747 "#
748 ));
749
750 for to_convert in to_convert {
751 self.src.push_str(&format!(
752 r#"
753impl As{upcase} for {to_convert} {{
754 #[inline]
755 fn as_{ty}(self) -> {ty} {{
756 self as {ty}
757 }}
758}}
759 "#
760 ));
761 }
762 }
763
764 fn finish_export_macro(&mut self, resolve: &Resolve, world_id: WorldId) {
770 if self.export_macros.is_empty() {
771 return;
772 }
773 let world = &resolve.worlds[world_id];
774 let world_name = world.name.to_snake_case();
775
776 let default_bindings_module = self
777 .opts
778 .default_bindings_module
779 .clone()
780 .unwrap_or("self".to_string());
781 let (macro_export, use_vis) = if self.opts.pub_export_macro {
782 ("#[macro_export]", "pub")
783 } else {
784 ("", "pub(crate)")
785 };
786 let export_macro_name = self
787 .opts
788 .export_macro_name
789 .as_deref()
790 .unwrap_or("export")
791 .to_string();
792 uwriteln!(
793 self.src,
794 r#"
795/// Generates `#[unsafe(no_mangle)]` functions to export the specified type as
796/// the root implementation of all generated traits.
797///
798/// For more information see the documentation of `wit_bindgen::generate!`.
799///
800/// ```rust
801/// # macro_rules! {export_macro_name} {{ ($($t:tt)*) => (); }}
802/// # trait Guest {{}}
803/// struct MyType;
804///
805/// impl Guest for MyType {{
806/// // ...
807/// }}
808///
809/// {export_macro_name}!(MyType);
810/// ```
811#[allow(unused_macros)]
812#[doc(hidden)]
813{macro_export}
814macro_rules! __export_{world_name}_impl {{
815 ($ty:ident) => ({default_bindings_module}::{export_macro_name}!($ty with_types_in {default_bindings_module}););
816 ($ty:ident with_types_in $($path_to_types_root:tt)*) => ("#
817 );
818 for (name, path_to_types) in self.export_macros.iter() {
819 let mut path = "$($path_to_types_root)*".to_string();
820 if !path_to_types.is_empty() {
821 path.push_str("::");
822 path.push_str(path_to_types)
823 }
824 uwriteln!(self.src, "{path}::{name}!($ty with_types_in {path});");
825 }
826
827 if self.opts.pub_export_macro {
829 uwriteln!(self.src, "const _: () = {{");
830 self.emit_custom_section(resolve, world_id, "imports and exports", None);
831 uwriteln!(self.src, "}};");
832 }
833
834 uwriteln!(self.src, ")\n}}");
835
836 uwriteln!(
837 self.src,
838 "#[doc(inline)]\n\
839 {use_vis} use __export_{world_name}_impl as {export_macro_name};"
840 );
841
842 if self.opts.stubs {
843 uwriteln!(self.src, "export!(Stub);");
844 }
845 }
846
847 fn emit_custom_section(
858 &mut self,
859 resolve: &Resolve,
860 world_id: WorldId,
861 section_suffix: &str,
862 func_name: Option<&str>,
863 ) {
864 if self.opts.format {
866 uwriteln!(self.src, "#[rustfmt::skip]");
867 }
868 self.src.push_str("\n#[cfg(target_arch = \"wasm32\")]\n");
869
870 let opts_suffix = self.opts.type_section_suffix.as_deref().unwrap_or("");
875 let world = &resolve.worlds[world_id];
876 let world_name = &world.name;
877 let pkg = &resolve.packages[world.package.unwrap()].name;
878 let version = env!("CARGO_PKG_VERSION");
879 self.src.push_str(&format!(
880 "#[unsafe(link_section = \"component-type:wit-bindgen:{version}:\
881 {pkg}:{world_name}:{section_suffix}{opts_suffix}\")]\n"
882 ));
883
884 let mut producers = wasm_metadata::Producers::empty();
885 producers.add(
886 "processed-by",
887 env!("CARGO_PKG_NAME"),
888 env!("CARGO_PKG_VERSION"),
889 );
890
891 let component_type = wit_component::metadata::encode(
892 resolve,
893 world_id,
894 wit_component::StringEncoding::UTF8,
895 Some(&producers),
896 )
897 .unwrap();
898
899 self.src.push_str("#[doc(hidden)]\n");
900 self.src.push_str("#[allow(clippy::octal_escapes)]\n");
901 self.src.push_str(&format!(
902 "pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; {}] = *b\"\\\n",
903 component_type.len()
904 ));
905 let old_indent = self.src.set_indent(0);
906 let mut line_length = 0;
907 let s = self.src.as_mut_string();
908 for byte in component_type.iter() {
909 if line_length >= 80 {
910 s.push_str("\\\n");
911 line_length = 0;
912 }
913 match byte {
914 b'\\' => {
915 s.push_str("\\\\");
916 line_length += 2;
917 }
918 b'"' => {
919 s.push_str("\\\"");
920 line_length += 2;
921 }
922 b if b.is_ascii_alphanumeric() || b.is_ascii_punctuation() => {
923 s.push(char::from(*byte));
924 line_length += 1;
925 }
926 0 => {
927 s.push_str("\\0");
928 line_length += 2;
929 }
930 _ => {
931 uwrite!(s, "\\x{:02x}", byte);
932 line_length += 4;
933 }
934 }
935 }
936
937 self.src.push_str("\";\n");
938 self.src.set_indent(old_indent);
939
940 if let Some(func_name) = func_name {
941 let rt = self.runtime_path().to_string();
942 uwriteln!(
943 self.src,
944 "
945 #[inline(never)]
946 #[doc(hidden)]
947 pub fn {func_name}() {{
948 {rt}::maybe_link_cabi_realloc();
949 }}
950 ",
951 );
952 }
953 }
954
955 fn is_async(
956 &mut self,
957 resolve: &Resolve,
958 interface: Option<&WorldKey>,
959 func: &Function,
960 is_import: bool,
961 ) -> bool {
962 self.opts
963 .async_
964 .is_async(resolve, interface, func, is_import)
965 }
966}
967
968impl WorldGenerator for RustWasm {
969 fn preprocess(&mut self, resolve: &Resolve, world: WorldId) {
970 wit_bindgen_core::generated_preamble(&mut self.src_preamble, env!("CARGO_PKG_VERSION"));
971
972 uwriteln!(self.src_preamble, "// Options used:");
975 if self.opts.std_feature {
976 uwriteln!(self.src_preamble, "// * std_feature");
977 }
978 if self.opts.raw_strings {
979 uwriteln!(self.src_preamble, "// * raw_strings");
980 }
981 if !self.opts.skip.is_empty() {
982 uwriteln!(self.src_preamble, "// * skip: {:?}", self.opts.skip);
983 }
984 if self.opts.stubs {
985 uwriteln!(self.src_preamble, "// * stubs");
986 }
987 if let Some(export_prefix) = &self.opts.export_prefix {
988 uwriteln!(
989 self.src_preamble,
990 "// * export_prefix: {:?}",
991 export_prefix
992 );
993 }
994 if let Some(runtime_path) = &self.opts.runtime_path {
995 uwriteln!(self.src_preamble, "// * runtime_path: {:?}", runtime_path);
996 }
997 if let Some(bitflags_path) = &self.opts.bitflags_path {
998 uwriteln!(
999 self.src_preamble,
1000 "// * bitflags_path: {:?}",
1001 bitflags_path
1002 );
1003 }
1004 if !matches!(self.opts.ownership, Ownership::Owning) {
1005 uwriteln!(
1006 self.src_preamble,
1007 "// * ownership: {:?}",
1008 self.opts.ownership
1009 );
1010 }
1011 if !self.opts.additional_derive_attributes.is_empty() {
1012 uwriteln!(
1013 self.src_preamble,
1014 "// * additional derives {:?}",
1015 self.opts.additional_derive_attributes
1016 );
1017 }
1018 if !self.opts.additional_derive_ignore.is_empty() {
1019 uwriteln!(
1020 self.src_preamble,
1021 "// * additional derives ignored {:?}",
1022 self.opts.additional_derive_ignore
1023 );
1024 }
1025 for (k, v) in self.opts.with.iter() {
1026 uwriteln!(self.src_preamble, "// * with {k:?} = {v}");
1027 }
1028 if let Some(type_section_suffix) = &self.opts.type_section_suffix {
1029 uwriteln!(
1030 self.src_preamble,
1031 "// * type_section_suffix: {:?}",
1032 type_section_suffix
1033 );
1034 }
1035 if let Some(default) = &self.opts.default_bindings_module {
1036 uwriteln!(
1037 self.src_preamble,
1038 "// * default-bindings-module: {default:?}"
1039 );
1040 }
1041 if self.opts.disable_run_ctors_once_workaround {
1042 uwriteln!(
1043 self.src_preamble,
1044 "// * disable-run-ctors-once-workaround"
1045 );
1046 }
1047 if let Some(s) = &self.opts.export_macro_name {
1048 uwriteln!(self.src_preamble, "// * export-macro-name: {s}");
1049 }
1050 if self.opts.pub_export_macro {
1051 uwriteln!(self.src_preamble, "// * pub-export-macro");
1052 }
1053 if self.opts.generate_unused_types {
1054 uwriteln!(self.src_preamble, "// * generate_unused_types");
1055 }
1056 if self.opts.disable_custom_section_link_helpers {
1057 uwriteln!(
1058 self.src_preamble,
1059 "// * disable_custom_section_link_helpers"
1060 );
1061 }
1062 for opt in self.opts.async_.debug_opts() {
1063 uwriteln!(self.src_preamble, "// * async: {opt}");
1064 }
1065 self.types.analyze(resolve);
1066 self.world = Some(world);
1067
1068 let world = &resolve.worlds[world];
1069 for (key, item) in world.imports.iter().chain(world.exports.iter()) {
1071 if let WorldItem::Interface { id, .. } = item {
1072 if resolve.interfaces[*id].package == world.package {
1073 let name = resolve.name_world_key(key);
1074 if self.with.get(&name).is_none() {
1075 self.with.insert(name, TypeGeneration::Generate);
1076 }
1077 }
1078 }
1079 }
1080
1081 for (k, v) in self.opts.with.iter() {
1082 self.with.insert(k.clone(), v.clone().into());
1083 }
1084 self.with.generate_by_default = self.opts.generate_all;
1085 }
1086
1087 fn import_interface(
1088 &mut self,
1089 resolve: &Resolve,
1090 name: &WorldKey,
1091 id: InterfaceId,
1092 _files: &mut Files,
1093 ) -> Result<()> {
1094 let mut to_define = Vec::new();
1095 for (name, ty_id) in resolve.interfaces[id].types.iter() {
1096 let full_name = full_wit_type_name(resolve, *ty_id);
1097 if let Some(type_gen) = self.with.get(&full_name) {
1098 if type_gen.generated() {
1100 to_define.push((name, ty_id));
1101 }
1102 } else {
1103 to_define.push((name, ty_id));
1104 }
1105 self.generated_types.insert(full_name);
1106 }
1107
1108 self.interface_last_seen_as_import.insert(id, true);
1109 let wasm_import_module = resolve.name_world_key(name);
1110 let mut r#gen = self.interface(
1111 Identifier::Interface(id, name),
1112 &wasm_import_module,
1113 resolve,
1114 true,
1115 );
1116 let (snake, module_path) = r#gen.start_append_submodule(name);
1117 if r#gen.r#gen.name_interface(resolve, id, name, false)? {
1118 return Ok(());
1119 }
1120
1121 for (name, ty_id) in to_define {
1122 r#gen.define_type(&name, *ty_id);
1123 }
1124
1125 r#gen.generate_imports(resolve.interfaces[id].functions.values(), Some(name));
1126
1127 let docs = &resolve.interfaces[id].docs;
1128
1129 r#gen.finish_append_submodule(&snake, module_path, docs);
1130
1131 Ok(())
1132 }
1133
1134 fn import_funcs(
1135 &mut self,
1136 resolve: &Resolve,
1137 world: WorldId,
1138 funcs: &[(&str, &Function)],
1139 _files: &mut Files,
1140 ) {
1141 self.import_funcs_called = true;
1142
1143 let mut r#gen = self.interface(Identifier::World(world), "$root", resolve, true);
1144
1145 r#gen.generate_imports(funcs.iter().map(|(_, func)| *func), None);
1146
1147 let src = r#gen.finish();
1148 self.src.push_str(&src);
1149 }
1150
1151 fn export_interface(
1152 &mut self,
1153 resolve: &Resolve,
1154 name: &WorldKey,
1155 id: InterfaceId,
1156 _files: &mut Files,
1157 ) -> Result<()> {
1158 let mut to_define = Vec::new();
1159 for (name, ty_id) in resolve.interfaces[id].types.iter() {
1160 let full_name = full_wit_type_name(resolve, *ty_id);
1161 if let Some(type_gen) = self.with.get(&full_name) {
1162 if type_gen.generated() {
1164 to_define.push((name, ty_id));
1165 }
1166 } else {
1167 to_define.push((name, ty_id));
1168 }
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}