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