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