Skip to main content

wit_bindgen_rust/
lib.rs

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, ChainableMethodFilterSet, ChainingMode, Files, InterfaceGenerator as _, Source,
14    Types, WorldGenerator, dealias, name_package_module, uwrite, uwriteln, wit_parser::*,
15};
16
17mod bindgen;
18mod interface;
19
20struct InterfaceName {
21    /// True when this interface name has been remapped through the use of `with` in the `bindgen!`
22    /// macro invocation.
23    remapped: bool,
24
25    /// The string name for this interface.
26    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    exported_resources: HashSet<TypeId>,
40    import_funcs_called: bool,
41    with_name_counter: usize,
42    // Track which interfaces and types are generated. Remapped interfaces and types provided via `with`
43    // are required to be used.
44    generated_types: HashSet<String>,
45    // Attribute selectors that matched something, so `finish` can reject the rest.
46    used_type_attr_selectors: HashSet<String>,
47    used_member_attr_selectors: HashSet<String>,
48    world: Option<WorldId>,
49
50    rt_module: IndexSet<RuntimeItem>,
51    export_macros: Vec<(String, String)>,
52
53    /// Maps wit interface and type names to their Rust identifiers
54    with: GenerationConfiguration,
55
56    future_payloads: IndexMap<Option<Type>, String>,
57    stream_payloads: IndexMap<Option<Type>, String>,
58}
59
60#[derive(Default)]
61struct GenerationConfiguration {
62    map: HashMap<String, TypeGeneration>,
63    generate_by_default: bool,
64}
65
66impl GenerationConfiguration {
67    fn get(&self, key: &str) -> Option<&TypeGeneration> {
68        self.map.get(key).or_else(|| {
69            self.generate_by_default
70                .then_some(&TypeGeneration::Generate)
71        })
72    }
73
74    fn insert(&mut self, name: String, generate: TypeGeneration) {
75        self.map.insert(name, generate);
76    }
77
78    fn iter(&self) -> impl Iterator<Item = (&String, &TypeGeneration)> {
79        self.map.iter()
80    }
81}
82
83/// How a wit interface or type should be rendered in Rust
84enum TypeGeneration {
85    /// Uses a Rust identifier defined elsewhere
86    Remap(String),
87    /// Define the interface or type with this bindgen invocation
88    Generate,
89}
90
91impl TypeGeneration {
92    /// Returns true if the interface or type should be defined with this bindgen invocation
93    fn generated(&self) -> bool {
94        match self {
95            TypeGeneration::Generate => true,
96            TypeGeneration::Remap(_) => false,
97        }
98    }
99}
100
101#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
102enum RuntimeItem {
103    AllocCrate,
104    StringType,
105    StdAllocModule,
106    VecType,
107    StringLift,
108    InvalidEnumDiscriminant,
109    CharLift,
110    BoolLift,
111    CabiDealloc,
112    RunCtorsOnce,
113    AsI32,
114    AsI64,
115    AsF32,
116    AsF64,
117    ResourceType,
118    BoxType,
119    WitMapTrait,
120}
121
122#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
123#[cfg_attr(
124    feature = "serde",
125    derive(serde::Deserialize),
126    serde(rename_all = "kebab-case")
127)]
128pub enum ExportKey {
129    World,
130    Name(String),
131}
132
133#[cfg(feature = "clap")]
134fn parse_with(s: &str) -> Result<(String, WithOption), String> {
135    let (k, v) = s.split_once('=').ok_or_else(|| {
136        format!("expected string of form `<key>=<value>[,<key>=<value>...]`; got `{s}`")
137    })?;
138    let v = match v {
139        "generate" => WithOption::Generate,
140        other => WithOption::Path(other.to_string()),
141    };
142    Ok((k.to_string(), v))
143}
144
145// Split on the first `=` only, so the attribute may itself contain `=`.
146#[cfg(feature = "clap")]
147fn parse_attribute(s: &str) -> Result<(String, String), String> {
148    let (sel, attr) = s
149        .split_once('=')
150        .ok_or_else(|| format!("expected string of form `<selector>=<attribute>`; got `{s}`"))?;
151    // An empty attribute would mark the selector used and escape the unused check.
152    if attr.trim().is_empty() {
153        return Err(format!("attribute must not be empty; got `{s}`"));
154    }
155    Ok((sel.to_string(), attr.to_string()))
156}
157
158#[derive(Default, Debug, Clone)]
159#[cfg_attr(feature = "clap", derive(clap::Parser))]
160#[cfg_attr(
161    feature = "serde",
162    derive(serde::Deserialize),
163    serde(default, rename_all = "kebab-case")
164)]
165pub struct Opts {
166    /// Whether or not a formatter is executed to format generated code.
167    #[cfg_attr(feature = "clap", arg(long))]
168    pub format: bool,
169
170    /// If true, code generation should qualify any features that depend on
171    /// `std` with `cfg(feature = "std")`.
172    #[cfg_attr(feature = "clap", arg(long))]
173    pub std_feature: bool,
174
175    /// If true, code generation should pass borrowed string arguments as
176    /// `&[u8]` instead of `&str`. Strings are still required to be valid
177    /// UTF-8, but this avoids the need for Rust code to do its own UTF-8
178    /// validation if it doesn't already have a `&str`.
179    #[cfg_attr(feature = "clap", arg(long))]
180    pub raw_strings: bool,
181
182    /// Names of functions to skip generating bindings for.
183    #[cfg_attr(feature = "clap", arg(long, value_name = "NAME"))]
184    pub skip: Vec<String>,
185
186    /// If true, generate stub implementations for any exported functions,
187    /// interfaces, and/or resources.
188    #[cfg_attr(feature = "clap", arg(long))]
189    pub stubs: bool,
190
191    /// Optionally prefix any export names with the specified value.
192    ///
193    /// This is useful to avoid name conflicts when testing.
194    #[cfg_attr(feature = "clap", arg(long, value_name = "STRING"))]
195    pub export_prefix: Option<String>,
196
197    /// Whether to generate owning or borrowing type definitions.
198    ///
199    /// Valid values include:
200    ///
201    /// - `owning`: Generated types will be composed entirely of owning fields,
202    /// regardless of whether they are used as parameters to imports or not.
203    ///
204    /// - `borrowing`: Generated types used as parameters to imports will be
205    /// "deeply borrowing", i.e. contain references rather than owned values
206    /// when applicable.
207    ///
208    /// - `borrowing-duplicate-if-necessary`: As above, but generating distinct
209    /// types for borrowing and owning, if necessary.
210    #[cfg_attr(feature = "clap", arg(long, default_value_t = Ownership::Owning))]
211    pub ownership: Ownership,
212
213    /// The optional path to the wit-bindgen runtime module to use.
214    ///
215    /// This defaults to `wit_bindgen::rt`.
216    #[cfg_attr(feature = "clap", arg(long, value_name = "PATH"))]
217    pub runtime_path: Option<String>,
218
219    /// The optional path to the map type to use for WIT `map<K, V>`.
220    ///
221    /// The specified type must accept two type parameters `<K, V>` and
222    /// implement the `WitMap<K, V>` trait from the wit-bindgen runtime.
223    /// It must also implement `IntoIterator<Item = (K, V)>` (owned) and
224    /// its reference must implement `IntoIterator` yielding key/value
225    /// pairs.
226    ///
227    /// Defaults to `{runtime_path}::Map` which is `BTreeMap`.
228    #[cfg_attr(feature = "clap", arg(long, value_name = "PATH"))]
229    pub map_type: Option<String>,
230
231    /// The optional path to the bitflags crate to use.
232    ///
233    /// This defaults to `wit_bindgen::bitflags`.
234    #[cfg_attr(feature = "clap", arg(long))]
235    pub bitflags_path: Option<String>,
236
237    /// Additional derive attributes to add to generated types. If using in a CLI, this flag can be
238    /// specified multiple times to add multiple attributes.
239    ///
240    /// These derive attributes will be added to any generated structs or enums
241    #[cfg_attr(feature = "clap", arg(long, short = 'd', value_name = "DERIVE"))]
242    pub additional_derive_attributes: Vec<String>,
243
244    /// Variants and records to ignore when applying additional derive attributes.
245    ///
246    /// These names are specified as they are listed in the wit file, i.e. in kebab case.
247    /// This feature allows some variants and records to use types for which adding traits will cause
248    /// compilation to fail, such as serde::Deserialize on wasi:io/streams.
249    ///
250    #[cfg_attr(feature = "clap", arg(long, value_name = "NAME"))]
251    pub additional_derive_ignore: Vec<String>,
252
253    /// Extra attributes to emit on specific generated types, rather than on all
254    /// types like `additional_derive_attributes`.
255    ///
256    /// Each entry pairs a selector with an attribute. A selector is a type's
257    /// fully qualified name, written as in `with`, so `my:pkg/types/point`,
258    /// carrying `@version` when the package is versioned. A selector matching
259    /// nothing is an error, as with `with`.
260    ///
261    /// Only records, variants, and enums are covered. Attributes are emitted
262    /// verbatim on every form of the type, including the borrowed form under
263    /// `ownership: Borrowing`, so an owned-only derive fails to compile there.
264    ///
265    /// In a CLI, this flag can be specified multiple times as
266    /// `selector=attribute`.
267    #[cfg_attr(feature = "clap", arg(long, value_name = "SELECTOR=ATTR", value_parser = parse_attribute))]
268    pub additional_type_attributes: Vec<(String, String)>,
269
270    /// Extra attributes to emit on specific generated record fields and
271    /// enum/variant cases.
272    ///
273    /// As `additional_type_attributes`, except the selector is a type's fully
274    /// qualified name, a `.`, and the member name.
275    ///
276    /// In a CLI, this flag can be specified multiple times as
277    /// `selector=attribute`.
278    #[cfg_attr(feature = "clap", arg(long, value_name = "SELECTOR=ATTR", value_parser = parse_attribute))]
279    pub additional_member_attributes: Vec<(String, String)>,
280
281    /// Remapping of wit import interface and type names to Rust module names
282    /// and types.
283    ///
284    /// Argument must be of the form `k=v` and this option can be passed
285    /// multiple times or one option can be comma separated, for example
286    /// `k1=v1,k2=v2`.
287    #[cfg_attr(feature = "clap", arg(long, value_parser = parse_with, value_delimiter = ','))]
288    pub with: Vec<(String, WithOption)>,
289
290    /// Indicates that all interfaces not specified in `with` should be
291    /// generated.
292    #[cfg_attr(feature = "clap", arg(long))]
293    pub generate_all: bool,
294
295    /// Add the specified suffix to the name of the custome section containing
296    /// the component type.
297    #[cfg_attr(feature = "clap", arg(long, value_name = "STRING"))]
298    pub type_section_suffix: Option<String>,
299
300    /// Disable a workaround used to prevent libc ctors/dtors from being invoked
301    /// too much.
302    #[cfg_attr(feature = "clap", arg(long))]
303    pub disable_run_ctors_once_workaround: bool,
304
305    /// Changes the default module used in the generated `export!` macro to
306    /// something other than `self`.
307    #[cfg_attr(feature = "clap", arg(long, value_name = "NAME"))]
308    pub default_bindings_module: Option<String>,
309
310    /// Alternative name to use for the `export!` macro if one is generated.
311    #[cfg_attr(feature = "clap", arg(long, value_name = "NAME"))]
312    pub export_macro_name: Option<String>,
313
314    /// Ensures that the `export!` macro will be defined as `pub` so it is a
315    /// candidate for being exported outside of the crate.
316    #[cfg_attr(feature = "clap", arg(long))]
317    pub pub_export_macro: bool,
318
319    /// Whether to generate unused structures, not generated by default (false)
320    #[cfg_attr(feature = "clap", arg(long))]
321    pub generate_unused_types: bool,
322
323    /// Whether or not to generate helper function/constants to help link custom
324    /// sections into the final output.
325    ///
326    /// Disabling this can shave a few bytes off a binary but makes
327    /// library-based usage of `generate!` prone to breakage.
328    #[cfg_attr(feature = "clap", arg(long))]
329    pub disable_custom_section_link_helpers: bool,
330
331    #[cfg_attr(feature = "clap", clap(flatten))]
332    #[cfg_attr(feature = "serde", serde(flatten))]
333    pub async_: AsyncFilterSet,
334
335    /// Find all structurally equal types and only generate one type definition
336    /// for each equivalence class.
337    ///
338    /// Other types in the same class will be type aliases to the generated
339    /// type. This avoids clone when converting between types that are
340    /// structurally equal, which is useful when import and export the same
341    /// interface.
342    #[cfg_attr(
343        feature = "clap",
344        arg(long, require_equals = true, value_name = "true|false")
345    )]
346    pub merge_structurally_equal_types: Option<Option<bool>>,
347
348    #[cfg_attr(feature = "clap", clap(flatten))]
349    #[cfg_attr(feature = "serde", serde(flatten))]
350    pub chainable_methods: ChainableMethodFilterSet,
351}
352
353impl Opts {
354    pub fn build(self) -> RustWasm {
355        let mut r = RustWasm::new();
356        r.skip = self.skip.iter().cloned().collect();
357        r.opts = self;
358        r
359    }
360
361    fn merge_structurally_equal_types(&self) -> bool {
362        const DEFAULT: bool = false;
363        match self.merge_structurally_equal_types {
364            // no option passed, use the default
365            None => DEFAULT,
366            // --merge-structurally-equal-types
367            Some(None) => true,
368            // --merge-structurally-equal-types=val
369            Some(Some(val)) => val,
370        }
371    }
372}
373
374impl RustWasm {
375    /// Generates Rust bindings from the `wit/` directory and writes
376    /// the result into Cargo’s `OUT_DIR`. Intended for use in `build.rs`.
377    ///
378    /// The `world` parameter specifies the world name to select.
379    /// It must be provided unless the main package contains exactly one world.
380    ///
381    /// Returns the full path to the generated bindings file.
382    pub fn generate_to_out_dir(mut self, world: Option<&str>) -> Result<PathBuf> {
383        let mut resolve = Resolve::default();
384        println!("cargo:rerun-if-changed=wit/");
385        let (pkg, _files) = resolve.push_path("wit")?;
386        let main_packages = vec![pkg];
387        let world = resolve.select_world(&main_packages, world)?;
388
389        let mut files = Files::default();
390        self.generate(&mut resolve, world, &mut files)?;
391        let out_dir = std::env::var("OUT_DIR").expect("cargo sets OUT_DIR");
392        let (name, contents) = files
393            .iter()
394            .next()
395            .expect("exactly one file should be generated");
396        let dst = Path::new(&out_dir).join(name);
397        std::fs::write(&dst, contents)?;
398        Ok(dst)
399    }
400
401    fn new() -> RustWasm {
402        RustWasm::default()
403    }
404
405    fn interface<'a>(
406        &'a mut self,
407        identifier: Identifier<'a>,
408        wasm_import_module: &'a str,
409        resolve: &'a Resolve,
410        in_import: bool,
411    ) -> Result<InterfaceGenerator<'a>> {
412        let mut sizes = SizeAlign::default();
413        sizes.fill(resolve)?;
414
415        Ok(InterfaceGenerator {
416            identifier,
417            wasm_import_module,
418            src: Source::default(),
419            in_import,
420            r#gen: self,
421            sizes,
422            resolve,
423            return_pointer_area_size: Default::default(),
424            return_pointer_area_align: Default::default(),
425            needs_runtime_module: false,
426            needs_wit_map: false,
427        })
428    }
429
430    fn emit_modules(&mut self, modules: Vec<(String, Vec<String>)>) {
431        #[derive(Default)]
432        struct Module {
433            submodules: BTreeMap<String, Module>,
434            contents: Vec<String>,
435        }
436        let mut map = Module::default();
437        for (module, path) in modules {
438            let mut cur = &mut map;
439            for name in path[..path.len() - 1].iter() {
440                cur = cur
441                    .submodules
442                    .entry(name.clone())
443                    .or_insert(Module::default());
444            }
445            cur.contents.push(module);
446        }
447
448        emit(&mut self.src, map, &self.opts, true);
449        fn emit(me: &mut Source, module: Module, opts: &Opts, toplevel: bool) {
450            for (name, submodule) in module.submodules {
451                if toplevel {
452                    // Disable rustfmt. By default we already format the code
453                    // using prettyplease, so we don't want `cargo fmt` to create
454                    // extra diffs for users to deal with.
455                    if opts.format {
456                        uwriteln!(me, "#[rustfmt::skip]");
457                    }
458
459                    // Ignore dead-code and clippy warnings. If the bindings are
460                    // only used within a crate, and not exported to a different
461                    // crate, some parts may be unused, and that's ok.
462                    uwriteln!(me, "#[allow(dead_code, clippy::all)]");
463                }
464
465                uwriteln!(me, "pub mod {name} {{");
466                emit(me, submodule, opts, false);
467                uwriteln!(me, "}}");
468            }
469            for submodule in module.contents {
470                uwriteln!(me, "{submodule}");
471            }
472        }
473    }
474
475    fn runtime_path(&self) -> &str {
476        self.opts
477            .runtime_path
478            .as_deref()
479            .unwrap_or("wit_bindgen::rt")
480    }
481
482    fn map_type_path(&self) -> String {
483        self.opts
484            .map_type
485            .clone()
486            .unwrap_or_else(|| format!("{}::Map", self.runtime_path()))
487    }
488
489    fn wit_map_path(&self) -> String {
490        format!("{}::WitMap", self.runtime_path())
491    }
492
493    fn bitflags_path(&self) -> String {
494        self.opts
495            .bitflags_path
496            .to_owned()
497            .unwrap_or(format!("{}::bitflags", self.runtime_path()))
498    }
499
500    fn async_support_path(&self) -> String {
501        format!("{}::async_support", self.runtime_path())
502    }
503
504    fn name_interface(
505        &mut self,
506        resolve: &Resolve,
507        id: InterfaceId,
508        name: &WorldKey,
509        is_export: bool,
510    ) -> Result<bool> {
511        let with_name = resolve.name_world_key(name);
512        let remapping = if is_export {
513            &TypeGeneration::Generate
514        } else {
515            match self.with.get(&with_name) {
516                Some(remapping) => remapping,
517                None => bail!(MissingWith(with_name)),
518            }
519        };
520        self.generated_types.insert(with_name);
521        let entry = match remapping {
522            TypeGeneration::Remap(remapped_path) => {
523                let name = format!("__with_name{}", self.with_name_counter);
524                self.with_name_counter += 1;
525                uwriteln!(
526                    self.src,
527                    "#[allow(unfulfilled_lint_expectations, unused_imports)]"
528                );
529                uwriteln!(self.src, "use {remapped_path} as {name};");
530                InterfaceName {
531                    remapped: true,
532                    path: name,
533                }
534            }
535            TypeGeneration::Generate => {
536                let path = compute_module_path(name, resolve, is_export).join("::");
537
538                InterfaceName {
539                    remapped: false,
540                    path,
541                }
542            }
543        };
544
545        let remapped = entry.remapped;
546        let prev = self.interface_names.insert(id, entry);
547        assert!(prev.is_none());
548
549        Ok(remapped)
550    }
551
552    fn finish_runtime_module(&mut self) {
553        if !self.rt_module.is_empty() {
554            // As above, disable rustfmt, as we use prettyplease.
555            if self.opts.format {
556                uwriteln!(self.src, "#[rustfmt::skip]");
557            }
558
559            self.src.push_str("mod _rt {\n");
560            self.src
561                .push_str("#![allow(dead_code, unused_imports, clippy::all)]\n");
562            let mut emitted = IndexSet::new();
563            while !self.rt_module.is_empty() {
564                for item in mem::take(&mut self.rt_module) {
565                    if emitted.insert(item) {
566                        self.emit_runtime_item(item);
567                    }
568                }
569            }
570            self.src.push_str("}\n");
571        }
572
573        if !self.future_payloads.is_empty() {
574            let async_support = self.async_support_path();
575            self.src.push_str(&format!(
576                "\
577pub mod wit_future {{
578    #![allow(dead_code, unused_variables, clippy::all)]
579
580    #[doc(hidden)]
581    pub trait FuturePayload: Unpin + Sized + 'static {{
582        const VTABLE: &'static {async_support}::FutureVtable<Self>;
583    }}"
584            ));
585            for code in self.future_payloads.values() {
586                self.src.push_str(code);
587            }
588            self.src.push_str(&format!(
589                "\
590    /// Creates a new Component Model `future` with the specified payload type.
591    ///
592    /// The `default` function provided computes the default value to be sent in
593    /// this future if no other value was otherwise sent.
594    pub fn new<T: FuturePayload>(default: fn() -> T) -> ({async_support}::FutureWriter<T>, {async_support}::FutureReader<T>) {{
595        unsafe {{ {async_support}::future_new::<T>(default, T::VTABLE) }}
596    }}
597}}
598                ",
599            ));
600        }
601
602        if !self.stream_payloads.is_empty() {
603            let async_support = self.async_support_path();
604            self.src.push_str(&format!(
605                "\
606pub mod wit_stream {{
607    #![allow(dead_code, unused_variables, clippy::all)]
608
609    pub trait StreamPayload: Unpin + Sized + 'static {{
610        const VTABLE: &'static {async_support}::StreamVtable<Self>;
611    }}"
612            ));
613            for code in self.stream_payloads.values() {
614                self.src.push_str(code);
615            }
616            self.src.push_str(
617                &format!("\
618    /// Creates a new Component Model `stream` with the specified payload type.
619    pub fn new<T: StreamPayload>() -> ({async_support}::StreamWriter<T>, {async_support}::StreamReader<T>) {{
620        unsafe {{ {async_support}::stream_new::<T>(T::VTABLE) }}
621    }}
622}}
623                "),
624            );
625        }
626    }
627
628    fn emit_runtime_item(&mut self, item: RuntimeItem) {
629        match item {
630            RuntimeItem::AllocCrate => {
631                uwriteln!(self.src, "extern crate alloc as alloc_crate;");
632            }
633            RuntimeItem::StdAllocModule => {
634                self.rt_module.insert(RuntimeItem::AllocCrate);
635                uwriteln!(self.src, "pub use alloc_crate::alloc;");
636            }
637            RuntimeItem::StringType => {
638                self.rt_module.insert(RuntimeItem::AllocCrate);
639                uwriteln!(self.src, "pub use alloc_crate::string::String;");
640            }
641            RuntimeItem::BoxType => {
642                self.rt_module.insert(RuntimeItem::AllocCrate);
643                uwriteln!(self.src, "pub use alloc_crate::boxed::Box;");
644            }
645            RuntimeItem::VecType => {
646                self.rt_module.insert(RuntimeItem::AllocCrate);
647                uwriteln!(self.src, "pub use alloc_crate::vec::Vec;");
648            }
649            RuntimeItem::CabiDealloc => {
650                self.rt_module.insert(RuntimeItem::StdAllocModule);
651                self.src.push_str(
652                    "\
653pub unsafe fn cabi_dealloc(ptr: *mut u8, size: usize, align: usize) {
654    if size == 0 {
655        return;
656    }
657    unsafe {
658        let layout = alloc::Layout::from_size_align_unchecked(size, align);
659        alloc::dealloc(ptr, layout);
660    }
661}
662                    ",
663                );
664            }
665
666            RuntimeItem::StringLift => {
667                self.rt_module.insert(RuntimeItem::StringType);
668                self.src.push_str(
669                    "\
670pub unsafe fn string_lift(bytes: Vec<u8>) -> String {
671    if cfg!(debug_assertions) {
672        String::from_utf8(bytes).unwrap()
673    } else {
674        unsafe { String::from_utf8_unchecked(bytes) }
675    }
676}
677                    ",
678                );
679            }
680
681            RuntimeItem::InvalidEnumDiscriminant => {
682                self.src.push_str(
683                    "\
684pub unsafe fn invalid_enum_discriminant<T>() -> T {
685    if cfg!(debug_assertions) {
686        panic!(\"invalid enum discriminant\")
687    } else {
688        unsafe { core::hint::unreachable_unchecked() }
689    }
690}
691                    ",
692                );
693            }
694
695            RuntimeItem::CharLift => {
696                self.src.push_str(
697                    "\
698pub unsafe fn char_lift(val: u32) -> char {
699    if cfg!(debug_assertions) {
700        core::char::from_u32(val).unwrap()
701    } else {
702        unsafe { core::char::from_u32_unchecked(val) }
703    }
704}
705                    ",
706                );
707            }
708
709            RuntimeItem::BoolLift => {
710                self.src.push_str(
711                    "\
712pub unsafe fn bool_lift(val: u8) -> bool {
713    if cfg!(debug_assertions) {
714        match val {
715            0 => false,
716            1 => true,
717            _ => panic!(\"invalid bool discriminant\"),
718        }
719    } else {
720        val != 0
721    }
722}
723                    ",
724                );
725            }
726
727            RuntimeItem::RunCtorsOnce => {
728                let rt = self.runtime_path();
729                self.src.push_str(&format!(
730                    r#"
731#[cfg(target_arch = "wasm32")]
732pub fn run_ctors_once() {{
733    {rt}::run_ctors_once();
734}}
735                    "#,
736                ));
737            }
738
739            RuntimeItem::AsI32 => {
740                self.emit_runtime_as_trait(
741                    "i32",
742                    &["i32", "u32", "i16", "u16", "i8", "u8", "char", "usize"],
743                );
744            }
745
746            RuntimeItem::AsI64 => {
747                self.emit_runtime_as_trait("i64", &["i64", "u64"]);
748            }
749
750            RuntimeItem::AsF32 => {
751                self.emit_runtime_as_trait("f32", &["f32"]);
752            }
753
754            RuntimeItem::AsF64 => {
755                self.emit_runtime_as_trait("f64", &["f64"]);
756            }
757
758            RuntimeItem::WitMapTrait => {
759                let rt = self.runtime_path().to_string();
760                uwriteln!(self.src, "pub use {rt}::WitMap;");
761            }
762
763            RuntimeItem::ResourceType => {
764                self.src.push_str(
765                    r#"
766
767use core::fmt;
768use core::marker;
769use core::sync::atomic::{AtomicU32, Ordering::Relaxed};
770
771/// A type which represents a component model resource, either imported or
772/// exported into this component.
773///
774/// This is a low-level wrapper which handles the lifetime of the resource
775/// (namely this has a destructor). The `T` provided defines the component model
776/// intrinsics that this wrapper uses.
777///
778/// One of the chief purposes of this type is to provide `Deref` implementations
779/// to access the underlying data when it is owned.
780///
781/// This type is primarily used in generated code for exported and imported
782/// resources.
783#[repr(transparent)]
784pub struct Resource<T: WasmResource> {
785    // NB: This would ideally be `u32` but it is not. The fact that this has
786    // interior mutability is not exposed in the API of this type except for the
787    // `take_handle` method which is supposed to in theory be private.
788    //
789    // This represents, almost all the time, a valid handle value. When it's
790    // invalid it's stored as `u32::MAX`.
791    handle: AtomicU32,
792    _marker: marker::PhantomData<T>,
793}
794
795/// A trait which all wasm resources implement, namely providing the ability to
796/// drop a resource.
797///
798/// This generally is implemented by generated code, not user-facing code.
799#[allow(clippy::missing_safety_doc)]
800pub unsafe trait WasmResource {
801    /// Invokes the `[resource-drop]...` intrinsic.
802    unsafe fn drop(handle: u32);
803}
804
805impl<T: WasmResource> Resource<T> {
806    #[doc(hidden)]
807    pub unsafe fn from_handle(handle: u32) -> Self {
808        debug_assert!(handle != 0 && handle != u32::MAX);
809        Self {
810            handle: AtomicU32::new(handle),
811            _marker: marker::PhantomData,
812        }
813    }
814
815    /// Takes ownership of the handle owned by `resource`.
816    ///
817    /// Note that this ideally would be `into_handle` taking `Resource<T>` by
818    /// ownership. The code generator does not enable that in all situations,
819    /// unfortunately, so this is provided instead.
820    ///
821    /// Also note that `take_handle` is in theory only ever called on values
822    /// owned by a generated function. For example a generated function might
823    /// take `Resource<T>` as an argument but then call `take_handle` on a
824    /// reference to that argument. In that sense the dynamic nature of
825    /// `take_handle` should only be exposed internally to generated code, not
826    /// to user code.
827    #[doc(hidden)]
828    pub fn take_handle(resource: &Resource<T>) -> u32 {
829        resource.handle.swap(u32::MAX, Relaxed)
830    }
831
832    #[doc(hidden)]
833    pub fn handle(resource: &Resource<T>) -> u32 {
834        resource.handle.load(Relaxed)
835    }
836}
837
838impl<T: WasmResource> fmt::Debug for Resource<T> {
839    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
840        f.debug_struct("Resource")
841            .field("handle", &self.handle)
842            .finish()
843    }
844}
845
846impl<T: WasmResource> Drop for Resource<T> {
847    fn drop(&mut self) {
848        unsafe {
849            match self.handle.load(Relaxed) {
850                // If this handle was "taken" then don't do anything in the
851                // destructor.
852                u32::MAX => {}
853
854                // ... but otherwise do actually destroy it with the imported
855                // component model intrinsic as defined through `T`.
856                other => T::drop(other),
857            }
858        }
859    }
860}
861                    "#,
862                );
863            }
864        }
865    }
866
867    // This is a workaround for in the bindings sometimes we've got `&i32` and
868    // sometimes we've got `i32` but that should all be able to be worked with
869    // as `i32`, so these helper functions are used to boil away the
870    // indirection.
871    fn emit_runtime_as_trait(&mut self, ty: &str, to_convert: &[&str]) {
872        let upcase = ty.to_uppercase();
873        self.src.push_str(&format!(
874            r#"
875pub fn as_{ty}<T: As{upcase}>(t: T) -> {ty} {{
876    t.as_{ty}()
877}}
878
879pub trait As{upcase} {{
880    fn as_{ty}(self) -> {ty};
881}}
882
883impl<'a, T: Copy + As{upcase}> As{upcase} for &'a T {{
884    fn as_{ty}(self) -> {ty} {{
885        (*self).as_{ty}()
886    }}
887}}
888            "#
889        ));
890
891        for to_convert in to_convert {
892            self.src.push_str(&format!(
893                r#"
894impl As{upcase} for {to_convert} {{
895    #[inline]
896    fn as_{ty}(self) -> {ty} {{
897        self as {ty}
898    }}
899}}
900                "#
901            ));
902        }
903    }
904
905    /// Generates an `export!` macro for the `world_id` specified.
906    ///
907    /// This will generate a macro which will then itself invoke all the
908    /// other macros collected in `self.export_macros` prior. All these macros
909    /// are woven together in this single invocation.
910    fn finish_export_macro(&mut self, resolve: &Resolve, world_id: WorldId) {
911        if self.export_macros.is_empty() {
912            return;
913        }
914        let world = &resolve.worlds[world_id];
915        let world_name = world.name.to_snake_case();
916
917        let default_bindings_module = self
918            .opts
919            .default_bindings_module
920            .clone()
921            .unwrap_or("self".to_string());
922        let (macro_export, use_vis) = if self.opts.pub_export_macro {
923            ("#[macro_export]", "pub")
924        } else {
925            ("", "pub(crate)")
926        };
927        let export_macro_name = self
928            .opts
929            .export_macro_name
930            .as_deref()
931            .unwrap_or("export")
932            .to_string();
933        uwriteln!(
934            self.src,
935            r#"
936/// Generates `#[unsafe(no_mangle)]` functions to export the specified type as
937/// the root implementation of all generated traits.
938///
939/// For more information see the documentation of `wit_bindgen::generate!`.
940///
941/// ```rust
942/// # macro_rules! {export_macro_name} {{ ($($t:tt)*) => (); }}
943/// # trait Guest {{}}
944/// struct MyType;
945///
946/// impl Guest for MyType {{
947///     // ...
948/// }}
949///
950/// {export_macro_name}!(MyType);
951/// ```
952#[allow(unused_macros)]
953#[doc(hidden)]
954{macro_export}
955macro_rules! __export_{world_name}_impl {{
956    ($ty:ident) => ({default_bindings_module}::{export_macro_name}!($ty with_types_in {default_bindings_module}););
957    ($ty:ident with_types_in $($path_to_types_root:tt)*) => ("#
958        );
959        for (name, path_to_types) in self.export_macros.iter() {
960            let mut path = "$($path_to_types_root)*".to_string();
961            if !path_to_types.is_empty() {
962                path.push_str("::");
963                path.push_str(path_to_types)
964            }
965            uwriteln!(self.src, "{path}::{name}!($ty with_types_in {path});");
966        }
967
968        // See comments in `finish` for why this conditionally happens here.
969        if self.opts.pub_export_macro {
970            uwriteln!(self.src, "const _: () = {{");
971            self.emit_custom_section(resolve, world_id, "imports and exports", None);
972            uwriteln!(self.src, "}};");
973        }
974
975        uwriteln!(self.src, ")\n}}");
976
977        uwriteln!(
978            self.src,
979            "#[doc(inline)]\n\
980            {use_vis} use __export_{world_name}_impl as {export_macro_name};"
981        );
982
983        if self.opts.stubs {
984            uwriteln!(self.src, "export!(Stub);");
985        }
986    }
987
988    /// Generates a `#[link_section]` custom section to get smuggled through
989    /// `wasm-ld`.
990    ///
991    /// This custom section is an encoding of the component metadata and will be
992    /// used as part of the `wit-component`-based componentization process.
993    ///
994    /// The `section_suffix` here is used to distinguish the multiple sections
995    /// that this generator emits, and `func_name` is an optional function to
996    /// generate next to this which is used to force rustc to at least visit
997    /// this `static` and codegen it.
998    fn emit_custom_section(
999        &mut self,
1000        resolve: &Resolve,
1001        world_id: WorldId,
1002        section_suffix: &str,
1003        func_name: Option<&str>,
1004    ) {
1005        // As above, disable rustfmt, as we use prettyplease.
1006        if self.opts.format {
1007            uwriteln!(self.src, "#[rustfmt::skip]");
1008        }
1009        self.src.push_str("\n#[cfg(target_arch = \"wasm32\")]\n");
1010
1011        // The custom section name here must start with "component-type" but
1012        // otherwise is attempted to be unique here to ensure that this doesn't get
1013        // concatenated to other custom sections by LLD by accident since LLD will
1014        // concatenate custom sections of the same name.
1015        let opts_suffix = self.opts.type_section_suffix.as_deref().unwrap_or("");
1016        let world = &resolve.worlds[world_id];
1017        let world_name = &world.name;
1018        let pkg = &resolve.packages[world.package.unwrap()].name;
1019        let version = env!("CARGO_PKG_VERSION");
1020        self.src.push_str(&format!(
1021            "#[unsafe(link_section = \"component-type:wit-bindgen:{version}:\
1022             {pkg}:{world_name}:{section_suffix}{opts_suffix}\")]\n"
1023        ));
1024
1025        let mut producers = wasm_metadata::Producers::empty();
1026        producers.add(
1027            "processed-by",
1028            env!("CARGO_PKG_NAME"),
1029            env!("CARGO_PKG_VERSION"),
1030        );
1031
1032        let component_type = wit_component::metadata::encode(
1033            resolve,
1034            world_id,
1035            wit_component::StringEncoding::UTF8,
1036            Some(&producers),
1037        )
1038        .unwrap();
1039
1040        self.src.push_str("#[doc(hidden)]\n");
1041        self.src.push_str("#[allow(clippy::octal_escapes)]\n");
1042        self.src.push_str(&format!(
1043            "pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; {}] = *b\"\\\n",
1044            component_type.len()
1045        ));
1046        let old_indent = self.src.set_indent(0);
1047        let mut line_length = 0;
1048        let s = self.src.as_mut_string();
1049        for byte in component_type.iter() {
1050            if line_length >= 80 {
1051                s.push_str("\\\n");
1052                line_length = 0;
1053            }
1054            match byte {
1055                b'\\' => {
1056                    s.push_str("\\\\");
1057                    line_length += 2;
1058                }
1059                b'"' => {
1060                    s.push_str("\\\"");
1061                    line_length += 2;
1062                }
1063                b if b.is_ascii_alphanumeric() || b.is_ascii_punctuation() => {
1064                    s.push(char::from(*byte));
1065                    line_length += 1;
1066                }
1067                0 => {
1068                    s.push_str("\\0");
1069                    line_length += 2;
1070                }
1071                _ => {
1072                    uwrite!(s, "\\x{:02x}", byte);
1073                    line_length += 4;
1074                }
1075            }
1076        }
1077
1078        self.src.push_str("\";\n");
1079        self.src.set_indent(old_indent);
1080
1081        if let Some(func_name) = func_name {
1082            let rt = self.runtime_path().to_string();
1083            uwriteln!(
1084                self.src,
1085                "
1086                #[inline(never)]
1087                #[doc(hidden)]
1088                pub fn {func_name}() {{
1089                    {rt}::maybe_link_cabi_realloc();
1090                }}
1091            ",
1092            );
1093        }
1094    }
1095
1096    fn is_async(
1097        &mut self,
1098        resolve: &Resolve,
1099        interface: Option<&WorldKey>,
1100        func: &Function,
1101        is_import: bool,
1102    ) -> bool {
1103        self.opts
1104            .async_
1105            .is_async(resolve, interface, func, is_import)
1106    }
1107
1108    fn should_return_self(
1109        &mut self,
1110        resolve: &Resolve,
1111        interface: Option<&WorldKey>,
1112        func: &Function,
1113        is_import: bool,
1114    ) -> Option<ChainingMode> {
1115        return self
1116            .opts
1117            .chainable_methods
1118            .should_be_chainable(resolve, interface, func, is_import);
1119    }
1120}
1121
1122impl WorldGenerator for RustWasm {
1123    fn preprocess(&mut self, resolve: &Resolve, world: WorldId) -> Result<()> {
1124        wit_bindgen_core::generated_preamble(&mut self.src_preamble, env!("CARGO_PKG_VERSION"));
1125
1126        // Render some generator options to assist with debugging and/or to help
1127        // recreate it if the original generation command is lost.
1128        uwriteln!(self.src_preamble, "// Options used:");
1129        if self.opts.std_feature {
1130            uwriteln!(self.src_preamble, "//   * std_feature");
1131        }
1132        if self.opts.raw_strings {
1133            uwriteln!(self.src_preamble, "//   * raw_strings");
1134        }
1135        if !self.opts.skip.is_empty() {
1136            uwriteln!(self.src_preamble, "//   * skip: {:?}", self.opts.skip);
1137        }
1138        if self.opts.stubs {
1139            uwriteln!(self.src_preamble, "//   * stubs");
1140        }
1141        if let Some(export_prefix) = &self.opts.export_prefix {
1142            uwriteln!(
1143                self.src_preamble,
1144                "//   * export_prefix: {:?}",
1145                export_prefix
1146            );
1147        }
1148        if let Some(runtime_path) = &self.opts.runtime_path {
1149            uwriteln!(self.src_preamble, "//   * runtime_path: {:?}", runtime_path);
1150        }
1151        if let Some(map_type) = &self.opts.map_type {
1152            uwriteln!(self.src_preamble, "//   * map_type: {:?}", map_type);
1153        }
1154        if let Some(bitflags_path) = &self.opts.bitflags_path {
1155            uwriteln!(
1156                self.src_preamble,
1157                "//   * bitflags_path: {:?}",
1158                bitflags_path
1159            );
1160        }
1161        if !matches!(self.opts.ownership, Ownership::Owning) {
1162            uwriteln!(
1163                self.src_preamble,
1164                "//   * ownership: {:?}",
1165                self.opts.ownership
1166            );
1167        }
1168        if !self.opts.additional_derive_attributes.is_empty() {
1169            uwriteln!(
1170                self.src_preamble,
1171                "//   * additional derives {:?}",
1172                self.opts.additional_derive_attributes
1173            );
1174        }
1175        if !self.opts.additional_derive_ignore.is_empty() {
1176            uwriteln!(
1177                self.src_preamble,
1178                "//   * additional derives ignored {:?}",
1179                self.opts.additional_derive_ignore
1180            );
1181        }
1182        for (selector, attr) in self.opts.additional_type_attributes.iter() {
1183            uwriteln!(
1184                self.src_preamble,
1185                "//   * additional type attribute {selector:?} = {attr:?}"
1186            );
1187        }
1188        for (selector, attr) in self.opts.additional_member_attributes.iter() {
1189            uwriteln!(
1190                self.src_preamble,
1191                "//   * additional member attribute {selector:?} = {attr:?}"
1192            );
1193        }
1194        for (k, v) in self.opts.with.iter() {
1195            uwriteln!(self.src_preamble, "//   * with {k:?} = {v}");
1196        }
1197        if let Some(type_section_suffix) = &self.opts.type_section_suffix {
1198            uwriteln!(
1199                self.src_preamble,
1200                "//   * type_section_suffix: {:?}",
1201                type_section_suffix
1202            );
1203        }
1204        if let Some(default) = &self.opts.default_bindings_module {
1205            uwriteln!(
1206                self.src_preamble,
1207                "//   * default-bindings-module: {default:?}"
1208            );
1209        }
1210        if self.opts.disable_run_ctors_once_workaround {
1211            uwriteln!(
1212                self.src_preamble,
1213                "//   * disable-run-ctors-once-workaround"
1214            );
1215        }
1216        if self.opts.merge_structurally_equal_types() {
1217            uwriteln!(self.src_preamble, "//   * merge_structurally_equal_types");
1218        }
1219        if let Some(s) = &self.opts.export_macro_name {
1220            uwriteln!(self.src_preamble, "//   * export-macro-name: {s}");
1221        }
1222        if self.opts.pub_export_macro {
1223            uwriteln!(self.src_preamble, "//   * pub-export-macro");
1224        }
1225        if self.opts.generate_unused_types {
1226            uwriteln!(self.src_preamble, "//   * generate_unused_types");
1227        }
1228        if self.opts.disable_custom_section_link_helpers {
1229            uwriteln!(
1230                self.src_preamble,
1231                "//   * disable_custom_section_link_helpers"
1232            );
1233        }
1234        for opt in self.opts.async_.debug_opts() {
1235            uwriteln!(self.src_preamble, "//   * async: {opt}");
1236        }
1237        for opt in self.opts.chainable_methods.debug_opts() {
1238            uwriteln!(self.src_preamble, "//   * chainable-methods: {opt}");
1239        }
1240        self.types.analyze(resolve);
1241        self.types.collect_equal_types(resolve, world, &|a| {
1242            // If `--merge-structurally-equal-types` is enabled then any type
1243            // anywhere can be generated as a type alias to anything else.
1244            if self.opts.merge_structurally_equal_types() {
1245                return true;
1246            }
1247
1248            match resolve.types[a].kind {
1249                // These types are all defined with `type Foo = ...` in Rust
1250                // since Rust either has native representations or they live in
1251                // libraries or similar.
1252                TypeDefKind::Type(_)
1253                | TypeDefKind::Handle(_)
1254                | TypeDefKind::List(_)
1255                | TypeDefKind::Tuple(_)
1256                | TypeDefKind::Option(_)
1257                | TypeDefKind::Result(_)
1258                | TypeDefKind::Future(_)
1259                | TypeDefKind::Stream(_)
1260                | TypeDefKind::Map(..)
1261                | TypeDefKind::FixedLengthList(..) => true,
1262
1263                // These types are all defined with fresh new types defined
1264                // in generated bindings and thus can't alias some other
1265                // existing type.
1266                TypeDefKind::Record(_)
1267                | TypeDefKind::Variant(_)
1268                | TypeDefKind::Enum(_)
1269                | TypeDefKind::Flags(_)
1270                | TypeDefKind::Resource
1271                | TypeDefKind::Unknown => false,
1272            }
1273        });
1274        self.world = Some(world);
1275
1276        let world = &resolve.worlds[world];
1277        // Specify that all imports local to the world's package should be
1278        // generated
1279        for (key, item) in world.imports.iter() {
1280            if let WorldItem::Interface { id, .. } = item {
1281                if resolve.interfaces[*id].package == world.package {
1282                    let name = resolve.name_world_key(key);
1283                    if self.with.get(&name).is_none() {
1284                        self.with.insert(name, TypeGeneration::Generate);
1285                    }
1286                }
1287            }
1288        }
1289
1290        for item in world.exports.values() {
1291            let WorldItem::Interface { id, .. } = item else {
1292                continue;
1293            };
1294            for id in resolve.interfaces[*id].types.values().copied() {
1295                let TypeDefKind::Resource = &resolve.types[id].kind else {
1296                    continue;
1297                };
1298                assert!(self.exported_resources.insert(id));
1299            }
1300        }
1301
1302        for (k, v) in self.opts.with.iter() {
1303            self.with.insert(k.clone(), v.clone().into());
1304        }
1305        self.with.generate_by_default = self.opts.generate_all;
1306        for (key, item) in world.imports.iter() {
1307            if let WorldItem::Interface { id, .. } = item {
1308                self.name_interface(resolve, *id, &key, false)?;
1309            }
1310        }
1311        for (key, item) in world.exports.iter() {
1312            if let WorldItem::Interface { id, .. } = item {
1313                self.name_interface(resolve, *id, &key, true)?;
1314            }
1315        }
1316        Ok(())
1317    }
1318
1319    fn import_interface(
1320        &mut self,
1321        resolve: &Resolve,
1322        name: &WorldKey,
1323        id: InterfaceId,
1324        _files: &mut Files,
1325    ) -> Result<()> {
1326        let mut to_define = Vec::new();
1327        for (name, ty_id) in resolve.interfaces[id].types.iter() {
1328            let full_name = full_wit_type_name(resolve, *ty_id);
1329            if let Some(type_gen) = self.with.get(&full_name) {
1330                // skip type definition generation for remapped types
1331                if type_gen.generated() {
1332                    to_define.push((name, ty_id));
1333                }
1334            } else {
1335                to_define.push((name, ty_id));
1336            }
1337            self.generated_types.insert(full_name);
1338        }
1339
1340        let wasm_import_module = resolve.name_world_key(name);
1341        let mut r#gen = self.interface(
1342            Identifier::Interface(id, name),
1343            &wasm_import_module,
1344            resolve,
1345            true,
1346        )?;
1347        let (snake, module_path) = r#gen.start_append_submodule(name);
1348        if r#gen.r#gen.interface_names[&id].remapped {
1349            return Ok(());
1350        }
1351
1352        for (name, ty_id) in to_define {
1353            r#gen.define_type(&name, *ty_id);
1354        }
1355
1356        r#gen.generate_imports(resolve.interfaces[id].functions.values(), Some(name));
1357
1358        let docs = &resolve.interfaces[id].docs;
1359
1360        r#gen.finish_append_submodule(&snake, module_path, docs);
1361
1362        Ok(())
1363    }
1364
1365    fn import_funcs(
1366        &mut self,
1367        resolve: &Resolve,
1368        world: WorldId,
1369        funcs: &[(&str, &Function)],
1370        _files: &mut Files,
1371    ) -> Result<()> {
1372        self.import_funcs_called = true;
1373
1374        let mut r#gen = self.interface(Identifier::World(world), "$root", resolve, true)?;
1375
1376        r#gen.generate_imports(funcs.iter().map(|(_, func)| *func), None);
1377
1378        let src = r#gen.finish();
1379        self.src.push_str(&src);
1380        Ok(())
1381    }
1382
1383    fn export_interface(
1384        &mut self,
1385        resolve: &Resolve,
1386        name: &WorldKey,
1387        id: InterfaceId,
1388        _files: &mut Files,
1389    ) -> Result<()> {
1390        let mut to_define = Vec::new();
1391        for (ty_name, ty_id) in resolve.interfaces[id].types.iter() {
1392            let full_name = full_wit_type_name(resolve, *ty_id);
1393            to_define.push((ty_name, ty_id));
1394            self.generated_types.insert(full_name);
1395        }
1396
1397        let wasm_import_module = format!("[export]{}", resolve.name_world_key(name));
1398        let mut r#gen = self.interface(
1399            Identifier::Interface(id, name),
1400            &wasm_import_module,
1401            resolve,
1402            false,
1403        )?;
1404        let (snake, module_path) = r#gen.start_append_submodule(name);
1405        if r#gen.r#gen.interface_names[&id].remapped {
1406            return Ok(());
1407        }
1408
1409        for (ty_name, ty_id) in to_define {
1410            r#gen.define_type(&ty_name, *ty_id);
1411        }
1412
1413        let macro_name =
1414            r#gen.generate_exports(Some((id, name)), resolve.interfaces[id].functions.values())?;
1415
1416        let docs = &resolve.interfaces[id].docs;
1417
1418        r#gen.finish_append_submodule(&snake, module_path, docs);
1419        self.export_macros
1420            .push((macro_name, self.interface_names[&id].path.clone()));
1421
1422        if self.opts.stubs {
1423            let world_id = self.world.unwrap();
1424            let mut r#gen = self.interface(
1425                Identifier::World(world_id),
1426                &wasm_import_module,
1427                resolve,
1428                false,
1429            )?;
1430            r#gen.generate_stub(Some((id, name)), resolve.interfaces[id].functions.values());
1431            let stub = r#gen.finish();
1432            self.src.push_str(&stub);
1433        }
1434        Ok(())
1435    }
1436
1437    fn export_funcs(
1438        &mut self,
1439        resolve: &Resolve,
1440        world: WorldId,
1441        funcs: &[(&str, &Function)],
1442        _files: &mut Files,
1443    ) -> Result<()> {
1444        let mut r#gen =
1445            self.interface(Identifier::World(world), "[export]$root", resolve, false)?;
1446        let macro_name = r#gen.generate_exports(None, funcs.iter().map(|f| f.1))?;
1447        let src = r#gen.finish();
1448        self.src.push_str(&src);
1449        self.export_macros.push((macro_name, String::new()));
1450
1451        if self.opts.stubs {
1452            let mut r#gen =
1453                self.interface(Identifier::World(world), "[export]$root", resolve, false)?;
1454            r#gen.generate_stub(None, funcs.iter().map(|f| f.1));
1455            let stub = r#gen.finish();
1456            self.src.push_str(&stub);
1457        }
1458        Ok(())
1459    }
1460
1461    fn import_types(
1462        &mut self,
1463        resolve: &Resolve,
1464        world: WorldId,
1465        types: &[(&str, TypeId)],
1466        _files: &mut Files,
1467    ) -> Result<()> {
1468        let mut to_define = Vec::new();
1469        for (name, ty_id) in types {
1470            let full_name = full_wit_type_name(resolve, *ty_id);
1471            if let Some(type_gen) = self.with.get(&full_name) {
1472                // skip type definition generation for remapped types
1473                if type_gen.generated() {
1474                    to_define.push((name, ty_id));
1475                }
1476            } else {
1477                to_define.push((name, ty_id));
1478            }
1479            self.generated_types.insert(full_name);
1480        }
1481        let mut r#gen = self.interface(Identifier::World(world), "$root", resolve, true)?;
1482        for (name, ty) in to_define {
1483            r#gen.define_type(name, *ty);
1484        }
1485        let src = r#gen.finish();
1486        self.src.push_str(&src);
1487        Ok(())
1488    }
1489
1490    fn finish_imports(
1491        &mut self,
1492        resolve: &Resolve,
1493        world: WorldId,
1494        files: &mut Files,
1495    ) -> Result<()> {
1496        if !self.import_funcs_called {
1497            // We call `import_funcs` even if the world doesn't import any
1498            // functions since one of the side effects of that method is to
1499            // generate `struct`s for any imported resources.
1500            self.import_funcs(resolve, world, &[], files)?;
1501        }
1502        Ok(())
1503    }
1504
1505    fn finish(&mut self, resolve: &Resolve, world: WorldId, files: &mut Files) -> Result<()> {
1506        let name = &resolve.worlds[world].name;
1507
1508        let imports = mem::take(&mut self.import_modules);
1509        self.emit_modules(imports);
1510        let exports = mem::take(&mut self.export_modules);
1511        self.emit_modules(exports);
1512
1513        self.finish_runtime_module();
1514        self.finish_export_macro(resolve, world);
1515
1516        // This is a bit tricky, but we sometimes want to "split" the `world` in
1517        // two and only encode the imports here.
1518        //
1519        // First, a primer. Each invocation of `generate!` has a WIT world as
1520        // input. This is one of the first steps in the build process as wasm
1521        // hasn't even been produced yet. One of the later stages of the build
1522        // process will be to emit a component, currently through the
1523        // `wit-component` crate. That crate relies on custom sections being
1524        // present to describe what WIT worlds were present in the wasm binary.
1525        //
1526        // Additionally a `generate!` macro is not the only thing in a binary.
1527        // There might be multiple `generate!` macros, perhaps even across
1528        // different languages. To handle all this `wit-component` will decode
1529        // each custom section and "union" everything together. Unioning in
1530        // general should work so long as everything has the same structure and
1531        // came from the same source.
1532        //
1533        // The problem here is that if `pub_export_macros` is turned on, meaning
1534        // that the macros are supposed to be used across crates, then neither
1535        // the imports nor the exports of this world are guaranteed to be used.
1536        // For imports that's ok because `wit-component` will drop any unused
1537        // imports automatically. For exports that's a problem because
1538        // `wit-component` unconditionally looks for a definition for all
1539        // exports.
1540        //
1541        // When `pub_export_macros` is turned on, and cross-crate usage of the
1542        // macro is expected, this is solved by emitting two custom sections:
1543        //
1544        // 1. The first section emitted here only has the imports of the world.
1545        //    This slimmed down world should be able to be unioned with the
1546        //    first world trivially and will be GC'd by `wit-component` if not
1547        //    used.
1548        // 2. The second section is emitted as part of the generated `export!`
1549        //    macro invocation. That world has all the export information as
1550        //    well as all the import information.
1551        //
1552        // In the end this is hoped to ensure that usage of crates like `wasi`
1553        // don't accidentally try to export things, for example.
1554        let mut resolve_copy;
1555        let (resolve_to_encode, world_to_encode) = if self.opts.pub_export_macro {
1556            resolve_copy = resolve.clone();
1557            let world_copy = resolve_copy.worlds.alloc(World {
1558                exports: Default::default(),
1559                name: format!("{name}-with-all-of-its-exports-removed"),
1560                ..resolve.worlds[world].clone()
1561            });
1562            (&resolve_copy, world_copy)
1563        } else {
1564            (resolve, world)
1565        };
1566        self.emit_custom_section(
1567            resolve_to_encode,
1568            world_to_encode,
1569            "encoded world",
1570            if self.opts.disable_custom_section_link_helpers {
1571                None
1572            } else {
1573                Some("__link_custom_section_describing_imports")
1574            },
1575        );
1576
1577        if self.opts.stubs {
1578            self.src.push_str("\n#[derive(Debug)]\npub struct Stub;\n");
1579        }
1580
1581        let mut src = mem::take(&mut self.src);
1582        if self.opts.format {
1583            let syntax_tree = syn::parse_file(src.as_str()).unwrap();
1584            *src.as_mut_string() = prettyplease::unparse(&syntax_tree);
1585        }
1586
1587        // Prepend the preamble. We do this after formatting because
1588        // `syn::parse_file` + `prettyplease::unparse` does not preserve comments.
1589        let src_preamble = mem::take(&mut self.src_preamble);
1590        *src.as_mut_string() = format!("{}{}", src_preamble.as_str(), src.as_str());
1591
1592        let module_name = name.to_snake_case();
1593        files.push(&format!("{module_name}.rs"), src.as_bytes());
1594
1595        let remapped_keys = self
1596            .with
1597            .iter()
1598            .map(|(k, _)| k)
1599            .cloned()
1600            .collect::<HashSet<String>>();
1601
1602        let mut unused_keys = remapped_keys
1603            .difference(&self.generated_types)
1604            .collect::<Vec<&String>>();
1605
1606        unused_keys.sort();
1607
1608        if !unused_keys.is_empty() {
1609            bail!("unused remappings provided via `with`: {unused_keys:?}");
1610        }
1611
1612        let mut unused_selectors = self
1613            .opts
1614            .additional_type_attributes
1615            .iter()
1616            .map(|(sel, _)| sel)
1617            .filter(|sel| !self.used_type_attr_selectors.contains(*sel))
1618            .chain(
1619                self.opts
1620                    .additional_member_attributes
1621                    .iter()
1622                    .map(|(sel, _)| sel)
1623                    .filter(|sel| !self.used_member_attr_selectors.contains(*sel)),
1624            )
1625            .collect::<Vec<_>>();
1626        unused_selectors.sort();
1627        unused_selectors.dedup();
1628        if !unused_selectors.is_empty() {
1629            bail!(
1630                "unused selectors provided via `additional_type_attributes` / \
1631                 `additional_member_attributes`: {unused_selectors:?}"
1632            );
1633        }
1634
1635        // Error about unused async configuration to help catch configuration
1636        // errors.
1637        self.opts.async_.ensure_all_used()?;
1638        self.opts.chainable_methods.ensure_all_used()?;
1639
1640        Ok(())
1641    }
1642}
1643
1644pub(crate) fn compute_module_path(
1645    name: &WorldKey,
1646    resolve: &Resolve,
1647    is_export: bool,
1648) -> Vec<String> {
1649    let mut path = Vec::new();
1650    if is_export {
1651        path.push("exports".to_string());
1652    }
1653    match name {
1654        WorldKey::Name(name) => {
1655            path.push(to_rust_ident(name));
1656        }
1657        WorldKey::Interface(id) => {
1658            let iface = &resolve.interfaces[*id];
1659            let pkg = iface.package.unwrap();
1660            let pkgname = resolve.packages[pkg].name.clone();
1661            path.push(to_rust_ident(&pkgname.namespace));
1662            path.push(name_package_module(resolve, pkg));
1663            path.push(to_rust_ident(iface.name.as_ref().unwrap()));
1664        }
1665    }
1666    path
1667}
1668
1669enum Identifier<'a> {
1670    World(WorldId),
1671    Interface(InterfaceId, &'a WorldKey),
1672    StreamOrFuturePayload,
1673}
1674
1675fn group_by_resource<'a>(
1676    funcs: impl Iterator<Item = &'a Function>,
1677) -> BTreeMap<Option<TypeId>, Vec<&'a Function>> {
1678    let mut by_resource = BTreeMap::<_, Vec<_>>::new();
1679    for func in funcs {
1680        by_resource
1681            .entry(func.kind.resource())
1682            .or_default()
1683            .push(func);
1684    }
1685    by_resource
1686}
1687
1688#[derive(Default, Debug, Clone, Copy)]
1689#[cfg_attr(
1690    feature = "serde",
1691    derive(serde::Deserialize),
1692    serde(rename_all = "kebab-case")
1693)]
1694pub enum Ownership {
1695    /// Generated types will be composed entirely of owning fields, regardless
1696    /// of whether they are used as parameters to imports or not.
1697    #[default]
1698    Owning,
1699
1700    /// Generated types used as parameters to imports will be "deeply
1701    /// borrowing", i.e. contain references rather than owned values when
1702    /// applicable.
1703    Borrowing {
1704        /// Whether or not to generate "duplicate" type definitions for a single
1705        /// WIT type if necessary, for example if it's used as both an import
1706        /// and an export, or if it's used both as a parameter to an import and
1707        /// a return value from an import.
1708        duplicate_if_necessary: bool,
1709    },
1710}
1711
1712impl FromStr for Ownership {
1713    type Err = String;
1714
1715    fn from_str(s: &str) -> Result<Self, Self::Err> {
1716        match s {
1717            "owning" => Ok(Self::Owning),
1718            "borrowing" => Ok(Self::Borrowing {
1719                duplicate_if_necessary: false,
1720            }),
1721            "borrowing-duplicate-if-necessary" => Ok(Self::Borrowing {
1722                duplicate_if_necessary: true,
1723            }),
1724            _ => Err(format!(
1725                "unrecognized ownership: `{s}`; \
1726                 expected `owning`, `borrowing`, or `borrowing-duplicate-if-necessary`"
1727            )),
1728        }
1729    }
1730}
1731
1732impl fmt::Display for Ownership {
1733    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1734        f.write_str(match self {
1735            Ownership::Owning => "owning",
1736            Ownership::Borrowing {
1737                duplicate_if_necessary: false,
1738            } => "borrowing",
1739            Ownership::Borrowing {
1740                duplicate_if_necessary: true,
1741            } => "borrowing-duplicate-if-necessary",
1742        })
1743    }
1744}
1745
1746/// Options for with "with" remappings.
1747#[derive(Debug, Clone)]
1748#[cfg_attr(
1749    feature = "serde",
1750    derive(serde::Deserialize),
1751    serde(rename_all = "kebab-case")
1752)]
1753pub enum WithOption {
1754    Path(String),
1755    Generate,
1756}
1757
1758impl std::fmt::Display for WithOption {
1759    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1760        match self {
1761            WithOption::Path(p) => f.write_fmt(format_args!("\"{p}\"")),
1762            WithOption::Generate => f.write_str("generate"),
1763        }
1764    }
1765}
1766
1767impl From<WithOption> for TypeGeneration {
1768    fn from(opt: WithOption) -> Self {
1769        match opt {
1770            WithOption::Path(p) => TypeGeneration::Remap(p),
1771            WithOption::Generate => TypeGeneration::Generate,
1772        }
1773    }
1774}
1775
1776#[derive(Default)]
1777struct FnSig {
1778    async_: bool,
1779    unsafe_: bool,
1780    private: bool,
1781    use_item_name: bool,
1782    generics: Option<String>,
1783    self_arg: Option<String>,
1784    self_is_first_param: bool,
1785}
1786
1787impl FnSig {
1788    fn update_for_func(&mut self, func: &Function, return_self: Option<ChainingMode>) {
1789        if let FunctionKind::Method(_) | FunctionKind::AsyncMethod(_) = &func.kind {
1790            self.self_arg = Some(
1791                match return_self {
1792                    Some(ChainingMode::Owning) => "self",
1793                    _ => "&self",
1794                }
1795                .into(),
1796            );
1797            self.self_is_first_param = true;
1798        }
1799    }
1800}
1801
1802pub fn to_rust_ident(name: &str) -> String {
1803    match name {
1804        // Escape Rust keywords.
1805        // Source: https://doc.rust-lang.org/reference/keywords.html
1806        "as" => "as_".into(),
1807        "break" => "break_".into(),
1808        "const" => "const_".into(),
1809        "continue" => "continue_".into(),
1810        "crate" => "crate_".into(),
1811        "else" => "else_".into(),
1812        "enum" => "enum_".into(),
1813        "extern" => "extern_".into(),
1814        "false" => "false_".into(),
1815        "fn" => "fn_".into(),
1816        "for" => "for_".into(),
1817        "if" => "if_".into(),
1818        "impl" => "impl_".into(),
1819        "in" => "in_".into(),
1820        "let" => "let_".into(),
1821        "loop" => "loop_".into(),
1822        "match" => "match_".into(),
1823        "mod" => "mod_".into(),
1824        "move" => "move_".into(),
1825        "mut" => "mut_".into(),
1826        "pub" => "pub_".into(),
1827        "ref" => "ref_".into(),
1828        "return" => "return_".into(),
1829        "self" => "self_".into(),
1830        "static" => "static_".into(),
1831        "struct" => "struct_".into(),
1832        "super" => "super_".into(),
1833        "trait" => "trait_".into(),
1834        "true" => "true_".into(),
1835        "type" => "type_".into(),
1836        "unsafe" => "unsafe_".into(),
1837        "use" => "use_".into(),
1838        "where" => "where_".into(),
1839        "while" => "while_".into(),
1840        "async" => "async_".into(),
1841        "await" => "await_".into(),
1842        "dyn" => "dyn_".into(),
1843        "abstract" => "abstract_".into(),
1844        "become" => "become_".into(),
1845        "box" => "box_".into(),
1846        "do" => "do_".into(),
1847        "final" => "final_".into(),
1848        "macro" => "macro_".into(),
1849        "override" => "override_".into(),
1850        "priv" => "priv_".into(),
1851        "typeof" => "typeof_".into(),
1852        "unsized" => "unsized_".into(),
1853        "virtual" => "virtual_".into(),
1854        "yield" => "yield_".into(),
1855        "try" => "try_".into(),
1856        s => s.to_snake_case(),
1857    }
1858}
1859
1860fn to_upper_camel_case(name: &str) -> String {
1861    match name {
1862        // The name "Guest" is reserved for traits generated by exported
1863        // interfaces, so remap types defined in wit to something else.
1864        "guest" => "Guest_".to_string(),
1865        s => s.to_upper_camel_case(),
1866    }
1867}
1868
1869fn wasm_type(ty: WasmType) -> &'static str {
1870    match ty {
1871        WasmType::I32 => "i32",
1872        WasmType::I64 => "i64",
1873        WasmType::F32 => "f32",
1874        WasmType::F64 => "f64",
1875        WasmType::Pointer => "*mut u8",
1876        WasmType::Length => "usize",
1877
1878        // `PointerOrI64` can hold either a `u64` or a pointer with provenance.
1879        // Neither a `u64` nor a pointer type can portably do both, so we use
1880        // `MaybeUninit<u64>`, since `MaybeUninit` is [documented] to preserve
1881        // provenance.
1882        // [documented]: https://github.com/rust-lang/rfcs/blob/master/text/3559-rust-has-provenance.md#reference-level-explanation
1883        WasmType::PointerOrI64 => "::core::mem::MaybeUninit::<u64>",
1884    }
1885}
1886
1887fn declare_import(
1888    wasm_import_module: &str,
1889    wasm_import_name: &str,
1890    rust_name: &str,
1891    params: &[WasmType],
1892    results: &[WasmType],
1893) -> String {
1894    let mut sig = "(".to_owned();
1895    for param in params.iter() {
1896        sig.push_str("_: ");
1897        sig.push_str(wasm_type(*param));
1898        sig.push_str(", ");
1899    }
1900    sig.push(')');
1901    assert!(results.len() < 2);
1902    for result in results.iter() {
1903        sig.push_str(" -> ");
1904        sig.push_str(wasm_type(*result));
1905    }
1906    format!(
1907        "
1908            #[cfg(target_arch = \"wasm32\")]
1909            #[link(wasm_import_module = \"{wasm_import_module}\")]
1910            unsafe extern \"C\" {{
1911                #[link_name = \"{wasm_import_name}\"]
1912                fn {rust_name}{sig};
1913            }}
1914
1915            #[cfg(not(target_arch = \"wasm32\"))]
1916            unsafe extern \"C\" fn {rust_name}{sig} {{ unreachable!() }}
1917        "
1918    )
1919}
1920
1921fn int_repr(repr: Int) -> &'static str {
1922    match repr {
1923        Int::U8 => "u8",
1924        Int::U16 => "u16",
1925        Int::U32 => "u32",
1926        Int::U64 => "u64",
1927    }
1928}
1929
1930fn bitcast(casts: &[Bitcast], operands: &[String], results: &mut Vec<String>) {
1931    for (cast, operand) in casts.iter().zip(operands) {
1932        results.push(perform_cast(operand, cast));
1933    }
1934}
1935
1936fn perform_cast(operand: &str, cast: &Bitcast) -> String {
1937    match cast {
1938        Bitcast::None => operand.to_owned(),
1939        Bitcast::I32ToI64 => format!("i64::from({operand})"),
1940        Bitcast::F32ToI32 => format!("({operand}).to_bits() as i32"),
1941        Bitcast::F64ToI64 => format!("({operand}).to_bits() as i64"),
1942        Bitcast::I64ToI32 => format!("{operand} as i32"),
1943        Bitcast::I32ToF32 => format!("f32::from_bits({operand} as u32)"),
1944        Bitcast::I64ToF64 => format!("f64::from_bits({operand} as u64)"),
1945        Bitcast::F32ToI64 => format!("i64::from(({operand}).to_bits())"),
1946        Bitcast::I64ToF32 => format!("f32::from_bits({operand} as u32)"),
1947
1948        // Convert an `i64` into a `MaybeUninit<u64>`.
1949        Bitcast::I64ToP64 => format!("::core::mem::MaybeUninit::new({operand} as u64)"),
1950        // Convert a `MaybeUninit<u64>` holding an `i64` value back into
1951        // the `i64` value.
1952        Bitcast::P64ToI64 => format!("{operand}.assume_init() as i64"),
1953
1954        // Convert a pointer value into a `MaybeUninit<u64>`.
1955        Bitcast::PToP64 => {
1956            format!(
1957                "{{
1958                        let mut t = ::core::mem::MaybeUninit::<u64>::uninit();
1959                        t.as_mut_ptr().cast::<*mut u8>().write({operand});
1960                        t
1961                    }}"
1962            )
1963        }
1964        // Convert a `MaybeUninit<u64>` holding a pointer value back into
1965        // the pointer value.
1966        Bitcast::P64ToP => {
1967            format!("{operand}.as_ptr().cast::<*mut u8>().read()")
1968        }
1969        // Convert an `i32` or a `usize` into a pointer.
1970        Bitcast::I32ToP | Bitcast::LToP => {
1971            format!("{operand} as *mut u8")
1972        }
1973        // Convert a pointer or length holding an `i32` value back into the `i32`.
1974        Bitcast::PToI32 | Bitcast::LToI32 => {
1975            format!("{operand} as i32")
1976        }
1977        // Convert an `i32`, `i64`, or pointer holding a `usize` value back into the `usize`.
1978        Bitcast::I32ToL | Bitcast::I64ToL | Bitcast::PToL => {
1979            format!("{operand} as usize")
1980        }
1981        // Convert a `usize` into an `i64`.
1982        Bitcast::LToI64 => {
1983            format!("{operand} as i64")
1984        }
1985        Bitcast::Sequence(sequence) => {
1986            let [first, second] = &**sequence;
1987            perform_cast(&perform_cast(operand, first), second)
1988        }
1989    }
1990}
1991
1992enum RustFlagsRepr {
1993    U8,
1994    U16,
1995    U32,
1996    U64,
1997    U128,
1998}
1999
2000impl RustFlagsRepr {
2001    fn new(f: &Flags) -> RustFlagsRepr {
2002        match f.repr() {
2003            FlagsRepr::U8 => RustFlagsRepr::U8,
2004            FlagsRepr::U16 => RustFlagsRepr::U16,
2005            FlagsRepr::U32(1) => RustFlagsRepr::U32,
2006            FlagsRepr::U32(2) => RustFlagsRepr::U64,
2007            FlagsRepr::U32(3 | 4) => RustFlagsRepr::U128,
2008            FlagsRepr::U32(n) => panic!("unsupported number of flags: {}", n * 32),
2009        }
2010    }
2011}
2012
2013impl fmt::Display for RustFlagsRepr {
2014    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2015        match self {
2016            RustFlagsRepr::U8 => "u8".fmt(f),
2017            RustFlagsRepr::U16 => "u16".fmt(f),
2018            RustFlagsRepr::U32 => "u32".fmt(f),
2019            RustFlagsRepr::U64 => "u64".fmt(f),
2020            RustFlagsRepr::U128 => "u128".fmt(f),
2021        }
2022    }
2023}
2024
2025#[derive(Debug, Clone)]
2026pub struct MissingWith(pub String);
2027
2028impl fmt::Display for MissingWith {
2029    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2030        write!(f, "missing `with` mapping for the key `{}`", self.0)
2031    }
2032}
2033
2034impl std::error::Error for MissingWith {}
2035
2036// bail!("no remapping found for {with_name:?} - use the `generate!` macro's `with` option to force the interface to be generated or specify where it is already defined:
2037// ```
2038// with: {{\n\t{with_name:?}: generate\n}}
2039// ```")
2040
2041/// Returns the full WIT type name with fully qualified interface name
2042fn full_wit_type_name(resolve: &Resolve, id: TypeId) -> String {
2043    let id = dealias(resolve, id);
2044    let type_def = &resolve.types[id];
2045    let interface_name = match type_def.owner {
2046        TypeOwner::World(w) => Some(resolve.worlds[w].name.clone()),
2047        TypeOwner::Interface(id) => resolve.id_of(id),
2048        TypeOwner::None => None,
2049    };
2050    match interface_name {
2051        Some(interface_name) => format!("{}/{}", interface_name, type_def.name.clone().unwrap()),
2052        None => type_def.name.clone().unwrap(),
2053    }
2054}
2055
2056enum ConstructorReturnType {
2057    /// Resource constructor is infallible. E.g.:
2058    /// ```wit
2059    /// resource R {
2060    ///    constructor(..);
2061    /// }
2062    /// ```
2063    Self_,
2064
2065    /// Resource constructor is fallible. E.g.:
2066    /// ```wit
2067    /// resource R {
2068    ///    constructor(..) -> result<R, err>;
2069    /// }
2070    /// ```
2071    Result { err: Option<Type> },
2072}
2073
2074fn classify_constructor_return_type(
2075    resolve: &Resolve,
2076    resource_id: TypeId,
2077    result: &Option<Type>,
2078) -> ConstructorReturnType {
2079    fn classify(
2080        resolve: &Resolve,
2081        resource_id: TypeId,
2082        result: &Option<Type>,
2083    ) -> Option<ConstructorReturnType> {
2084        let resource_id = dealias(resolve, resource_id);
2085        let typedef = match result.as_ref()? {
2086            Type::Id(id) => &resolve.types[dealias(resolve, *id)],
2087            _ => return None,
2088        };
2089
2090        match &typedef.kind {
2091            TypeDefKind::Handle(Handle::Own(id)) if dealias(resolve, *id) == resource_id => {
2092                Some(ConstructorReturnType::Self_)
2093            }
2094            TypeDefKind::Result(Result_ { ok, err }) => {
2095                let ok_typedef = match ok.as_ref()? {
2096                    Type::Id(id) => &resolve.types[dealias(resolve, *id)],
2097                    _ => return None,
2098                };
2099
2100                match &ok_typedef.kind {
2101                    TypeDefKind::Handle(Handle::Own(id))
2102                        if dealias(resolve, *id) == resource_id =>
2103                    {
2104                        Some(ConstructorReturnType::Result { err: *err })
2105                    }
2106                    _ => None,
2107                }
2108            }
2109            _ => None,
2110        }
2111    }
2112
2113    classify(resolve, resource_id, result).expect("invalid constructor")
2114}