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