Skip to main content

wit_bindgen_cpp/
lib.rs

1use anyhow::{Result, bail};
2use heck::{ToPascalCase, ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase};
3use indexmap::{IndexMap, IndexSet};
4use std::{
5    collections::{HashMap, HashSet},
6    fmt::{self, Display, Write as FmtWrite},
7    io::{Read, Write},
8    path::PathBuf,
9    process::{Command, Stdio},
10    str::FromStr,
11};
12use symbol_name::{make_external_component, make_external_symbol};
13use wit_bindgen_c::to_c_ident;
14use wit_bindgen_core::{
15    Files, InterfaceGenerator, Source, Types, WorldGenerator,
16    abi::{self, AbiVariant, Bindgen, Bitcast, LiftLower, WasmSignature, WasmType},
17    name_package_module, uwrite, uwriteln,
18    wit_parser::{
19        Alignment, ArchitectureSize, Docs, Function, FunctionKind, Handle, Int, InterfaceId, Param,
20        Resolve, SizeAlign, Stability, Type, TypeDef, TypeDefKind, TypeId, TypeOwner, WorldId,
21        WorldKey,
22    },
23};
24use wit_parser::TypeIdVisitor;
25
26// mod wamr;
27mod symbol_name;
28
29pub const RESOURCE_IMPORT_BASE_CLASS_NAME: &str = "ResourceImportBase";
30pub const RESOURCE_EXPORT_BASE_CLASS_NAME: &str = "ResourceExportBase";
31pub const RESOURCE_TABLE_NAME: &str = "ResourceTable";
32pub const OWNED_CLASS_NAME: &str = "Owned";
33pub const POINTER_SIZE_EXPRESSION: &str = "sizeof(void*)";
34
35type CppType = String;
36
37#[derive(Clone, Copy, Debug)]
38enum Flavor {
39    Argument(AbiVariant),
40    Result(AbiVariant),
41    InStruct,
42    BorrowedArgument,
43}
44
45#[derive(Default)]
46struct HighlevelSignature {
47    /// this is a constructor or destructor without a written type
48    // implicit_result: bool, -> empty result
49    const_member: bool,
50    static_member: bool,
51    result: CppType,
52    arguments: Vec<(String, CppType)>,
53    name: String,
54    namespace: Vec<String>,
55    implicit_self: bool,
56    post_return: bool,
57}
58
59// follows https://google.github.io/styleguide/cppguide.html
60
61#[derive(Default)]
62struct Includes {
63    needs_vector: bool,
64    needs_expected: bool,
65    needs_string: bool,
66    needs_string_view: bool,
67    needs_optional: bool,
68    needs_cstring: bool,
69    needs_imported_resources: bool,
70    needs_exported_resources: bool,
71    needs_variant: bool,
72    needs_tuple: bool,
73    needs_assert: bool,
74    needs_bit: bool,
75    needs_span: bool,
76    // needs wit types
77    needs_wit: bool,
78    needs_memory: bool,
79    needs_array: bool,
80}
81
82#[derive(Default)]
83struct SourceWithState {
84    src: Source,
85    namespace: Vec<String>,
86}
87
88#[derive(Eq, Hash, PartialEq, Clone, Copy, Debug)]
89enum Direction {
90    Import,
91    Export,
92}
93
94#[derive(Default)]
95struct Cpp {
96    opts: Opts,
97    c_src: SourceWithState,
98    h_src: SourceWithState,
99    c_src_head: Source,
100    extern_c_decls: Source,
101    dependencies: Includes,
102    includes: Vec<String>,
103    world: String,
104    world_id: Option<WorldId>,
105    imported_interfaces: HashSet<InterfaceId>,
106    instance_names: HashMap<InterfaceId, String>,
107    user_class_files: HashMap<String, String>,
108    defined_types: HashSet<(Vec<String>, String)>,
109    types: Types,
110
111    // needed for symmetric disambiguation
112    interface_prefixes: HashMap<(Direction, WorldKey), String>,
113    import_prefix: Option<String>,
114}
115
116#[cfg(feature = "clap")]
117fn parse_with(s: &str) -> Result<(String, String), String> {
118    let (k, v) = s.split_once('=').ok_or_else(|| {
119        format!("expected string of form `<key>=<value>[,<key>=<value>...]`; got `{s}`")
120    })?;
121    Ok((k.to_string(), v.to_string()))
122}
123
124#[derive(Default, Debug, Clone)]
125#[cfg_attr(feature = "clap", derive(clap::Args))]
126pub struct Opts {
127    /// Call clang-format on the generated code
128    #[cfg_attr(feature = "clap", arg(long, default_value_t = bool::default()))]
129    pub format: bool,
130
131    /// Place each interface in its own file,
132    /// this enables sharing bindings across projects
133    #[cfg_attr(feature = "clap", arg(long, default_value_t = bool::default()))]
134    pub split_interfaces: bool,
135
136    /// Optionally prefix any export names with the specified value.
137    ///
138    /// This is useful to avoid name conflicts when testing.
139    #[cfg_attr(feature = "clap", arg(long))]
140    pub export_prefix: Option<String>,
141
142    /// Wrap all C++ classes inside a custom namespace.
143    ///
144    /// This avoids identical names across components, useful for native
145    #[cfg_attr(feature = "clap", arg(long))]
146    pub internal_prefix: Option<String>,
147
148    /// Set API style to symmetric or asymmetric
149    #[cfg_attr(
150        feature = "clap",
151        arg(
152            long,
153            default_value_t = APIStyle::default(),
154            value_name = "STYLE",
155        ),
156    )]
157    pub api_style: APIStyle,
158
159    /// Whether to generate owning or borrowing type definitions for `record` arguments to imported functions.
160    ///
161    /// Valid values include:
162    ///
163    /// - `owning`: Generated types will be composed entirely of owning fields,
164    ///   regardless of whether they are used as parameters to imports or not.
165    ///
166    /// - `coarse-borrowing`: Generated types used as parameters to imports will be
167    ///   "deeply borrowing", i.e. contain references rather than owned values,
168    ///   so long as they don't contain resources, in which case they will be
169    ///   owning.
170    ///
171    /// - `fine-borrowing": Generated types used as parameters to imports will be
172    ///   "deeply borrowing", i.e. contain references rather than owned values
173    ///   for all fields that are not resources, which will be owning.
174    #[cfg_attr(feature = "clap", arg(long, default_value_t = Ownership::Owning))]
175    pub ownership: Ownership,
176
177    /// Where to place output files
178    #[cfg_attr(feature = "clap", arg(skip))]
179    out_dir: Option<PathBuf>,
180
181    /// Importing wit interface from custom include
182    ///
183    /// Argument must be of the form `k=v` and this option can be passed
184    /// multiple times or one option can be comma separated, for example
185    /// `k1=v1,k2=v2`.
186    #[cfg_attr(feature = "clap", arg(long, value_parser = parse_with, value_delimiter = ','))]
187    pub with: Vec<(String, String)>,
188}
189
190/// Supported API styles for the generated bindings.
191#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
192pub enum APIStyle {
193    /// Imported functions borrow arguments, while exported functions receive owned arguments. Reduces the allocation overhead for the canonical ABI.
194    #[default]
195    Asymmetric,
196    /// Same API for imported and exported functions. Reduces the allocation overhead for symmetric ABI.
197    Symmetric,
198}
199
200impl Display for APIStyle {
201    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202        match self {
203            APIStyle::Asymmetric => write!(f, "asymmetric"),
204            APIStyle::Symmetric => write!(f, "symmetric"),
205        }
206    }
207}
208
209impl FromStr for APIStyle {
210    type Err = anyhow::Error;
211
212    fn from_str(s: &str) -> Result<Self, Self::Err> {
213        match s {
214            "asymmetric" => Ok(APIStyle::Asymmetric),
215            "symmetric" => Ok(APIStyle::Symmetric),
216            _ => bail!("unrecognized API style: `{s}`; expected `asymmetric` or `symmetric`"),
217        }
218    }
219}
220
221#[derive(Default, Debug, Clone, Copy)]
222pub enum Ownership {
223    /// Generated types will be composed entirely of owning fields, regardless
224    /// of whether they are used as parameters to imports or not.
225    #[default]
226    Owning,
227
228    /// Generated types used as parameters to imports will be "deeply
229    /// borrowing", i.e. contain references rather than owned values when
230    /// applicable.
231    CoarseBorrowing,
232
233    /// Generated types used as parameters to imports will be "deeply
234    /// borrowing", i.e. contain references rather than owned values
235    /// for all fields that are not resources, which will be owning.
236    FineBorrowing,
237}
238
239impl FromStr for Ownership {
240    type Err = String;
241
242    fn from_str(s: &str) -> Result<Self, Self::Err> {
243        match s {
244            "owning" => Ok(Self::Owning),
245            "coarse-borrowing" => Ok(Self::CoarseBorrowing),
246            "fine-borrowing" => Ok(Self::FineBorrowing),
247            _ => Err(format!(
248                "unrecognized ownership: `{s}`; \
249                 expected `owning`, `coarse-borrowing`, or `fine-borrowing`"
250            )),
251        }
252    }
253}
254
255impl fmt::Display for Ownership {
256    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
257        f.write_str(match self {
258            Ownership::Owning => "owning",
259            Ownership::CoarseBorrowing => "coarse-borrowing",
260            Ownership::FineBorrowing => "fine-borrowing",
261        })
262    }
263}
264
265impl Opts {
266    pub fn build(mut self, out_dir: Option<&PathBuf>) -> Box<dyn WorldGenerator> {
267        let mut r = Cpp::new();
268        self.out_dir = out_dir.cloned();
269        r.opts = self;
270        Box::new(r)
271    }
272
273    fn is_only_handle(&self, variant: AbiVariant) -> bool {
274        !matches!(variant, AbiVariant::GuestExport)
275    }
276
277    fn ptr_type(&self) -> &'static str {
278        "uint8_t*"
279    }
280}
281
282impl Cpp {
283    fn new() -> Cpp {
284        Cpp::default()
285    }
286
287    fn update_instance_name(&mut self, resolve: &Resolve, name: &WorldKey, id: InterfaceId) {
288        match name {
289            WorldKey::Name(instance) if resolve.interfaces[id].name.is_some() => {
290                self.instance_names.insert(id, instance.clone());
291            }
292            _ => {
293                self.instance_names.remove(&id);
294            }
295        }
296    }
297
298    pub fn is_first_definition(&mut self, ns: &Vec<String>, name: &str) -> bool {
299        let owned = (ns.to_owned(), name.to_owned());
300        if !self.defined_types.contains(&owned) {
301            self.defined_types.insert(owned);
302            true
303        } else {
304            false
305        }
306    }
307
308    fn include(&mut self, s: &str) {
309        self.includes.push(s.to_string());
310    }
311
312    /// Returns true if the function is a fallible constructor.
313    ///
314    /// Fallible constructors are constructors that return `result<T, E>` instead of just `T`.
315    /// In the generated C++ code, these become static factory methods named `Create` that
316    /// return `std::expected<T, E>`, rather than regular constructors.
317    fn is_fallible_constructor(&self, resolve: &Resolve, func: &Function) -> bool {
318        matches!(&func.kind, FunctionKind::Constructor(_))
319            && func.result.as_ref().is_some_and(|ty| {
320                if let Type::Id(id) = ty {
321                    matches!(&resolve.types[*id].kind, TypeDefKind::Result(_))
322                } else {
323                    false
324                }
325            })
326    }
327
328    fn interface<'a>(
329        &'a mut self,
330        resolve: &'a Resolve,
331        name: Option<&'a WorldKey>,
332        in_guest_import: bool,
333        wasm_import_module: Option<String>,
334    ) -> Result<CppInterfaceGenerator<'a>> {
335        let mut sizes = SizeAlign::default();
336        sizes.fill(resolve)?;
337
338        Ok(CppInterfaceGenerator {
339            _src: Source::default(),
340            r#gen: self,
341            resolve,
342            interface: None,
343            _name: name,
344            sizes,
345            in_guest_import,
346            wasm_import_module,
347        })
348    }
349
350    fn clang_format(code: &mut String) {
351        let mut child = Command::new("clang-format")
352            .stdin(Stdio::piped())
353            .stdout(Stdio::piped())
354            .spawn()
355            .expect("failed to spawn `clang-format`");
356        child
357            .stdin
358            .take()
359            .unwrap()
360            .write_all(code.as_bytes())
361            .unwrap();
362        code.truncate(0);
363        child.stdout.take().unwrap().read_to_string(code).unwrap();
364        let status = child.wait().unwrap();
365        assert!(status.success());
366    }
367
368    fn perform_cast(&mut self, op: &str, cast: &Bitcast) -> String {
369        match cast {
370            Bitcast::I32ToF32 | Bitcast::I64ToF32 => {
371                self.dependencies.needs_bit = true;
372                format!("std::bit_cast<float, int32_t>({op})")
373            }
374            Bitcast::F32ToI32 | Bitcast::F32ToI64 => {
375                self.dependencies.needs_bit = true;
376                format!("std::bit_cast<int32_t, float>({op})")
377            }
378            Bitcast::I64ToF64 => {
379                self.dependencies.needs_bit = true;
380                format!("std::bit_cast<double, int64_t>({op})")
381            }
382            Bitcast::F64ToI64 => {
383                self.dependencies.needs_bit = true;
384                format!("std::bit_cast<int64_t, double>({op})")
385            }
386            Bitcast::I32ToI64 | Bitcast::LToI64 | Bitcast::PToP64 => {
387                format!("(int64_t) {op}")
388            }
389            Bitcast::I64ToI32 | Bitcast::PToI32 | Bitcast::LToI32 => {
390                format!("(int32_t) {op}")
391            }
392            Bitcast::P64ToI64 | Bitcast::None | Bitcast::I64ToP64 => op.to_string(),
393            Bitcast::P64ToP | Bitcast::I32ToP | Bitcast::LToP => {
394                format!("(uint8_t*) {op}")
395            }
396            Bitcast::PToL | Bitcast::I32ToL | Bitcast::I64ToL => {
397                format!("(size_t) {op}")
398            }
399            Bitcast::Sequence(sequence) => {
400                let [first, second] = &**sequence;
401                let inner = self.perform_cast(op, first);
402                self.perform_cast(&inner, second)
403            }
404        }
405    }
406
407    fn finish_includes(&mut self) {
408        self.include("<cstdint>");
409        self.include("<utility>"); // for std::move
410        if self.dependencies.needs_string {
411            self.include("<string>");
412        }
413        if self.dependencies.needs_string_view {
414            self.include("<string_view>");
415        }
416        if self.dependencies.needs_vector {
417            self.include("<vector>");
418        }
419        if self.dependencies.needs_expected {
420            self.include("<expected>");
421        }
422        if self.dependencies.needs_optional {
423            self.include("<optional>");
424        }
425        if self.dependencies.needs_cstring {
426            self.include("<cstring>");
427        }
428        if self.dependencies.needs_imported_resources {
429            self.include("<cassert>");
430        }
431        if self.dependencies.needs_exported_resources {
432            self.include("<map>");
433        }
434        if self.dependencies.needs_variant {
435            self.include("<variant>");
436        }
437        if self.dependencies.needs_tuple {
438            self.include("<tuple>");
439        }
440        if self.dependencies.needs_span {
441            self.include("<span>");
442        }
443        if self.dependencies.needs_wit {
444            self.include("\"wit.h\"");
445        }
446        if self.dependencies.needs_memory {
447            self.include("<memory>");
448        }
449        if self.dependencies.needs_array {
450            self.include("<array>");
451        }
452        if self.dependencies.needs_bit {
453            self.include("<bit>");
454        }
455    }
456
457    fn start_new_file(&mut self, condition: Option<bool>) -> FileContext {
458        if condition == Some(true) || self.opts.split_interfaces {
459            FileContext {
460                includes: std::mem::take(&mut self.includes),
461                src: std::mem::take(&mut self.h_src),
462                dependencies: std::mem::take(&mut self.dependencies),
463            }
464        } else {
465            Default::default()
466        }
467    }
468
469    fn finish_file(&mut self, namespace: &[String], store: FileContext) {
470        if !store.src.src.is_empty() {
471            let mut header = String::default();
472            self.finish_includes();
473            self.h_src.change_namespace(&[]);
474            uwriteln!(header, "#pragma once");
475            for include in self.includes.iter() {
476                uwriteln!(header, "#include {include}");
477            }
478            header.push_str(&self.h_src.src);
479            let mut filename = namespace.join("-");
480            filename.push_str(".h");
481            if self.opts.format {
482                Self::clang_format(&mut header);
483            }
484            self.user_class_files.insert(filename.clone(), header);
485
486            let _ = std::mem::replace(&mut self.includes, store.includes);
487            let _ = std::mem::replace(&mut self.h_src, store.src);
488            let _ = std::mem::replace(&mut self.dependencies, store.dependencies);
489            self.includes.push(String::from("\"") + &filename + "\"");
490        }
491    }
492}
493
494#[derive(Default)]
495struct FileContext {
496    includes: Vec<String>,
497    src: SourceWithState,
498    dependencies: Includes,
499}
500
501impl WorldGenerator for Cpp {
502    fn preprocess(&mut self, resolve: &Resolve, world: WorldId) -> anyhow::Result<()> {
503        let name = &resolve.worlds[world].name;
504        self.world = name.to_string();
505        self.types.analyze(resolve);
506        self.world_id = Some(world);
507        uwriteln!(
508            self.c_src_head,
509            r#"#include "{}_cpp.h"
510            #include <cstdlib> // realloc
511
512            extern "C" void *cabi_realloc(void *ptr, size_t old_size, size_t align, size_t new_size);
513
514            __attribute__((__weak__, __export_name__("cabi_realloc")))
515            void *cabi_realloc(void *ptr, size_t old_size, size_t align, size_t new_size) {{
516                (void) old_size;
517                if (new_size == 0) return (void*) align;
518                void *ret = realloc(ptr, new_size);
519                if (!ret) abort();
520                return ret;
521            }}
522
523            "#,
524            self.world.to_snake_case(),
525        );
526        Ok(())
527    }
528
529    fn import_interface(
530        &mut self,
531        resolve: &Resolve,
532        name: &WorldKey,
533        id: InterfaceId,
534        _files: &mut Files,
535    ) -> anyhow::Result<()> {
536        self.imported_interfaces.insert(id);
537        self.update_instance_name(resolve, name, id);
538
539        let full_name = resolve.name_world_key(name);
540        match self.opts.with.iter().find(|e| e.0 == full_name) {
541            None => {
542                if let Some(prefix) = self
543                    .interface_prefixes
544                    .get(&(Direction::Import, name.clone()))
545                {
546                    self.import_prefix = Some(prefix.clone());
547                }
548
549                let store = self.start_new_file(None);
550                let wasm_import_module = resolve.name_world_key(name);
551                let binding = Some(name);
552                let mut r#gen = self.interface(resolve, binding, true, Some(wasm_import_module))?;
553                r#gen.interface = Some(id);
554                let namespace = namespace(resolve, &TypeOwner::Interface(id), false, &*r#gen.r#gen);
555                let docs = resolve.interfaces[id].docs.contents.as_deref();
556                r#gen
557                    .r#gen
558                    .h_src
559                    .change_namespace_with_docs(&namespace, docs);
560                r#gen.types(id);
561
562                for (_name, func) in resolve.interfaces[id].functions.iter() {
563                    if matches!(func.kind, FunctionKind::Freestanding) {
564                        r#gen.r#gen.h_src.change_namespace(&namespace);
565                        r#gen.generate_function(
566                            func,
567                            &TypeOwner::Interface(id),
568                            AbiVariant::GuestImport,
569                        );
570                    }
571                }
572                self.finish_file(&namespace, store);
573            }
574            Some((_, val)) => {
575                let with_quotes = format!("\"{val}\"");
576                if !self.includes.contains(&with_quotes) {
577                    self.includes.push(with_quotes);
578                }
579            }
580        }
581        let _ = self.import_prefix.take();
582        Ok(())
583    }
584
585    fn export_interface(
586        &mut self,
587        resolve: &Resolve,
588        name: &WorldKey,
589        id: InterfaceId,
590        _files: &mut Files,
591    ) -> anyhow::Result<()> {
592        let old_prefix = self.opts.export_prefix.clone();
593        if let Some(prefix) = self
594            .interface_prefixes
595            .get(&(Direction::Export, name.clone()))
596        {
597            self.opts.export_prefix =
598                Some(prefix.clone() + old_prefix.as_ref().unwrap_or(&String::new()));
599        }
600        let store = self.start_new_file(None);
601        self.h_src
602            .src
603            .push_str(&format!("// export_interface {name:?}\n"));
604        self.imported_interfaces.remove(&id);
605        self.update_instance_name(resolve, name, id);
606        let wasm_import_module = resolve.name_world_key(name);
607        let binding = Some(name);
608        let mut r#gen = self.interface(resolve, binding, false, Some(wasm_import_module))?;
609        r#gen.interface = Some(id);
610        let namespace = namespace(resolve, &TypeOwner::Interface(id), true, &*r#gen.r#gen);
611        let docs = resolve.interfaces[id].docs.contents.as_deref();
612        r#gen
613            .r#gen
614            .h_src
615            .change_namespace_with_docs(&namespace, docs);
616        r#gen.types(id);
617
618        for (_name, func) in resolve.interfaces[id].functions.iter() {
619            if matches!(func.kind, FunctionKind::Freestanding) {
620                r#gen.r#gen.h_src.change_namespace(&namespace);
621                r#gen.generate_function(func, &TypeOwner::Interface(id), AbiVariant::GuestExport);
622            }
623        }
624        self.finish_file(&namespace, store);
625        self.opts.export_prefix = old_prefix;
626        Ok(())
627    }
628
629    fn import_funcs(
630        &mut self,
631        resolve: &Resolve,
632        world: WorldId,
633        funcs: &[(&str, &Function)],
634        _files: &mut Files,
635    ) -> Result<()> {
636        let name = WorldKey::Name("$root".to_string()); //WorldKey::Name(resolve.worlds[world].name.clone());
637        let wasm_import_module = resolve.name_world_key(&name);
638        let binding = Some(name);
639        let mut r#gen =
640            self.interface(resolve, binding.as_ref(), true, Some(wasm_import_module))?;
641        let namespace = namespace(resolve, &TypeOwner::World(world), false, &*r#gen.r#gen);
642
643        for (_name, func) in funcs.iter() {
644            if matches!(func.kind, FunctionKind::Freestanding) {
645                r#gen.r#gen.h_src.change_namespace(&namespace);
646                r#gen.generate_function(func, &TypeOwner::World(world), AbiVariant::GuestImport);
647            }
648        }
649        Ok(())
650    }
651
652    fn export_funcs(
653        &mut self,
654        resolve: &Resolve,
655        world: WorldId,
656        funcs: &[(&str, &Function)],
657        _files: &mut Files,
658    ) -> anyhow::Result<()> {
659        let name = WorldKey::Name(resolve.worlds[world].name.clone());
660        let binding = Some(name);
661        let mut r#gen = self.interface(resolve, binding.as_ref(), false, None)?;
662        let namespace = namespace(resolve, &TypeOwner::World(world), true, &*r#gen.r#gen);
663
664        for (_name, func) in funcs.iter() {
665            if matches!(func.kind, FunctionKind::Freestanding) {
666                r#gen.r#gen.h_src.change_namespace(&namespace);
667                r#gen.generate_function(func, &TypeOwner::World(world), AbiVariant::GuestExport);
668            }
669        }
670        Ok(())
671    }
672
673    fn import_types(
674        &mut self,
675        resolve: &Resolve,
676        _world: WorldId,
677        types: &[(&str, TypeId)],
678        _files: &mut Files,
679    ) -> Result<()> {
680        let mut r#gen = self.interface(resolve, None, true, Some("$root".to_string()))?;
681        for (name, id) in types.iter() {
682            r#gen.define_type(name, *id);
683        }
684        Ok(())
685    }
686
687    fn finish(
688        &mut self,
689        resolve: &Resolve,
690        world_id: WorldId,
691        files: &mut Files,
692    ) -> std::result::Result<(), anyhow::Error> {
693        let world = &resolve.worlds[world_id];
694        let snake = world.name.to_snake_case();
695        let linking_symbol = wit_bindgen_c::component_type_object::linking_symbol(&world.name);
696
697        let mut h_str = SourceWithState::default();
698        let mut c_str = SourceWithState::default();
699
700        let version = env!("CARGO_PKG_VERSION");
701        uwriteln!(
702            h_str.src,
703            "// Generated by `wit-bindgen` {version}. DO NOT EDIT!"
704        );
705
706        uwrite!(
707            h_str.src,
708            "#ifndef __CPP_GUEST_BINDINGS_{0}_H
709            #define __CPP_GUEST_BINDINGS_{0}_H\n",
710            world.name.to_shouty_snake_case(),
711        );
712        self.finish_includes();
713
714        for include in self.includes.iter() {
715            uwriteln!(h_str.src, "#include {include}");
716        }
717
718        uwriteln!(
719            c_str.src,
720            "// Generated by `wit-bindgen` {version}. DO NOT EDIT!"
721        );
722        uwriteln!(
723            c_str.src,
724            "\n// Ensure that the *_component_type.o object is linked in"
725        );
726        uwrite!(
727            c_str.src,
728            "#ifdef __wasm32__
729                   extern \"C\" void {linking_symbol}(void);
730                   __attribute__((used))
731                   void {linking_symbol}_public_use_in_this_compilation_unit(void) {{
732                       {linking_symbol}();
733                   }}
734                   #endif
735               ",
736        );
737        if self.dependencies.needs_assert {
738            uwriteln!(c_str.src, "#include <assert.h>");
739        }
740
741        h_str.change_namespace(&Vec::default());
742
743        self.c_src.change_namespace(&Vec::default());
744        c_str.src.push_str(&self.c_src_head);
745        c_str.src.push_str(&self.extern_c_decls);
746        c_str.src.push_str(&self.c_src.src);
747        self.h_src.change_namespace(&Vec::default());
748        h_str.src.push_str(&self.h_src.src);
749
750        uwriteln!(c_str.src, "\n// Component Adapters");
751
752        uwriteln!(
753            h_str.src,
754            "
755            #endif"
756        );
757
758        if self.opts.format {
759            Self::clang_format(c_str.src.as_mut_string());
760            Self::clang_format(h_str.src.as_mut_string());
761        }
762
763        files.push(&format!("{snake}.cpp"), c_str.src.as_bytes());
764        files.push(&format!("{snake}_cpp.h"), h_str.src.as_bytes());
765        for (name, content) in self.user_class_files.iter() {
766            // if the user class file exists create an updated .template
767            let dst = match &self.opts.out_dir {
768                Some(path) => path.join(name),
769                None => name.into(),
770            };
771            if std::path::Path::exists(&dst) {
772                files.push(&(String::from(name) + ".template"), content.as_bytes());
773            } else {
774                files.push(name, content.as_bytes());
775            }
776        }
777        files.push(
778            &format!("{snake}_component_type.o",),
779            wit_bindgen_c::component_type_object::object(
780                resolve,
781                world_id,
782                &world.name,
783                wit_component::StringEncoding::UTF8,
784                None,
785            )
786            .unwrap()
787            .as_slice(),
788        );
789
790        if self.dependencies.needs_wit {
791            files.push("wit.h", include_bytes!("../helper-types/wit.h"));
792        }
793        Ok(())
794    }
795}
796
797// determine namespace (for the lifted C++ function)
798fn namespace(resolve: &Resolve, owner: &TypeOwner, guest_export: bool, r#gen: &Cpp) -> Vec<String> {
799    let mut result = Vec::default();
800    if let Some(prefix) = &r#gen.opts.internal_prefix {
801        result.push(prefix.clone());
802    }
803    if guest_export {
804        result.push(String::from("exports"));
805    }
806    match owner {
807        TypeOwner::World(w) => result.push(to_c_ident(&resolve.worlds[*w].name)),
808        TypeOwner::Interface(i) => {
809            if let Some(instance) = r#gen.instance_names.get(i) {
810                result.push(to_c_ident(instance));
811            } else {
812                let iface = &resolve.interfaces[*i];
813                let pkg_id = iface.package.unwrap();
814                let pkg = &resolve.packages[pkg_id];
815                result.push(to_c_ident(&pkg.name.namespace));
816                // Use name_package_module to get version-specific package names
817                result.push(to_c_ident(&name_package_module(resolve, pkg_id)));
818                if let Some(name) = &iface.name {
819                    result.push(to_c_ident(name));
820                }
821            }
822        }
823        TypeOwner::None => (),
824    }
825    result
826}
827
828impl SourceWithState {
829    fn change_namespace(&mut self, target: &[String]) {
830        self.change_namespace_with_docs(target, None);
831    }
832
833    fn change_namespace_with_docs(&mut self, target: &[String], docs: Option<&str>) {
834        let mut same = 0;
835        // itertools::fold_while?
836        for (a, b) in self.namespace.iter().zip(target.iter()) {
837            if a == b {
838                same += 1;
839            } else {
840                break;
841            }
842        }
843        for _i in same..self.namespace.len() {
844            uwrite!(self.src, "}}\n");
845        }
846        self.namespace.truncate(same);
847        let new_namespaces: Vec<_> = target.iter().skip(same).collect();
848        if !new_namespaces.is_empty() {
849            if let Some(content) = docs {
850                for line in content.trim().lines() {
851                    uwriteln!(self.src, "/// {}", line);
852                }
853            }
854            for i in &new_namespaces {
855                uwrite!(self.src, "namespace {} {{\n", i);
856                self.namespace.push(i.to_string());
857            }
858        }
859    }
860
861    fn qualify(&mut self, target: &[String]) {
862        let mut same = 0;
863        // itertools::fold_while?
864        for (a, b) in self.namespace.iter().zip(target.iter()) {
865            if a == b {
866                same += 1;
867            } else {
868                break;
869            }
870        }
871        if same == 0 && !target.is_empty() {
872            // if the root namespace exists below the current namespace we need to start at root
873            // Also ensure absolute qualification when crossing from exports to imports
874            if self.namespace.contains(target.first().unwrap())
875                || (self.namespace.first().map(|s| s.as_str()) == Some("exports")
876                    && target.first().map(|s| s.as_str()) != Some("exports"))
877            {
878                self.src.push_str("::");
879            }
880        }
881        if same == target.len() && self.namespace.len() != target.len() && same > 0 {
882            // namespace is parent, qualify at least one namespace (and cross fingers)
883            uwrite!(self.src, "{}::", target[same - 1]);
884        } else {
885            for i in target.iter().skip(same) {
886                uwrite!(self.src, "{i}::");
887            }
888        }
889    }
890}
891
892struct CppInterfaceGenerator<'a> {
893    _src: Source,
894    r#gen: &'a mut Cpp,
895    resolve: &'a Resolve,
896    interface: Option<InterfaceId>,
897    _name: Option<&'a WorldKey>,
898    sizes: SizeAlign,
899    in_guest_import: bool,
900    pub wasm_import_module: Option<String>,
901}
902
903impl CppInterfaceGenerator<'_> {
904    fn types(&mut self, iface: InterfaceId) {
905        let iface_data = &self.resolve().interfaces[iface];
906
907        // Here we sort the types topologically before emitting code for them,
908        // taking into consideration the parameter and return types of functions
909        // associated with resource types. This ensures each type is declared
910        // before any uses of it.
911        for (name, id) in sort_types(self.resolve, &iface_data.types) {
912            self.define_type(name, id);
913        }
914    }
915
916    fn define_type(&mut self, name: &str, id: TypeId) {
917        let ty = &self.resolve().types[id];
918        match &ty.kind {
919            TypeDefKind::Record(record) => self.type_record(id, name, record, &ty.docs),
920            TypeDefKind::Resource => self.type_resource(id, name, &ty.docs),
921            TypeDefKind::Flags(flags) => self.type_flags(id, name, flags, &ty.docs),
922            TypeDefKind::Tuple(tuple) => self.type_tuple(id, name, tuple, &ty.docs),
923            TypeDefKind::Enum(enum_) => self.type_enum(id, name, enum_, &ty.docs),
924            TypeDefKind::Variant(variant) => self.type_variant(id, name, variant, &ty.docs),
925            TypeDefKind::Option(t) => self.type_option(id, name, t, &ty.docs),
926            TypeDefKind::Result(r) => self.type_result(id, name, r, &ty.docs),
927            TypeDefKind::List(t) => self.type_list(id, name, t, &ty.docs),
928            TypeDefKind::Type(t) => self.type_alias(id, name, t, &ty.docs),
929            TypeDefKind::Future(_) => todo!("generate for future"),
930            TypeDefKind::Stream(_) => todo!("generate for stream"),
931            TypeDefKind::Handle(_) => todo!("generate for handle"),
932            TypeDefKind::FixedLengthList(_, _) => todo!(),
933            TypeDefKind::Map(k, v) => self.type_map(id, name, k, v, &ty.docs),
934            TypeDefKind::Unknown => unreachable!(),
935        }
936    }
937
938    /// This describes the C++ side name
939    fn func_namespace_name(
940        &self,
941        func: &Function,
942        guest_export: bool,
943        cpp_file: bool,
944    ) -> (Vec<String>, String) {
945        let (object, owner) = match &func.kind {
946            FunctionKind::Freestanding => None,
947            FunctionKind::Method(i) => Some(i),
948            FunctionKind::Static(i) => Some(i),
949            FunctionKind::Constructor(i) => Some(i),
950            FunctionKind::AsyncFreestanding => todo!(),
951            FunctionKind::AsyncMethod(_id) => todo!(),
952            FunctionKind::AsyncStatic(_id) => todo!(),
953        }
954        .map(|i| {
955            let ty = &self.resolve.types[*i];
956            (ty.name.as_ref().unwrap().to_pascal_case(), ty.owner)
957        })
958        .unwrap_or((
959            Default::default(),
960            self.interface
961                .map(TypeOwner::Interface)
962                .unwrap_or(TypeOwner::World(self.r#gen.world_id.unwrap())),
963        ));
964        let mut namespace = namespace(self.resolve, &owner, guest_export, &*self.r#gen);
965        let is_drop = is_special_method(func);
966        let func_name_h = if !matches!(&func.kind, FunctionKind::Freestanding) {
967            namespace.push(object.clone());
968            if let FunctionKind::Constructor(_i) = &func.kind {
969                // Fallible constructors return result<T, E> and are static factory methods
970                let is_fallible_constructor =
971                    self.r#gen.is_fallible_constructor(self.resolve, func);
972
973                if is_fallible_constructor {
974                    String::from("Create")
975                } else if guest_export && cpp_file {
976                    String::from("New")
977                } else {
978                    object.clone()
979                }
980            } else {
981                match is_drop {
982                    SpecialMethod::ResourceDrop => {
983                        if guest_export {
984                            "ResourceDrop".to_string()
985                        } else {
986                            "~".to_string() + &object
987                        }
988                    }
989                    SpecialMethod::Dtor => "Dtor".to_string(),
990                    SpecialMethod::ResourceNew => "ResourceNew".to_string(),
991                    SpecialMethod::ResourceRep => "ResourceRep".to_string(),
992                    SpecialMethod::Allocate => "New".to_string(),
993                    SpecialMethod::None => func.item_name().to_pascal_case(),
994                }
995            }
996        } else {
997            func.name.to_pascal_case()
998        };
999        (namespace, func_name_h)
1000    }
1001
1002    // print the signature of the guest export (lowered (wasm) function calling into highlevel)
1003    fn print_export_signature(&mut self, func: &Function, variant: AbiVariant) -> Vec<String> {
1004        let is_drop = is_special_method(func);
1005        let id_type = WasmType::I32;
1006        let signature = match is_drop {
1007            SpecialMethod::ResourceDrop => WasmSignature {
1008                params: vec![id_type],
1009                results: Vec::new(),
1010                indirect_params: false,
1011                retptr: false,
1012            },
1013            SpecialMethod::ResourceRep => WasmSignature {
1014                params: vec![id_type],
1015                results: vec![WasmType::Pointer],
1016                indirect_params: false,
1017                retptr: false,
1018            },
1019            SpecialMethod::Dtor => WasmSignature {
1020                params: vec![WasmType::Pointer],
1021                results: Vec::new(),
1022                indirect_params: false,
1023                retptr: false,
1024            },
1025            SpecialMethod::ResourceNew => WasmSignature {
1026                params: vec![WasmType::Pointer],
1027                results: vec![id_type],
1028                indirect_params: false,
1029                retptr: false,
1030            },
1031            SpecialMethod::None => {
1032                // TODO perhaps remember better names for the arguments
1033                self.resolve.wasm_signature(variant, func)
1034            }
1035            SpecialMethod::Allocate => WasmSignature {
1036                params: vec![],
1037                results: vec![],
1038                indirect_params: false,
1039                retptr: false,
1040            },
1041        };
1042        let mut module_name = self.wasm_import_module.clone();
1043        let symbol_variant = variant;
1044        if matches!(variant, AbiVariant::GuestExport)
1045            && matches!(
1046                is_drop,
1047                SpecialMethod::ResourceNew
1048                    | SpecialMethod::ResourceDrop
1049                    | SpecialMethod::ResourceRep
1050            )
1051        {
1052            module_name = Some(String::from("[export]") + &module_name.unwrap());
1053        }
1054        let func_name = func.name.clone();
1055        let module_prefix = module_name.as_ref().map_or(String::default(), |name| {
1056            let mut res = name.clone();
1057            res.push('#');
1058            res
1059        });
1060        uwriteln!(
1061            self.r#gen.c_src.src,
1062            r#"extern "C" __attribute__((__export_name__("{module_prefix}{func_name}")))"#
1063        );
1064        let return_via_pointer = false;
1065        self.r#gen
1066            .c_src
1067            .src
1068            .push_str(if signature.results.is_empty() || return_via_pointer {
1069                "void"
1070            } else {
1071                wit_bindgen_c::wasm_type(signature.results[0])
1072            });
1073        self.r#gen.c_src.src.push_str(" ");
1074        let export_name = match module_name {
1075            Some(ref module_name) => make_external_symbol(module_name, &func_name, symbol_variant),
1076            None => make_external_component(&func_name),
1077        };
1078        // Add prefix to C ABI export functions to avoid conflicts with C++ namespaces
1079        self.r#gen.c_src.src.push_str("__wasm_export_");
1080        if let Some(prefix) = self.r#gen.opts.export_prefix.as_ref() {
1081            self.r#gen.c_src.src.push_str(prefix);
1082        }
1083        self.r#gen.c_src.src.push_str(&export_name);
1084        self.r#gen.c_src.src.push_str("(");
1085        let mut first_arg = true;
1086        let mut params = Vec::new();
1087        for (n, ty) in signature.params.iter().enumerate() {
1088            let name = format!("arg{n}");
1089            if !first_arg {
1090                self.r#gen.c_src.src.push_str(", ");
1091            } else {
1092                first_arg = false;
1093            }
1094            self.r#gen.c_src.src.push_str(wit_bindgen_c::wasm_type(*ty));
1095            self.r#gen.c_src.src.push_str(" ");
1096            self.r#gen.c_src.src.push_str(&name);
1097            params.push(name);
1098        }
1099        if return_via_pointer {
1100            if !first_arg {
1101                self.r#gen.c_src.src.push_str(", ");
1102            }
1103            self.r#gen.c_src.src.push_str(self.r#gen.opts.ptr_type());
1104            self.r#gen.c_src.src.push_str(" resultptr");
1105            params.push("resultptr".into());
1106        }
1107        self.r#gen.c_src.src.push_str(")\n");
1108        params
1109    }
1110
1111    fn high_level_signature(
1112        &mut self,
1113        func: &Function,
1114        abi_variant: AbiVariant,
1115        outer_namespace: &[String],
1116    ) -> HighlevelSignature {
1117        let mut res = HighlevelSignature::default();
1118
1119        let (namespace, func_name_h) =
1120            self.func_namespace_name(func, matches!(abi_variant, AbiVariant::GuestExport), false);
1121        res.name = func_name_h;
1122        res.namespace = namespace;
1123        let is_drop = is_special_method(func);
1124        // we might want to separate c_sig and h_sig
1125        // let mut sig = String::new();
1126
1127        // Check if this is a fallible constructor (returns result<T, E>)
1128        let is_fallible_constructor = self.r#gen.is_fallible_constructor(self.resolve, func);
1129
1130        // not for ctor nor imported dtor on guest (except fallible constructors)
1131        if (!matches!(&func.kind, FunctionKind::Constructor(_)) || is_fallible_constructor)
1132            && !(matches!(is_drop, SpecialMethod::ResourceDrop)
1133                && matches!(abi_variant, AbiVariant::GuestImport))
1134        {
1135            if matches!(is_drop, SpecialMethod::Allocate) {
1136                res.result.push_str("Owned");
1137            } else if let Some(ty) = &func.result {
1138                res.result.push_str(
1139                    &(self.type_name(ty, outer_namespace, Flavor::Result(abi_variant))
1140                        + if matches!(is_drop, SpecialMethod::ResourceRep) {
1141                            "*"
1142                        } else {
1143                            ""
1144                        }),
1145                );
1146            } else {
1147                res.result = "void".into();
1148            }
1149            if matches!(abi_variant, AbiVariant::GuestExport)
1150                && abi::guest_export_needs_post_return(self.resolve, func)
1151            {
1152                res.post_return = true;
1153            }
1154        }
1155        if (matches!(func.kind, FunctionKind::Static(_)) || is_fallible_constructor)
1156            && !(matches!(&is_drop, SpecialMethod::ResourceDrop)
1157                && matches!(abi_variant, AbiVariant::GuestImport))
1158        {
1159            res.static_member = true;
1160        }
1161        for (
1162            i,
1163            Param {
1164                name, ty: param, ..
1165            },
1166        ) in func.params.iter().enumerate()
1167        {
1168            if i == 0
1169                && name == "self"
1170                && (matches!(&func.kind, FunctionKind::Method(_))
1171                    || (matches!(&is_drop, SpecialMethod::ResourceDrop)
1172                        && matches!(abi_variant, AbiVariant::GuestImport)))
1173            {
1174                res.implicit_self = true;
1175                continue;
1176            }
1177            let is_pointer = if i == 0
1178                && name == "self"
1179                && matches!(&is_drop, SpecialMethod::Dtor | SpecialMethod::ResourceNew)
1180                && matches!(abi_variant, AbiVariant::GuestExport)
1181            {
1182                "*"
1183            } else {
1184                ""
1185            };
1186            res.arguments.push((
1187                to_c_ident(name),
1188                self.type_name(param, &res.namespace, Flavor::Argument(abi_variant)) + is_pointer,
1189            ));
1190        }
1191        // default to non-const when exporting a method
1192        let import = matches!(abi_variant, AbiVariant::GuestImport);
1193        if matches!(func.kind, FunctionKind::Method(_)) && import {
1194            res.const_member = true;
1195        }
1196        res
1197    }
1198
1199    fn print_signature(
1200        &mut self,
1201        func: &Function,
1202        variant: AbiVariant,
1203        import: bool,
1204    ) -> Vec<String> {
1205        let is_special = is_special_method(func);
1206        let from_namespace = self.r#gen.h_src.namespace.clone();
1207        let cpp_sig = self.high_level_signature(func, variant, &from_namespace);
1208        if cpp_sig.static_member {
1209            self.r#gen.h_src.src.push_str("static ");
1210        }
1211        self.r#gen.h_src.src.push_str(&cpp_sig.result);
1212        if !cpp_sig.result.is_empty() {
1213            self.r#gen.h_src.src.push_str(" ");
1214        }
1215        self.r#gen.h_src.src.push_str(&cpp_sig.name);
1216        self.r#gen.h_src.src.push_str("(");
1217        for (num, (arg, typ)) in cpp_sig.arguments.iter().enumerate() {
1218            if num > 0 {
1219                self.r#gen.h_src.src.push_str(", ");
1220            }
1221            self.r#gen.h_src.src.push_str(typ);
1222            self.r#gen.h_src.src.push_str(" ");
1223            self.r#gen.h_src.src.push_str(arg);
1224        }
1225        self.r#gen.h_src.src.push_str(")");
1226        if cpp_sig.const_member {
1227            self.r#gen.h_src.src.push_str(" const");
1228        }
1229        match (&is_special, false, &variant) {
1230            (SpecialMethod::Allocate, _, _) => {
1231                uwriteln!(
1232                    self.r#gen.h_src.src,
1233                    "{{\
1234                        return {OWNED_CLASS_NAME}(new {}({}));\
1235                    }}",
1236                    cpp_sig.namespace.last().unwrap(), //join("::"),
1237                    cpp_sig
1238                        .arguments
1239                        .iter()
1240                        .map(|(arg, _)| format!("std::move({arg})"))
1241                        .collect::<Vec<_>>()
1242                        .join(", ")
1243                );
1244                // body is inside the header
1245                return Vec::default();
1246            }
1247            (SpecialMethod::Dtor, _, _ /*AbiVariant::GuestImport*/)
1248            | (SpecialMethod::ResourceDrop, true, _) => {
1249                uwriteln!(
1250                    self.r#gen.h_src.src,
1251                    "{{\
1252                        delete {};\
1253                    }}",
1254                    cpp_sig.arguments.first().unwrap().0
1255                );
1256            }
1257            _ => self.r#gen.h_src.src.push_str(";\n"),
1258        }
1259
1260        // we want to separate the lowered signature (wasm) and the high level signature
1261        if !import
1262            && !matches!(
1263                &is_special,
1264                SpecialMethod::ResourceDrop
1265                    | SpecialMethod::ResourceNew
1266                    | SpecialMethod::ResourceRep
1267            )
1268        {
1269            self.print_export_signature(func, variant)
1270        } else {
1271            // recalulate with c file namespace
1272            let c_namespace = self.r#gen.c_src.namespace.clone();
1273            let cpp_sig = self.high_level_signature(func, variant, &c_namespace);
1274            let mut params = Vec::new();
1275            self.r#gen.c_src.src.push_str(&cpp_sig.result);
1276            if !cpp_sig.result.is_empty() {
1277                self.r#gen.c_src.src.push_str(" ");
1278            }
1279            self.r#gen.c_src.qualify(&cpp_sig.namespace);
1280            self.r#gen.c_src.src.push_str(&cpp_sig.name);
1281            self.r#gen.c_src.src.push_str("(");
1282            if cpp_sig.implicit_self {
1283                params.push("(*this)".into());
1284            }
1285            for (num, (arg, typ)) in cpp_sig.arguments.iter().enumerate() {
1286                if num > 0 {
1287                    self.r#gen.c_src.src.push_str(", ");
1288                }
1289                self.r#gen.c_src.src.push_str(typ);
1290                self.r#gen.c_src.src.push_str(" ");
1291                self.r#gen.c_src.src.push_str(arg);
1292                params.push(arg.clone());
1293            }
1294            self.r#gen.c_src.src.push_str(")");
1295            if cpp_sig.const_member {
1296                self.r#gen.c_src.src.push_str(" const");
1297            }
1298            self.r#gen.c_src.src.push_str("\n");
1299            params
1300        }
1301    }
1302
1303    fn generate_function(&mut self, func: &Function, owner: &TypeOwner, variant: AbiVariant) {
1304        fn class_namespace(
1305            cifg: &CppInterfaceGenerator,
1306            func: &Function,
1307            variant: AbiVariant,
1308        ) -> Vec<String> {
1309            let owner = &cifg.resolve.types[match &func.kind {
1310                FunctionKind::Static(id) => *id,
1311                _ => panic!("special func should be static"),
1312            }];
1313            let mut namespace = namespace(
1314                cifg.resolve,
1315                &owner.owner,
1316                matches!(variant, AbiVariant::GuestExport),
1317                &*cifg.r#gen,
1318            );
1319            namespace.push(owner.name.as_ref().unwrap().to_upper_camel_case());
1320            namespace
1321        }
1322
1323        let export = match variant {
1324            AbiVariant::GuestImport => false,
1325            AbiVariant::GuestExport => true,
1326            AbiVariant::GuestImportAsync => todo!(),
1327            AbiVariant::GuestExportAsync => todo!(),
1328            AbiVariant::GuestExportAsyncStackful => todo!(),
1329        };
1330        if func.docs.contents.is_some() && !self.r#gen.h_src.src.ends_with('\n') {
1331            uwriteln!(self.r#gen.h_src.src, "");
1332        }
1333        Self::docs(&mut self.r#gen.h_src.src, &func.docs);
1334        let params = self.print_signature(func, variant, !export);
1335        let special = is_special_method(func);
1336        if !matches!(special, SpecialMethod::Allocate) {
1337            self.r#gen.c_src.src.push_str("{\n");
1338            let needs_dealloc = if self.r#gen.opts.api_style == APIStyle::Symmetric
1339                && matches!(variant, AbiVariant::GuestExport)
1340            {
1341                self.r#gen
1342                    .c_src
1343                    .src
1344                    .push_str("std::vector<void*> _deallocate;\n");
1345                self.r#gen.dependencies.needs_vector = true;
1346                true
1347            } else {
1348                false
1349            };
1350            let lift_lower = if export {
1351                LiftLower::LiftArgsLowerResults
1352            } else {
1353                LiftLower::LowerArgsLiftResults
1354            };
1355            match is_special_method(func) {
1356                SpecialMethod::ResourceDrop => match lift_lower {
1357                    LiftLower::LiftArgsLowerResults => {
1358                        let module_name =
1359                            String::from("[export]") + &self.wasm_import_module.clone().unwrap();
1360                        let wasm_sig =
1361                            self.declare_import(&module_name, &func.name, &[WasmType::I32], &[]);
1362                        uwriteln!(
1363                            self.r#gen.c_src.src,
1364                            "{wasm_sig}({});",
1365                            func.params.first().unwrap().name
1366                        );
1367                    }
1368                    LiftLower::LowerArgsLiftResults => {
1369                        let module_name = self.wasm_import_module.clone().unwrap();
1370                        let name =
1371                            self.declare_import(&module_name, &func.name, &[WasmType::I32], &[]);
1372                        uwriteln!(
1373                            self.r#gen.c_src.src,
1374                            "   if (handle>=0) {{
1375                                {name}(handle);
1376                            }}"
1377                        );
1378                    }
1379                },
1380                SpecialMethod::Dtor => {
1381                    let classname = class_namespace(self, func, variant).join("::");
1382                    uwriteln!(self.r#gen.c_src.src, "(({classname}*)arg0)->handle=-1;");
1383                    uwriteln!(self.r#gen.c_src.src, "{0}::Dtor(({0}*)arg0);", classname);
1384                }
1385                SpecialMethod::ResourceNew => {
1386                    let module_name =
1387                        String::from("[export]") + &self.wasm_import_module.clone().unwrap();
1388                    let wasm_sig = self.declare_import(
1389                        &module_name,
1390                        &func.name,
1391                        &[WasmType::Pointer],
1392                        &[WasmType::I32],
1393                    );
1394                    uwriteln!(
1395                        self.r#gen.c_src.src,
1396                        "return {wasm_sig}(({}){});",
1397                        self.r#gen.opts.ptr_type(),
1398                        func.params.first().unwrap().name
1399                    );
1400                }
1401                SpecialMethod::ResourceRep => {
1402                    let module_name =
1403                        String::from("[export]") + &self.wasm_import_module.clone().unwrap();
1404                    let wasm_sig = self.declare_import(
1405                        &module_name,
1406                        &func.name,
1407                        &[WasmType::I32],
1408                        &[WasmType::Pointer],
1409                    );
1410                    let classname = class_namespace(self, func, variant).join("::");
1411                    uwriteln!(
1412                        self.r#gen.c_src.src,
1413                        "return ({}*){wasm_sig}({});",
1414                        classname,
1415                        func.params.first().unwrap().name
1416                    );
1417                }
1418                SpecialMethod::Allocate => unreachable!(),
1419                SpecialMethod::None => {
1420                    // normal methods
1421                    let namespace = if matches!(func.kind, FunctionKind::Freestanding) {
1422                        namespace(
1423                            self.resolve,
1424                            owner,
1425                            matches!(variant, AbiVariant::GuestExport),
1426                            &*self.r#gen,
1427                        )
1428                    } else {
1429                        let owner = &self.resolve.types[match &func.kind {
1430                            FunctionKind::Static(id) => *id,
1431                            FunctionKind::Constructor(id) => *id,
1432                            FunctionKind::Method(id) => *id,
1433                            FunctionKind::Freestanding => unreachable!(),
1434                            FunctionKind::AsyncFreestanding => todo!(),
1435                            FunctionKind::AsyncMethod(_id) => todo!(),
1436                            FunctionKind::AsyncStatic(_id) => todo!(),
1437                        }]
1438                        .clone();
1439                        let mut namespace = namespace(
1440                            self.resolve,
1441                            &owner.owner,
1442                            matches!(variant, AbiVariant::GuestExport),
1443                            &*self.r#gen,
1444                        );
1445                        namespace.push(owner.name.as_ref().unwrap().to_upper_camel_case());
1446                        namespace
1447                    };
1448                    let mut f = FunctionBindgen::new(self, params);
1449                    if !export {
1450                        f.namespace = namespace.clone();
1451                    }
1452                    f.variant = variant;
1453                    f.needs_dealloc = needs_dealloc;
1454                    f.cabi_post = None;
1455                    abi::call(f.r#gen.resolve, variant, lift_lower, func, &mut f, false);
1456                    let ret_area_decl = f.emit_ret_area_if_needed();
1457                    let code = format!("{}{}", ret_area_decl, String::from(f.src));
1458                    self.r#gen.c_src.src.push_str(&code);
1459                }
1460            }
1461            self.r#gen.c_src.src.push_str("}\n");
1462            // cabi_post
1463            if matches!(variant, AbiVariant::GuestExport)
1464                && abi::guest_export_needs_post_return(self.resolve, func)
1465            {
1466                let sig = self.resolve.wasm_signature(variant, func);
1467                let module_name = self.wasm_import_module.clone();
1468                let export_name = match module_name {
1469                    Some(ref module_name) => {
1470                        format!("{module_name}#{}", func.name)
1471                    }
1472                    None => make_external_component(&func.name),
1473                };
1474                let import_name = match module_name {
1475                    Some(ref module_name) => {
1476                        make_external_symbol(module_name, &func.name, AbiVariant::GuestExport)
1477                    }
1478                    None => make_external_component(&func.name),
1479                };
1480                uwriteln!(
1481                    self.r#gen.c_src.src,
1482                    "extern \"C\" __attribute__((__weak__, __export_name__(\"cabi_post_{export_name}\")))"
1483                );
1484                uwrite!(self.r#gen.c_src.src, "void cabi_post_{import_name}(");
1485
1486                let mut params = Vec::new();
1487                for (i, result) in sig.results.iter().enumerate() {
1488                    let name = format!("arg{i}");
1489                    uwrite!(
1490                        self.r#gen.c_src.src,
1491                        "{} {name}",
1492                        wit_bindgen_c::wasm_type(*result)
1493                    );
1494                    params.push(name);
1495                }
1496                self.r#gen.c_src.src.push_str(") {\n");
1497
1498                let mut f = FunctionBindgen::new(self, params.clone());
1499                f.params = params;
1500                abi::post_return(f.r#gen.resolve, func, &mut f);
1501                let ret_area_decl = f.emit_ret_area_if_needed();
1502                let code = format!("{}{}", ret_area_decl, String::from(f.src));
1503                self.r#gen.c_src.src.push_str(&code);
1504                self.r#gen.c_src.src.push_str("}\n");
1505            }
1506        }
1507    }
1508
1509    // in C this is print_optional_ty
1510    fn optional_type_name(
1511        &mut self,
1512        ty: Option<&Type>,
1513        from_namespace: &[String],
1514        flavor: Flavor,
1515    ) -> String {
1516        match ty {
1517            Some(ty) => self.type_name(ty, from_namespace, flavor),
1518            None => "void".into(),
1519        }
1520    }
1521
1522    fn scoped_record_name(
1523        &self,
1524        id: TypeId,
1525        from_namespace: &[String],
1526        guest_export: bool,
1527        flavor: Flavor,
1528    ) -> String {
1529        let name = self.scoped_type_name(id, from_namespace, guest_export);
1530
1531        if let Flavor::Argument(AbiVariant::GuestImport) = flavor {
1532            match self.r#gen.opts.ownership {
1533                Ownership::Owning => name.to_string(),
1534                Ownership::CoarseBorrowing => {
1535                    if self.r#gen.types.get(id).has_own_handle {
1536                        name.to_string()
1537                    } else {
1538                        format!("{name}Param")
1539                    }
1540                }
1541                Ownership::FineBorrowing => {
1542                    format!("{name}Param")
1543                }
1544            }
1545        } else {
1546            name
1547        }
1548    }
1549
1550    fn scoped_type_name(
1551        &self,
1552        id: TypeId,
1553        from_namespace: &[String],
1554        guest_export: bool,
1555    ) -> String {
1556        let ty = &self.resolve.types[id];
1557        let namespc = namespace(self.resolve, &ty.owner, guest_export, &*self.r#gen);
1558        let mut relative = SourceWithState {
1559            namespace: Vec::from(from_namespace),
1560            ..Default::default()
1561        };
1562        relative.qualify(&namespc);
1563        format!(
1564            "{}{}",
1565            &*relative.src,
1566            ty.name.as_ref().unwrap().to_pascal_case()
1567        )
1568    }
1569
1570    fn type_name(&mut self, ty: &Type, from_namespace: &[String], flavor: Flavor) -> String {
1571        match ty {
1572            Type::Bool => "bool".into(),
1573            Type::Char => "uint32_t".into(),
1574            Type::U8 => "uint8_t".into(),
1575            Type::S8 => "int8_t".into(),
1576            Type::U16 => "uint16_t".into(),
1577            Type::S16 => "int16_t".into(),
1578            Type::U32 => "uint32_t".into(),
1579            Type::S32 => "int32_t".into(),
1580            Type::U64 => "uint64_t".into(),
1581            Type::S64 => "int64_t".into(),
1582            Type::F32 => "float".into(),
1583            Type::F64 => "double".into(),
1584            Type::String => match flavor {
1585                Flavor::BorrowedArgument => {
1586                    self.r#gen.dependencies.needs_string_view = true;
1587                    "std::string_view".into()
1588                }
1589                Flavor::Argument(var)
1590                    if matches!(var, AbiVariant::GuestImport)
1591                        || self.r#gen.opts.api_style == APIStyle::Symmetric =>
1592                {
1593                    self.r#gen.dependencies.needs_string_view = true;
1594                    "std::string_view".into()
1595                }
1596                Flavor::Argument(AbiVariant::GuestExport) => {
1597                    self.r#gen.dependencies.needs_wit = true;
1598                    "wit::string".into()
1599                }
1600                _ => {
1601                    self.r#gen.dependencies.needs_wit = true;
1602                    "wit::string".into()
1603                }
1604            },
1605            Type::Id(id) => match &self.resolve.types[*id].kind {
1606                TypeDefKind::Record(_) => {
1607                    let guest_export = self.is_exported_type(&self.resolve.types[*id]);
1608                    self.scoped_record_name(*id, from_namespace, guest_export, flavor)
1609                }
1610                TypeDefKind::Resource => {
1611                    let guest_export = self.is_exported_type(&self.resolve.types[*id]);
1612                    self.scoped_type_name(*id, from_namespace, guest_export)
1613                }
1614                TypeDefKind::Handle(Handle::Own(id)) => {
1615                    let mut typename = self.type_name(&Type::Id(*id), from_namespace, flavor);
1616                    let ty = &self.resolve.types[*id];
1617
1618                    // Follow type aliases to find the actual resource definition
1619                    // When a resource is `use`d in another interface, we have a type alias
1620                    // with the new interface as owner. We need to follow to the original resource.
1621                    let resource_ty = match &ty.kind {
1622                        TypeDefKind::Type(Type::Id(resource_id)) => {
1623                            &self.resolve.types[*resource_id]
1624                        }
1625                        _ => ty,
1626                    };
1627
1628                    let is_exported = self.is_exported_type(resource_ty);
1629                    match (false, flavor) {
1630                        (false, Flavor::Argument(AbiVariant::GuestImport))
1631                        | (true, Flavor::Argument(AbiVariant::GuestExport)) => {
1632                            typename.push_str("&&")
1633                        }
1634                        (false, Flavor::Argument(AbiVariant::GuestExport))
1635                        | (false, Flavor::Result(AbiVariant::GuestExport))
1636                        | (true, Flavor::Argument(AbiVariant::GuestImport))
1637                        | (true, Flavor::Result(AbiVariant::GuestImport)) => {
1638                            // Only exported resources have ::Owned typedef
1639                            if is_exported {
1640                                typename.push_str(&format!("::{OWNED_CLASS_NAME}"))
1641                            } else {
1642                                typename.push_str("&&")
1643                            }
1644                        }
1645                        (false, Flavor::Result(AbiVariant::GuestImport))
1646                        | (true, Flavor::Result(AbiVariant::GuestExport)) => (),
1647                        (_, Flavor::InStruct) => (),
1648                        (false, Flavor::BorrowedArgument) => (),
1649                        (_, _) => todo!(),
1650                    }
1651                    if matches!(flavor, Flavor::InStruct) && is_exported {
1652                        typename.push_str(&format!("::{OWNED_CLASS_NAME}"))
1653                    }
1654                    typename
1655                }
1656                TypeDefKind::Handle(Handle::Borrow(id)) => {
1657                    "std::reference_wrapper<const ".to_string()
1658                        + &self.type_name(&Type::Id(*id), from_namespace, flavor)
1659                        + ">"
1660                }
1661                TypeDefKind::Flags(_f) => {
1662                    let ty = &self.resolve.types[*id];
1663                    let guest_export = self.is_exported_type(ty);
1664                    self.scoped_type_name(*id, from_namespace, guest_export)
1665                }
1666                TypeDefKind::Tuple(t) => {
1667                    let types = t.types.iter().fold(String::new(), |mut a, b| {
1668                        if !a.is_empty() {
1669                            a += ", ";
1670                        }
1671                        a + &self.type_name(b, from_namespace, flavor)
1672                    });
1673                    self.r#gen.dependencies.needs_tuple = true;
1674                    String::from("std::tuple<") + &types + ">"
1675                }
1676                TypeDefKind::Variant(_v) => {
1677                    let ty = &self.resolve.types[*id];
1678                    let guest_export = self.is_exported_type(ty);
1679                    self.scoped_type_name(*id, from_namespace, guest_export)
1680                }
1681                TypeDefKind::Enum(_e) => {
1682                    let ty = &self.resolve.types[*id];
1683                    let guest_export = self.is_exported_type(ty);
1684                    self.scoped_type_name(*id, from_namespace, guest_export)
1685                }
1686                TypeDefKind::Option(o) => {
1687                    // Template parameters need base types without && or other decorations
1688                    // For import arguments, use BorrowedArgument flavor to get string_view
1689                    let template_flavor = match flavor {
1690                        Flavor::Argument(AbiVariant::GuestImport) => Flavor::BorrowedArgument,
1691                        _ => Flavor::InStruct,
1692                    };
1693                    self.r#gen.dependencies.needs_optional = true;
1694                    "std::optional<".to_string()
1695                        + &self.type_name(o, from_namespace, template_flavor)
1696                        + ">"
1697                }
1698                TypeDefKind::Result(r) => {
1699                    // Template parameters need base types without && or other decorations
1700                    let template_flavor = Flavor::InStruct;
1701                    let err_type = r.err.as_ref().map_or(String::from("wit::Void"), |ty| {
1702                        self.type_name(ty, from_namespace, template_flavor)
1703                    });
1704                    self.r#gen.dependencies.needs_expected = true;
1705                    "std::expected<".to_string()
1706                        + &self.optional_type_name(r.ok.as_ref(), from_namespace, template_flavor)
1707                        + ", "
1708                        + &err_type
1709                        + ">"
1710                }
1711                TypeDefKind::List(ty) => {
1712                    // For list elements, use BorrowedArgument flavor for imported functions
1713                    // to get std::string_view instead of wit::string. Otherwise use InStruct
1714                    // flavor to avoid adding && to owned resources (lists contain values, not rvalue references)
1715                    let element_flavor = match flavor {
1716                        Flavor::BorrowedArgument | Flavor::Argument(AbiVariant::GuestImport) => {
1717                            Flavor::BorrowedArgument
1718                        }
1719                        _ => Flavor::InStruct,
1720                    };
1721                    let inner = self.type_name(ty, from_namespace, element_flavor);
1722                    match flavor {
1723                        Flavor::BorrowedArgument => {
1724                            self.r#gen.dependencies.needs_span = true;
1725                            format!("std::span<{inner} const>")
1726                        }
1727                        Flavor::Argument(var)
1728                            if matches!(var, AbiVariant::GuestImport)
1729                                || self.r#gen.opts.api_style == APIStyle::Symmetric =>
1730                        {
1731                            self.r#gen.dependencies.needs_span = true;
1732                            // If the list has an owning handle, it must support moving, so can't be const
1733                            let constness = if self.r#gen.types.get(*id).has_own_handle {
1734                                ""
1735                            } else {
1736                                " const"
1737                            };
1738                            format!("std::span<{inner}{constness}>")
1739                        }
1740                        Flavor::Argument(AbiVariant::GuestExport) => {
1741                            self.r#gen.dependencies.needs_wit = true;
1742                            format!("wit::vector<{inner}>")
1743                        }
1744                        _ => {
1745                            self.r#gen.dependencies.needs_wit = true;
1746                            format!("wit::vector<{inner}>")
1747                        }
1748                    }
1749                }
1750                TypeDefKind::Future(_) => todo!(),
1751                TypeDefKind::Stream(_) => todo!(),
1752                TypeDefKind::Type(ty) => self.type_name(ty, from_namespace, flavor),
1753                TypeDefKind::FixedLengthList(ty, size) => {
1754                    self.r#gen.dependencies.needs_array = true;
1755                    format!(
1756                        "std::array<{}, {size}>",
1757                        self.type_name(ty, from_namespace, flavor)
1758                    )
1759                }
1760                TypeDefKind::Map(key, value) => {
1761                    let borrowed = match flavor {
1762                        Flavor::BorrowedArgument => true,
1763                        Flavor::Argument(var) => {
1764                            matches!(var, AbiVariant::GuestImport)
1765                                || self.r#gen.opts.api_style == APIStyle::Symmetric
1766                        }
1767                        _ => false,
1768                    };
1769                    let element_flavor = if borrowed {
1770                        Flavor::BorrowedArgument
1771                    } else {
1772                        Flavor::InStruct
1773                    };
1774                    let k = self.type_name(key, from_namespace, element_flavor);
1775                    let v = self.type_name(value, from_namespace, element_flavor);
1776                    if borrowed {
1777                        self.r#gen.dependencies.needs_span = true;
1778                        format!("std::span<std::pair<{k}, {v}> const>")
1779                    } else {
1780                        self.r#gen.dependencies.needs_wit = true;
1781                        format!("wit::unordered_map<{k}, {v}>")
1782                    }
1783                }
1784                TypeDefKind::Unknown => todo!(),
1785            },
1786            Type::ErrorContext => todo!(),
1787        }
1788    }
1789
1790    fn declare_import2(
1791        &self,
1792        module_name: &str,
1793        name: &str,
1794        args: &str,
1795        result: &str,
1796        variant: AbiVariant,
1797    ) -> (String, String) {
1798        let mut extern_name = String::from("__wasm_import_");
1799        extern_name.push_str(&make_external_symbol(module_name, name, variant));
1800        let import = format!(
1801            "extern \"C\" __attribute__((import_module(\"{module_name}\")))\n __attribute__((import_name(\"{name}\")))\n {result} {extern_name}({args});\n"
1802        );
1803        (extern_name, import)
1804    }
1805
1806    fn declare_import(
1807        &mut self,
1808        module_name: &str,
1809        name: &str,
1810        params: &[WasmType],
1811        results: &[WasmType],
1812    ) -> String {
1813        let mut args = String::default();
1814        for (n, param) in params.iter().enumerate() {
1815            args.push_str(wit_bindgen_c::wasm_type(*param));
1816            if n + 1 != params.len() {
1817                args.push_str(", ");
1818            }
1819        }
1820        let result = if results.is_empty() {
1821            "void"
1822        } else {
1823            wit_bindgen_c::wasm_type(results[0])
1824        };
1825        let variant = AbiVariant::GuestImport;
1826        let (name, code) = self.declare_import2(module_name, name, &args, result, variant);
1827        self.r#gen.extern_c_decls.push_str(&code);
1828        name
1829    }
1830
1831    fn docs(src: &mut Source, docs: &Docs) {
1832        if let Some(docs) = docs.contents.as_ref() {
1833            for line in docs.trim().lines() {
1834                src.push_str("/// ");
1835                src.push_str(line);
1836                src.push_str("\n");
1837            }
1838        }
1839    }
1840
1841    fn type_record_param(
1842        &mut self,
1843        id: TypeId,
1844        name: &str,
1845        record: &wit_bindgen_core::wit_parser::Record,
1846        namespc: &[String],
1847    ) {
1848        let (flavor, needs_param_type) = {
1849            match self.r#gen.opts.ownership {
1850                Ownership::Owning => (Flavor::InStruct, false),
1851                Ownership::CoarseBorrowing => {
1852                    if self.r#gen.types.get(id).has_own_handle {
1853                        (Flavor::InStruct, false)
1854                    } else {
1855                        (Flavor::BorrowedArgument, true)
1856                    }
1857                }
1858                Ownership::FineBorrowing => (Flavor::BorrowedArgument, true),
1859            }
1860        };
1861
1862        if needs_param_type {
1863            let pascal = format!("{name}-param").to_pascal_case();
1864
1865            uwriteln!(self.r#gen.h_src.src, "struct {pascal} {{");
1866            for field in record.fields.iter() {
1867                let typename = self.type_name(&field.ty, namespc, flavor);
1868                let fname = to_c_ident(&field.name);
1869                uwriteln!(self.r#gen.h_src.src, "{typename} {fname};");
1870            }
1871            uwriteln!(self.r#gen.h_src.src, "}};");
1872        }
1873    }
1874
1875    fn is_exported_type(&self, ty: &TypeDef) -> bool {
1876        match ty.owner {
1877            TypeOwner::Interface(intf) => {
1878                // For resources used in export functions, check if the resource's owner
1879                // interface is in imported_interfaces (which was populated during import())
1880                !self.r#gen.imported_interfaces.contains(&intf)
1881            }
1882            TypeOwner::World(_) => {
1883                // World-level resources are treated as imports, not exports
1884                false
1885            }
1886            TypeOwner::None => true,
1887        }
1888    }
1889}
1890
1891impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for CppInterfaceGenerator<'a> {
1892    fn resolve(&self) -> &'a Resolve {
1893        self.resolve
1894    }
1895
1896    fn type_record(
1897        &mut self,
1898        id: TypeId,
1899        name: &str,
1900        record: &wit_bindgen_core::wit_parser::Record,
1901        docs: &wit_bindgen_core::wit_parser::Docs,
1902    ) {
1903        let ty = &self.resolve.types[id];
1904        let guest_export = self.is_exported_type(ty);
1905        let namespc = namespace(self.resolve, &ty.owner, guest_export, &*self.r#gen);
1906
1907        if self.r#gen.is_first_definition(&namespc, name) {
1908            self.r#gen.h_src.change_namespace(&namespc);
1909            Self::docs(&mut self.r#gen.h_src.src, docs);
1910            let pascal = name.to_pascal_case();
1911
1912            uwriteln!(self.r#gen.h_src.src, "struct {pascal} {{");
1913            for field in record.fields.iter() {
1914                Self::docs(&mut self.r#gen.h_src.src, &field.docs);
1915                let typename = self.type_name(&field.ty, &namespc, Flavor::InStruct);
1916                let fname = to_c_ident(&field.name);
1917                uwriteln!(self.r#gen.h_src.src, "{typename} {fname};");
1918            }
1919            uwriteln!(self.r#gen.h_src.src, "}};");
1920            self.type_record_param(id, name, record, namespc.as_slice());
1921        }
1922    }
1923
1924    fn type_resource(
1925        &mut self,
1926        id: TypeId,
1927        name: &str,
1928        _docs: &wit_bindgen_core::wit_parser::Docs,
1929    ) {
1930        let type_ = &self.resolve.types[id];
1931        if let TypeOwner::Interface(intf) = type_.owner {
1932            let guest_import = self.r#gen.imported_interfaces.contains(&intf);
1933            let definition = !(guest_import);
1934            let store = self.r#gen.start_new_file(Some(definition));
1935            let mut world_name = to_c_ident(&self.r#gen.world);
1936            world_name.push_str("::");
1937            let namespc = namespace(self.resolve, &type_.owner, !guest_import, &*self.r#gen);
1938            let pascal = name.to_upper_camel_case();
1939            let mut user_filename = namespc.clone();
1940            user_filename.push(pascal.clone());
1941            if definition {
1942                uwriteln!(
1943                    self.r#gen.h_src.src,
1944                    r#"/* User class definition file, autogenerated once, then user modified
1945                    * Updated versions of this file are generated into {pascal}.template.
1946                    */"#
1947                );
1948            }
1949            self.r#gen.h_src.change_namespace(&namespc);
1950
1951            if !definition {
1952                self.r#gen.dependencies.needs_imported_resources = true;
1953            } else {
1954                self.r#gen.dependencies.needs_exported_resources = true;
1955            }
1956            self.r#gen.dependencies.needs_wit = true;
1957
1958            let base_type = match (definition, false) {
1959                (true, false) => format!("wit::{RESOURCE_EXPORT_BASE_CLASS_NAME}<{pascal}>"),
1960                (false, false) => {
1961                    String::from_str("wit::").unwrap() + RESOURCE_IMPORT_BASE_CLASS_NAME
1962                }
1963                (false, true) => {
1964                    String::from_str("wit::").unwrap() + RESOURCE_EXPORT_BASE_CLASS_NAME
1965                }
1966                (true, true) => format!("wit::{RESOURCE_IMPORT_BASE_CLASS_NAME}<{pascal}>"),
1967            };
1968            let derive = format!(" : public {base_type}");
1969            uwriteln!(self.r#gen.h_src.src, "class {pascal}{derive} {{\n");
1970            uwriteln!(self.r#gen.h_src.src, "public:\n");
1971            let variant = if guest_import {
1972                AbiVariant::GuestImport
1973            } else {
1974                AbiVariant::GuestExport
1975            };
1976            {
1977                // destructor
1978                let name = match variant {
1979                    AbiVariant::GuestImport => "[resource-drop]",
1980                    AbiVariant::GuestExport => "[dtor]",
1981                    AbiVariant::GuestImportAsync => todo!(),
1982                    AbiVariant::GuestExportAsync => todo!(),
1983                    AbiVariant::GuestExportAsyncStackful => todo!(),
1984                }
1985                .to_string()
1986                    + name;
1987                let func = Function {
1988                    name,
1989                    kind: FunctionKind::Static(id),
1990                    params: vec![Param {
1991                        name: "self".into(),
1992                        ty: Type::Id(id),
1993                        span: Default::default(),
1994                    }],
1995                    result: None,
1996                    docs: Docs::default(),
1997                    stability: Stability::Unknown,
1998                    span: Default::default(),
1999                    external_id: None,
2000                };
2001                self.generate_function(&func, &TypeOwner::Interface(intf), variant);
2002            }
2003            let funcs = self.resolve.interfaces[intf].functions.values();
2004            for func in funcs {
2005                if match &func.kind {
2006                    FunctionKind::Freestanding => false,
2007                    FunctionKind::Method(mid) => *mid == id,
2008                    FunctionKind::Static(mid) => *mid == id,
2009                    FunctionKind::Constructor(mid) => *mid == id,
2010                    FunctionKind::AsyncFreestanding => todo!(),
2011                    FunctionKind::AsyncMethod(_id) => todo!(),
2012                    FunctionKind::AsyncStatic(_id) => todo!(),
2013                } {
2014                    self.generate_function(func, &TypeOwner::Interface(intf), variant);
2015                    // For non-fallible constructors on export side, generate a New allocator method
2016                    // For fallible constructors, the user provides their own Create method
2017                    let is_fallible_constructor =
2018                        self.r#gen.is_fallible_constructor(self.resolve, func);
2019
2020                    if matches!(func.kind, FunctionKind::Constructor(_))
2021                        && matches!(variant, AbiVariant::GuestExport)
2022                        && !is_fallible_constructor
2023                    {
2024                        // functional safety requires the option to use a different allocator, so move new into the implementation
2025                        let func2 = Function {
2026                            name: "$alloc".to_string(),
2027                            kind: FunctionKind::Static(id),
2028                            // same params as constructor
2029                            params: func.params.clone(),
2030                            result: Some(Type::Id(id)),
2031                            docs: Docs::default(),
2032                            stability: Stability::Unknown,
2033                            span: Default::default(),
2034                            external_id: None,
2035                        };
2036                        self.generate_function(&func2, &TypeOwner::Interface(intf), variant);
2037                    }
2038                }
2039            }
2040
2041            if !definition {
2042                // consuming constructor from handle (bindings)
2043                uwriteln!(self.r#gen.h_src.src, "{pascal}({base_type} &&);",);
2044                uwriteln!(self.r#gen.h_src.src, "{pascal}({pascal}&&) = default;");
2045                uwriteln!(
2046                    self.r#gen.h_src.src,
2047                    "{pascal}& operator=({pascal}&&) = default;"
2048                );
2049                self.r#gen.c_src.qualify(&namespc);
2050                uwriteln!(
2051                    self.r#gen.c_src.src,
2052                    "{pascal}::{pascal}({base_type}&&b) : {base_type}(std::move(b)) {{}}"
2053                );
2054            }
2055            if matches!(variant, AbiVariant::GuestExport) {
2056                let id_type = Type::S32;
2057                let func = Function {
2058                    name: "[resource-new]".to_string() + name,
2059                    kind: FunctionKind::Static(id),
2060                    params: vec![Param {
2061                        name: "self".into(),
2062                        ty: Type::Id(id),
2063                        span: Default::default(),
2064                    }],
2065                    result: Some(id_type),
2066                    docs: Docs::default(),
2067                    stability: Stability::Unknown,
2068                    span: Default::default(),
2069                    external_id: None,
2070                };
2071                self.generate_function(&func, &TypeOwner::Interface(intf), variant);
2072
2073                let func1 = Function {
2074                    name: "[resource-rep]".to_string() + name,
2075                    kind: FunctionKind::Static(id),
2076                    params: vec![Param {
2077                        name: "id".into(),
2078                        ty: id_type,
2079                        span: Default::default(),
2080                    }],
2081                    result: Some(Type::Id(id)),
2082                    docs: Docs::default(),
2083                    stability: Stability::Unknown,
2084                    span: Default::default(),
2085                    external_id: None,
2086                };
2087                self.generate_function(&func1, &TypeOwner::Interface(intf), variant);
2088
2089                let func2 = Function {
2090                    name: "[resource-drop]".to_string() + name,
2091                    kind: FunctionKind::Static(id),
2092                    params: vec![Param {
2093                        name: "id".into(),
2094                        ty: id_type,
2095                        span: Default::default(),
2096                    }],
2097                    result: None,
2098                    docs: Docs::default(),
2099                    stability: Stability::Unknown,
2100                    span: Default::default(),
2101                    external_id: None,
2102                };
2103                self.generate_function(&func2, &TypeOwner::Interface(intf), variant);
2104            }
2105            uwriteln!(self.r#gen.h_src.src, "}};\n");
2106            self.r#gen.finish_file(&user_filename, store);
2107        } else if matches!(type_.owner, TypeOwner::World(_)) {
2108            // Handle world-level resources - treat as imported resources
2109            let guest_export = false; // World-level resources are treated as imports
2110            let namespc = namespace(self.resolve, &type_.owner, guest_export, &*self.r#gen);
2111            self.r#gen.h_src.change_namespace(&namespc);
2112
2113            let pascal = name.to_upper_camel_case();
2114            self.r#gen.dependencies.needs_imported_resources = true;
2115            self.r#gen.dependencies.needs_wit = true;
2116
2117            let base_type = format!("wit::{RESOURCE_IMPORT_BASE_CLASS_NAME}");
2118            let derive = format!(" : public {base_type}");
2119            uwriteln!(self.r#gen.h_src.src, "class {pascal}{derive}{{\n");
2120            uwriteln!(self.r#gen.h_src.src, "public:\n");
2121
2122            // Add destructor and constructor
2123            uwriteln!(self.r#gen.h_src.src, "~{pascal}();");
2124            uwriteln!(
2125                self.r#gen.h_src.src,
2126                "{pascal}(wit::{RESOURCE_IMPORT_BASE_CLASS_NAME} &&);"
2127            );
2128            uwriteln!(self.r#gen.h_src.src, "{pascal}({pascal}&&) = default;");
2129            uwriteln!(
2130                self.r#gen.h_src.src,
2131                "{pascal}& operator=({pascal}&&) = default;"
2132            );
2133            uwriteln!(self.r#gen.h_src.src, "}};\n");
2134        }
2135    }
2136
2137    fn type_flags(
2138        &mut self,
2139        id: TypeId,
2140        name: &str,
2141        flags: &wit_bindgen_core::wit_parser::Flags,
2142        docs: &wit_bindgen_core::wit_parser::Docs,
2143    ) {
2144        let ty = &self.resolve.types[id];
2145        let guest_export = self.is_exported_type(ty);
2146        let namespc = namespace(self.resolve, &ty.owner, guest_export, &*self.r#gen);
2147        if self.r#gen.is_first_definition(&namespc, name) {
2148            self.r#gen.h_src.change_namespace(&namespc);
2149            Self::docs(&mut self.r#gen.h_src.src, docs);
2150            let pascal = name.to_pascal_case();
2151            let int_repr = wit_bindgen_c::int_repr(wit_bindgen_c::flags_repr(flags));
2152            uwriteln!(self.r#gen.h_src.src, "enum class {pascal} : {int_repr} {{");
2153            uwriteln!(self.r#gen.h_src.src, "k_None = 0,");
2154            for (n, field) in flags.flags.iter().enumerate() {
2155                Self::docs(&mut self.r#gen.h_src.src, &field.docs);
2156                let fname = to_c_ident(&field.name).to_pascal_case();
2157                uwriteln!(self.r#gen.h_src.src, "k{fname} = (1ULL<<{n}),");
2158            }
2159            uwriteln!(self.r#gen.h_src.src, "}};");
2160            uwriteln!(
2161                self.r#gen.h_src.src,
2162                r#"static inline {pascal} operator|({pascal} a, {pascal} b) {{ return {pascal}({int_repr}(a)|{int_repr}(b)); }}
2163        static inline {pascal} operator&({pascal} a, {pascal} b) {{ return {pascal}({int_repr}(a)&{int_repr}(b)); }}"#
2164            );
2165        }
2166    }
2167
2168    fn type_tuple(
2169        &mut self,
2170        _id: TypeId,
2171        _name: &str,
2172        _flags: &wit_bindgen_core::wit_parser::Tuple,
2173        _docs: &wit_bindgen_core::wit_parser::Docs,
2174    ) {
2175        // I assume I don't need to do anything ...
2176    }
2177
2178    fn type_variant(
2179        &mut self,
2180        id: TypeId,
2181        name: &str,
2182        variant: &wit_bindgen_core::wit_parser::Variant,
2183        docs: &wit_bindgen_core::wit_parser::Docs,
2184    ) {
2185        let ty = &self.resolve.types[id];
2186        let guest_export = self.is_exported_type(ty);
2187        let namespc = namespace(self.resolve, &ty.owner, guest_export, &*self.r#gen);
2188        if self.r#gen.is_first_definition(&namespc, name) {
2189            self.r#gen.h_src.change_namespace(&namespc);
2190            Self::docs(&mut self.r#gen.h_src.src, docs);
2191            let pascal = name.to_pascal_case();
2192            uwriteln!(self.r#gen.h_src.src, "struct {pascal} {{");
2193            let mut inner_namespace = namespc.clone();
2194            inner_namespace.push(pascal.clone());
2195            let mut all_types = String::new();
2196            for case in variant.cases.iter() {
2197                Self::docs(&mut self.r#gen.h_src.src, &case.docs);
2198                let case_pascal = to_c_ident(&case.name).to_pascal_case();
2199                if !all_types.is_empty() {
2200                    all_types += ", ";
2201                }
2202                all_types += &case_pascal;
2203                uwrite!(self.r#gen.h_src.src, "struct {case_pascal} {{");
2204                if let Some(ty) = case.ty.as_ref() {
2205                    let typestr = self.type_name(ty, &inner_namespace, Flavor::InStruct);
2206                    uwrite!(self.r#gen.h_src.src, " {typestr} value; ")
2207                }
2208                uwriteln!(self.r#gen.h_src.src, "}};");
2209            }
2210            uwriteln!(
2211                self.r#gen.h_src.src,
2212                "  std::variant<{all_types}> variants;"
2213            );
2214            uwriteln!(self.r#gen.h_src.src, "}};");
2215            self.r#gen.dependencies.needs_variant = true;
2216        }
2217    }
2218
2219    fn type_option(
2220        &mut self,
2221        _id: TypeId,
2222        _name: &str,
2223        _payload: &wit_bindgen_core::wit_parser::Type,
2224        _docs: &wit_bindgen_core::wit_parser::Docs,
2225    ) {
2226        // nothing to do here
2227    }
2228
2229    fn type_result(
2230        &mut self,
2231        _id: TypeId,
2232        _name: &str,
2233        _result: &wit_bindgen_core::wit_parser::Result_,
2234        _docs: &wit_bindgen_core::wit_parser::Docs,
2235    ) {
2236        // nothing to do here
2237    }
2238
2239    fn type_enum(
2240        &mut self,
2241        id: TypeId,
2242        name: &str,
2243        enum_: &wit_bindgen_core::wit_parser::Enum,
2244        docs: &wit_bindgen_core::wit_parser::Docs,
2245    ) {
2246        let ty = &self.resolve.types[id];
2247        let guest_export = self.is_exported_type(ty);
2248        let namespc = namespace(self.resolve, &ty.owner, guest_export, &*self.r#gen);
2249        if self.r#gen.is_first_definition(&namespc, name) {
2250            self.r#gen.h_src.change_namespace(&namespc);
2251            let pascal = name.to_pascal_case();
2252            Self::docs(&mut self.r#gen.h_src.src, docs);
2253            let int_t = wit_bindgen_c::int_repr(enum_.tag());
2254            uwriteln!(self.r#gen.h_src.src, "enum class {pascal} : {int_t} {{");
2255            for (i, case) in enum_.cases.iter().enumerate() {
2256                Self::docs(&mut self.r#gen.h_src.src, &case.docs);
2257                uwriteln!(
2258                    self.r#gen.h_src.src,
2259                    " k{} = {i},",
2260                    to_c_ident(&case.name).to_pascal_case(),
2261                );
2262            }
2263            uwriteln!(self.r#gen.h_src.src, "}};\n");
2264        }
2265    }
2266
2267    fn type_alias(
2268        &mut self,
2269        id: TypeId,
2270        name: &str,
2271        alias_type: &wit_bindgen_core::wit_parser::Type,
2272        docs: &wit_bindgen_core::wit_parser::Docs,
2273    ) {
2274        let ty = &self.resolve.types[id];
2275        let guest_export = self.is_exported_type(ty);
2276        let namespc = namespace(self.resolve, &ty.owner, guest_export, &*self.r#gen);
2277        self.r#gen.h_src.change_namespace(&namespc);
2278        let pascal = name.to_pascal_case();
2279        Self::docs(&mut self.r#gen.h_src.src, docs);
2280        let typename = self.type_name(alias_type, &namespc, Flavor::InStruct);
2281        uwriteln!(self.r#gen.h_src.src, "using {pascal} = {typename};");
2282    }
2283
2284    fn type_list(
2285        &mut self,
2286        _id: TypeId,
2287        _name: &str,
2288        _ty: &wit_bindgen_core::wit_parser::Type,
2289        _docs: &wit_bindgen_core::wit_parser::Docs,
2290    ) {
2291        // nothing to do here
2292    }
2293
2294    fn type_fixed_length_list(
2295        &mut self,
2296        _id: TypeId,
2297        _name: &str,
2298        _ty: &wit_bindgen_core::wit_parser::Type,
2299        _size: u32,
2300        _docs: &wit_bindgen_core::wit_parser::Docs,
2301    ) {
2302        todo!("named fixed-length list types are not yet supported in the C++ backend")
2303    }
2304
2305    fn type_map(
2306        &mut self,
2307        _id: TypeId,
2308        _name: &str,
2309        _key: &wit_bindgen_core::wit_parser::Type,
2310        _value: &wit_bindgen_core::wit_parser::Type,
2311        _docs: &wit_bindgen_core::wit_parser::Docs,
2312    ) {
2313        // nothing to do here
2314    }
2315
2316    fn type_builtin(
2317        &mut self,
2318        _id: TypeId,
2319        _name: &str,
2320        _ty: &wit_bindgen_core::wit_parser::Type,
2321        _docs: &wit_bindgen_core::wit_parser::Docs,
2322    ) {
2323        todo!()
2324    }
2325
2326    fn type_future(&mut self, _id: TypeId, _name: &str, _ty: &Option<Type>, _docs: &Docs) {
2327        todo!()
2328    }
2329
2330    fn type_stream(&mut self, _id: TypeId, _name: &str, _ty: &Option<Type>, _docs: &Docs) {
2331        todo!()
2332    }
2333}
2334
2335struct CabiPostInformation {
2336    module: String,
2337    name: String,
2338    ret_type: String,
2339}
2340
2341struct FunctionBindgen<'a, 'b> {
2342    r#gen: &'b mut CppInterfaceGenerator<'a>,
2343    params: Vec<String>,
2344    tmp: usize,
2345    namespace: Vec<String>,
2346    src: Source,
2347    block_storage: Vec<wit_bindgen_core::Source>,
2348    /// intermediate calculations for contained objects
2349    blocks: Vec<(String, Vec<String>)>,
2350    payloads: Vec<String>,
2351    // caching for wasm
2352    variant: AbiVariant,
2353    cabi_post: Option<CabiPostInformation>,
2354    needs_dealloc: bool,
2355    leak_on_insertion: Option<String>,
2356    return_pointer_area_size: ArchitectureSize,
2357    return_pointer_area_align: Alignment,
2358}
2359
2360impl<'a, 'b> FunctionBindgen<'a, 'b> {
2361    fn new(r#gen: &'b mut CppInterfaceGenerator<'a>, params: Vec<String>) -> Self {
2362        Self {
2363            r#gen,
2364            params,
2365            tmp: 0,
2366            namespace: Default::default(),
2367            src: Default::default(),
2368            block_storage: Default::default(),
2369            blocks: Default::default(),
2370            payloads: Default::default(),
2371            variant: AbiVariant::GuestImport,
2372            cabi_post: None,
2373            needs_dealloc: false,
2374            leak_on_insertion: None,
2375            return_pointer_area_size: Default::default(),
2376            return_pointer_area_align: Default::default(),
2377        }
2378    }
2379
2380    fn tmp(&mut self) -> usize {
2381        let ret = self.tmp;
2382        self.tmp += 1;
2383        ret
2384    }
2385
2386    fn tempname(&self, base: &str, idx: usize) -> String {
2387        format!("{base}{idx}")
2388    }
2389
2390    fn push_str(&mut self, s: &str) {
2391        self.src.push_str(s);
2392    }
2393
2394    fn let_results(&mut self, amt: usize, results: &mut Vec<String>) {
2395        if amt > 0 {
2396            let tmp = self.tmp();
2397            let res = format!("result{tmp}");
2398            self.push_str("auto ");
2399            self.push_str(&res);
2400            self.push_str(" = ");
2401            if amt == 1 {
2402                results.push(res);
2403            } else {
2404                for i in 0..amt {
2405                    results.push(format!("std::get<{i}>({res})"));
2406                }
2407            }
2408        }
2409    }
2410
2411    fn load(
2412        &mut self,
2413        ty: &str,
2414        offset: ArchitectureSize,
2415        operands: &[String],
2416        results: &mut Vec<String>,
2417    ) {
2418        results.push(format!(
2419            "*(({}*) ({} + {}))",
2420            ty,
2421            operands[0],
2422            offset.format(POINTER_SIZE_EXPRESSION)
2423        ));
2424    }
2425
2426    fn load_ext(
2427        &mut self,
2428        ty: &str,
2429        offset: ArchitectureSize,
2430        operands: &[String],
2431        results: &mut Vec<String>,
2432    ) {
2433        self.load(ty, offset, operands, results);
2434        let result = results.pop().unwrap();
2435        results.push(format!("(int32_t) ({result})"));
2436    }
2437
2438    fn store(&mut self, ty: &str, offset: ArchitectureSize, operands: &[String]) {
2439        uwriteln!(
2440            self.src,
2441            "*(({}*)({} + {})) = {};",
2442            ty,
2443            operands[1],
2444            offset.format(POINTER_SIZE_EXPRESSION),
2445            operands[0]
2446        );
2447    }
2448
2449    /// Emits a shared return area declaration if needed by this function.
2450    ///
2451    /// During code generation, `return_pointer()` may be called multiple times for:
2452    /// - Indirect parameter storage (when too many/large params)
2453    /// - Return value storage (when return type is too large)
2454    ///
2455    /// **Safety:** This is safe because return pointers are used sequentially:
2456    /// 1. Parameter marshaling (before call)
2457    /// 2. Function execution
2458    /// 3. Return value unmarshaling (after call)
2459    ///
2460    /// The scratch space is reused but never accessed simultaneously.
2461    fn emit_ret_area_if_needed(&self) -> String {
2462        if !self.return_pointer_area_size.is_empty() {
2463            let size_string = self
2464                .return_pointer_area_size
2465                .format(POINTER_SIZE_EXPRESSION);
2466            let tp = match self.return_pointer_area_align {
2467                Alignment::Bytes(bytes) => match bytes.get() {
2468                    1 => "uint8_t",
2469                    2 => "uint16_t",
2470                    4 => "uint32_t",
2471                    8 => "uint64_t",
2472                    // Fallback to uint8_t for unusual alignments (e.g., 16-byte SIMD).
2473                    // This is safe: the size calculation ensures correct buffer size,
2474                    // and uint8_t arrays can store any data regardless of alignment.
2475                    _ => "uint8_t",
2476                },
2477                Alignment::Pointer => "uintptr_t",
2478            };
2479            let static_var = if self.r#gen.in_guest_import {
2480                ""
2481            } else {
2482                "static "
2483            };
2484            format!("{static_var}{tp} ret_area[({size_string}+sizeof({tp})-1)/sizeof({tp})];\n")
2485        } else {
2486            String::new()
2487        }
2488    }
2489}
2490
2491fn move_if_necessary(arg: &str) -> String {
2492    // if it is a name of a variable move it
2493    if !arg.is_empty() && arg.chars().all(|c| char::is_alphanumeric(c) || c == '_') {
2494        format!("std::move({arg})")
2495    } else {
2496        arg.into()
2497    }
2498}
2499
2500impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> {
2501    type Operand = String;
2502
2503    fn emit(
2504        &mut self,
2505        _resolve: &Resolve,
2506        inst: &wit_bindgen_core::abi::Instruction<'_>,
2507        operands: &mut Vec<Self::Operand>,
2508        results: &mut Vec<Self::Operand>,
2509    ) {
2510        let mut top_as = |cvt: &str| {
2511            results.push(format!("({cvt}({}))", operands.pop().unwrap()));
2512        };
2513
2514        match inst {
2515            abi::Instruction::GetArg { nth } => {
2516                if *nth == 0 && self.params[0].as_str() == "self" {
2517                    if self.r#gen.in_guest_import {
2518                        results.push("(*this)".to_string());
2519                    } else {
2520                        results.push("(*lookup_resource(self))".to_string());
2521                    }
2522                } else {
2523                    results.push(self.params[*nth].clone());
2524                }
2525            }
2526            abi::Instruction::I32Const { val } => results.push(format!("(int32_t({val}))")),
2527            abi::Instruction::Bitcasts { casts } => {
2528                for (cast, op) in casts.iter().zip(operands) {
2529                    // let op = op;
2530                    results.push(self.r#gen.r#gen.perform_cast(op, cast));
2531                }
2532            }
2533            abi::Instruction::ConstZero { tys } => {
2534                for ty in tys.iter() {
2535                    match ty {
2536                        WasmType::I32 => results.push("int32_t(0)".to_string()),
2537                        WasmType::I64 => results.push("int64_t(0)".to_string()),
2538                        WasmType::F32 => results.push("0.0f".to_string()),
2539                        WasmType::F64 => results.push("0.0".to_string()),
2540                        WasmType::Length => results.push("size_t(0)".to_string()),
2541                        WasmType::Pointer => results.push("nullptr".to_string()),
2542                        WasmType::PointerOrI64 => results.push("int64_t(0)".to_string()),
2543                    }
2544                }
2545            }
2546            abi::Instruction::I32Load { offset } => {
2547                let tmp = self.tmp();
2548                uwriteln!(
2549                    self.src,
2550                    "int32_t l{tmp} = *((int32_t const*)({} + {offset}));",
2551                    operands[0],
2552                    offset = offset.format(POINTER_SIZE_EXPRESSION)
2553                );
2554                results.push(format!("l{tmp}"));
2555            }
2556            abi::Instruction::I32Load8U { offset } => {
2557                self.load_ext("uint8_t", *offset, operands, results)
2558            }
2559            abi::Instruction::I32Load8S { offset } => {
2560                self.load_ext("int8_t", *offset, operands, results)
2561            }
2562            abi::Instruction::I32Load16U { offset } => {
2563                self.load_ext("uint16_t", *offset, operands, results)
2564            }
2565            abi::Instruction::I32Load16S { offset } => {
2566                self.load_ext("int16_t", *offset, operands, results)
2567            }
2568            abi::Instruction::I64Load { offset } => {
2569                self.load("int64_t", *offset, operands, results)
2570            }
2571            abi::Instruction::F32Load { offset } => self.load("float", *offset, operands, results),
2572            abi::Instruction::F64Load { offset } => self.load("double", *offset, operands, results),
2573            abi::Instruction::I32Store { offset } => self.store("int32_t", *offset, operands),
2574            abi::Instruction::I32Store8 { offset } => self.store("int8_t", *offset, operands),
2575            abi::Instruction::I32Store16 { offset } => self.store("int16_t", *offset, operands),
2576            abi::Instruction::I64Store { offset } => self.store("int64_t", *offset, operands),
2577            abi::Instruction::F32Store { offset } => self.store("float", *offset, operands),
2578            abi::Instruction::F64Store { offset } => self.store("double", *offset, operands),
2579            abi::Instruction::I32FromChar
2580            | abi::Instruction::I32FromBool
2581            | abi::Instruction::I32FromU8
2582            | abi::Instruction::I32FromS8
2583            | abi::Instruction::I32FromU16
2584            | abi::Instruction::I32FromS16
2585            | abi::Instruction::I32FromU32
2586            | abi::Instruction::I32FromS32 => top_as("int32_t"),
2587            abi::Instruction::I64FromU64 | abi::Instruction::I64FromS64 => top_as("int64_t"),
2588            abi::Instruction::F32FromCoreF32 => top_as("float"),
2589            abi::Instruction::F64FromCoreF64 => top_as("double"),
2590            abi::Instruction::S8FromI32 => top_as("int8_t"),
2591            abi::Instruction::U8FromI32 => top_as("uint8_t"),
2592            abi::Instruction::S16FromI32 => top_as("int16_t"),
2593            abi::Instruction::U16FromI32 => top_as("uint16_t"),
2594            abi::Instruction::S32FromI32 => top_as("int32_t"),
2595            abi::Instruction::U32FromI32 => top_as("uint32_t"),
2596            abi::Instruction::S64FromI64 => top_as("int64_t"),
2597            abi::Instruction::U64FromI64 => top_as("uint64_t"),
2598            abi::Instruction::CharFromI32 => top_as("uint32_t"),
2599            abi::Instruction::CoreF32FromF32 => top_as("float"),
2600            abi::Instruction::CoreF64FromF64 => top_as("double"),
2601            abi::Instruction::BoolFromI32 => top_as("bool"),
2602            abi::Instruction::ListCanonLower { realloc, .. } => {
2603                let tmp = self.tmp();
2604                let val = format!("_vec{tmp}");
2605                let ptr = format!("_ptr{tmp}");
2606                let len = format!("_len{tmp}");
2607                self.push_str(&format!("auto&& {} = {};\n", val, operands[0]));
2608                self.push_str(&format!(
2609                    "auto {} = ({})({}.data());\n",
2610                    ptr,
2611                    self.r#gen.r#gen.opts.ptr_type(),
2612                    val
2613                ));
2614                self.push_str(&format!("auto {len} = (size_t)({val}.size());\n"));
2615                if realloc.is_none() {
2616                    results.push(ptr);
2617                } else {
2618                    uwriteln!(self.src, "{}.leak();\n", operands[0]);
2619                    results.push(ptr);
2620                }
2621                results.push(len);
2622            }
2623            abi::Instruction::StringLower { realloc } => {
2624                let tmp = self.tmp();
2625                let val = format!("_vec{tmp}");
2626                let ptr = format!("_ptr{tmp}");
2627                let len = format!("_len{tmp}");
2628                self.push_str(&format!("auto&& {} = {};\n", val, operands[0]));
2629                self.push_str(&format!(
2630                    "auto {} = ({})({}.data());\n",
2631                    ptr,
2632                    self.r#gen.r#gen.opts.ptr_type(),
2633                    val
2634                ));
2635                self.push_str(&format!("auto {len} = (size_t)({val}.size());\n"));
2636                if realloc.is_none() {
2637                    results.push(ptr);
2638                } else {
2639                    uwriteln!(self.src, "{}.leak();\n", operands[0]);
2640                    results.push(ptr);
2641                }
2642                results.push(len);
2643            }
2644            abi::Instruction::ListLower { element, realloc } => {
2645                let tmp = self.tmp();
2646                let body = self.blocks.pop().unwrap();
2647                let val = format!("_vec{tmp}");
2648                let ptr = format!("_ptr{tmp}");
2649                let len = format!("_len{tmp}");
2650                let size = self.r#gen.sizes.size(element);
2651                self.push_str(&format!("auto&& {} = {};\n", val, operands[0]));
2652                self.push_str(&format!(
2653                    "auto {} = ({})({}.data());\n",
2654                    ptr,
2655                    self.r#gen.r#gen.opts.ptr_type(),
2656                    val
2657                ));
2658                self.push_str(&format!("auto {len} = (size_t)({val}.size());\n"));
2659                self.push_str(&format!("for (size_t i = 0; i < {len}; ++i) {{\n"));
2660                self.push_str(&format!(
2661                    "auto _base = {ptr} + i * {size};\n",
2662                    size = size.format(POINTER_SIZE_EXPRESSION)
2663                ));
2664                self.push_str(&format!("auto&& _iter_elem = {val}[i];\n"));
2665                self.push_str(&format!("{}\n", body.0));
2666                self.push_str("}\n");
2667                if realloc.is_none() {
2668                    results.push(ptr);
2669                } else {
2670                    uwriteln!(self.src, "{}.leak();\n", operands[0]);
2671                    results.push(ptr);
2672                }
2673                results.push(len);
2674            }
2675            abi::Instruction::ListCanonLift { element, .. } => {
2676                let tmp = self.tmp();
2677                let len = format!("_len{tmp}");
2678                let inner = self
2679                    .r#gen
2680                    .type_name(element, &self.namespace, Flavor::InStruct);
2681                self.push_str(&format!("auto {} = {};\n", len, operands[1]));
2682                let result = if self.r#gen.r#gen.opts.api_style == APIStyle::Symmetric
2683                    && matches!(self.variant, AbiVariant::GuestExport)
2684                {
2685                    format!(
2686                        "wit::vector<{inner} const>(({inner}*)({}), {len}).get_view()",
2687                        operands[0]
2688                    )
2689                } else {
2690                    format!("wit::vector<{inner}>(({inner}*)({}), {len})", operands[0])
2691                };
2692                results.push(result);
2693            }
2694            abi::Instruction::StringLift => {
2695                let tmp = self.tmp();
2696                let len = format!("_len{tmp}");
2697                uwriteln!(self.src, "auto {} = {};\n", len, operands[1]);
2698                let result = if self.r#gen.r#gen.opts.api_style == APIStyle::Symmetric
2699                    && matches!(self.variant, AbiVariant::GuestExport)
2700                {
2701                    assert!(self.needs_dealloc);
2702                    uwriteln!(
2703                        self.src,
2704                        "if ({len}>0) _deallocate.push_back({});\n",
2705                        operands[0]
2706                    );
2707                    format!("std::string_view((char const*)({}), {len})", operands[0])
2708                } else {
2709                    format!("wit::string((char const*)({}), {len})", operands[0])
2710                };
2711                results.push(result);
2712            }
2713            abi::Instruction::ListLift { element, .. } => {
2714                let body = self.blocks.pop().unwrap();
2715                let tmp = self.tmp();
2716                let size = self.r#gen.sizes.size(element);
2717                let _align = self.r#gen.sizes.align(element);
2718                let flavor = if self.r#gen.r#gen.opts.api_style == APIStyle::Symmetric
2719                    && matches!(self.variant, AbiVariant::GuestExport)
2720                {
2721                    Flavor::BorrowedArgument
2722                } else {
2723                    Flavor::InStruct
2724                };
2725                let vtype = self.r#gen.type_name(element, &self.namespace, flavor);
2726                let len = format!("_len{tmp}");
2727                let base = format!("_base{tmp}");
2728                let result = format!("_result{tmp}");
2729                self.push_str(&format!(
2730                    "auto {base} = {operand0};\n",
2731                    operand0 = operands[0]
2732                ));
2733                self.push_str(&format!(
2734                    "auto {len} = {operand1};\n",
2735                    operand1 = operands[1]
2736                ));
2737                self.push_str(&format!(
2738                    r#"auto {result} = wit::vector<{vtype}>::allocate({len});
2739                    "#,
2740                ));
2741
2742                if self.r#gen.r#gen.opts.api_style == APIStyle::Symmetric
2743                    && matches!(self.variant, AbiVariant::GuestExport)
2744                {
2745                    assert!(self.needs_dealloc);
2746                    self.push_str(&format!("if ({len}>0) _deallocate.push_back({base});\n"));
2747                }
2748
2749                uwriteln!(self.src, "for (unsigned i=0; i<{len}; ++i) {{");
2750                uwriteln!(
2751                    self.src,
2752                    "auto _base = {base} + i * {size};",
2753                    size = size.format(POINTER_SIZE_EXPRESSION)
2754                );
2755                uwrite!(self.src, "{}", body.0);
2756                uwriteln!(
2757                    self.src,
2758                    "auto _e{tmp} = {};",
2759                    move_if_necessary(&body.1[0])
2760                );
2761                if let Some(code) = self.leak_on_insertion.take() {
2762                    assert!(self.needs_dealloc);
2763                    uwriteln!(self.src, "{code}");
2764                }
2765                // inplace construct
2766                uwriteln!(self.src, "{result}.initialize(i, std::move(_e{tmp}));");
2767                uwriteln!(self.src, "}}");
2768
2769                if self.r#gen.r#gen.opts.api_style == APIStyle::Symmetric
2770                    && matches!(self.variant, AbiVariant::GuestExport)
2771                {
2772                    results.push(format!("{result}.get_const_view()"));
2773                    if self.r#gen.r#gen.opts.api_style == APIStyle::Symmetric
2774                        && matches!(self.variant, AbiVariant::GuestExport)
2775                    {
2776                        self.leak_on_insertion.replace(format!(
2777                            "if ({len}>0) _deallocate.push_back((void*){result}.leak());\n"
2778                        ));
2779                    }
2780                } else {
2781                    results.push(move_if_necessary(&result));
2782                }
2783            }
2784            abi::Instruction::FixedLengthListLift {
2785                element,
2786                size,
2787                id: _,
2788            } => {
2789                let tmp = self.tmp();
2790                let result = format!("_result{tmp}");
2791                let typename = self
2792                    .r#gen
2793                    .type_name(element, &self.namespace, Flavor::InStruct);
2794                self.push_str(&format!("std::array<{typename}, {size}> {result} = {{",));
2795                for a in operands.drain(0..(*size as usize)) {
2796                    self.push_str(&a);
2797                    self.push_str(", ");
2798                }
2799                self.push_str("};\n");
2800                results.push(result);
2801            }
2802            abi::Instruction::FixedLengthListLiftFromMemory {
2803                element,
2804                size: elemsize,
2805                id: _,
2806            } => {
2807                let body = self.blocks.pop().unwrap();
2808                let tmp = self.tmp();
2809                let vec = format!("_array{tmp}");
2810                let source = operands[0].clone();
2811                let size = self.r#gen.sizes.size(element);
2812                let size_str = size.format(POINTER_SIZE_EXPRESSION);
2813                let typename = self
2814                    .r#gen
2815                    .type_name(element, &self.namespace, Flavor::InStruct);
2816                let ptr_type = self.r#gen.r#gen.opts.ptr_type();
2817                self.push_str(&format!("std::array<{typename}, {elemsize}> {vec};\n"));
2818                self.push_str(&format!(
2819                    "{{
2820                    {ptr_type} _outer_base = {source};\n"
2821                ));
2822                let source: String = "_outer_base".into();
2823                // let vec: String = "outer_vec".into();
2824                self.push_str(&format!("for (unsigned i = 0; i<{elemsize}; ++i) {{\n",));
2825                self.push_str(&format!("{ptr_type} _base = {source} + i * {size_str};\n"));
2826                self.push_str(&body.0);
2827                self.push_str(&format!("{vec}[i] = {};", body.1[0]));
2828                self.push_str("\n}\n}\n");
2829                results.push(vec);
2830            }
2831            abi::Instruction::FixedLengthListLower {
2832                element: _,
2833                size,
2834                id: _,
2835            } => {
2836                for i in 0..(*size as usize) {
2837                    results.push(format!("{}[{i}]", operands[0]));
2838                }
2839            }
2840            abi::Instruction::FixedLengthListLowerToMemory {
2841                element,
2842                size: elemsize,
2843                id: _,
2844            } => {
2845                let body = self.blocks.pop().unwrap();
2846                let vec = operands[0].clone();
2847                let target = operands[1].clone();
2848                let size = self.r#gen.sizes.size(element);
2849                let size_str = size.format(POINTER_SIZE_EXPRESSION);
2850                let typename = self
2851                    .r#gen
2852                    .type_name(element, &self.namespace, Flavor::InStruct);
2853                let ptr_type = self.r#gen.r#gen.opts.ptr_type();
2854                self.push_str(&format!(
2855                    "{{
2856                    {ptr_type} _outer_base = {target};\n"
2857                ));
2858                let target: String = "_outer_base".into();
2859                self.push_str(&format!(
2860                    "std::array<{typename}, {elemsize}>& _outer_vec = {vec};\n"
2861                ));
2862                let vec: String = "_outer_vec".into();
2863                self.push_str(&format!("for (unsigned i = 0; i<{vec}.size(); ++i) {{\n",));
2864                self.push_str(&format!(
2865                    "{ptr_type} _base = {target} + i * {size_str};
2866                     {typename}& _iter_elem = {vec}[i];\n"
2867                ));
2868                self.push_str(&body.0);
2869                self.push_str("\n}\n}\n");
2870            }
2871            abi::Instruction::IterElem { .. } => results.push("_iter_elem".to_string()),
2872            abi::Instruction::IterBasePointer => results.push("_base".to_string()),
2873            abi::Instruction::RecordLower { record, .. } => {
2874                let op = &operands[0];
2875                for f in record.fields.iter() {
2876                    results.push(format!("({}).{}", op, to_c_ident(&f.name)));
2877                }
2878            }
2879            abi::Instruction::RecordLift { record, ty, .. } => {
2880                let mut result =
2881                    self.r#gen
2882                        .type_name(&Type::Id(*ty), &self.namespace, Flavor::InStruct);
2883                result.push('{');
2884                for (_field, val) in record.fields.iter().zip(operands) {
2885                    result.push_str(&(move_if_necessary(val) + ", "));
2886                }
2887                result.push('}');
2888                results.push(result);
2889            }
2890            abi::Instruction::HandleLower {
2891                handle: Handle::Own(ty),
2892                ..
2893            } => {
2894                let op = &operands[0];
2895
2896                // Check if this is an imported or exported resource
2897                let resource_ty = &self.r#gen.resolve.types[*ty];
2898                let resource_ty = match &resource_ty.kind {
2899                    TypeDefKind::Type(Type::Id(id)) => &self.r#gen.resolve.types[*id],
2900                    _ => resource_ty,
2901                };
2902                let is_exported = self.r#gen.is_exported_type(resource_ty);
2903
2904                if is_exported {
2905                    // Exported resources use .release()->handle
2906                    results.push(format!("{op}.release()->handle"));
2907                } else {
2908                    // Imported resources use .into_handle()
2909                    results.push(format!("{op}.into_handle()"));
2910                }
2911            }
2912            abi::Instruction::HandleLower {
2913                handle: Handle::Borrow(_),
2914                ..
2915            } => {
2916                let op = &operands[0];
2917                if op == "(*this)" {
2918                    // TODO is there a better way to decide?
2919                    results.push(format!("{op}.get_handle()"));
2920                } else {
2921                    results.push(format!("{op}.get().get_handle()"));
2922                }
2923            }
2924            abi::Instruction::HandleLift { handle, .. } => {
2925                let op = &operands[0];
2926                match (handle, false) {
2927                    (Handle::Own(ty), true) => match self.variant {
2928                        AbiVariant::GuestExport => {
2929                            results.push(format!("wit::{RESOURCE_EXPORT_BASE_CLASS_NAME}{{{op}}}"))
2930                        }
2931                        AbiVariant::GuestImport => {
2932                            let tmp = self.tmp();
2933                            let var = self.tempname("obj", tmp);
2934                            let tname = self.r#gen.type_name(
2935                                &Type::Id(*ty),
2936                                &self.namespace,
2937                                Flavor::Argument(self.variant),
2938                            );
2939                            uwriteln!(
2940                                self.src,
2941                                "auto {var} = {tname}::remove_resource({op});
2942                                assert({var}.has_value());"
2943                            );
2944                            results.push(format!("{tname}::Owned(*{var})"));
2945                        }
2946                        AbiVariant::GuestImportAsync => todo!(),
2947                        AbiVariant::GuestExportAsync => todo!(),
2948                        AbiVariant::GuestExportAsyncStackful => todo!(),
2949                    },
2950                    (Handle::Own(ty), false) => match self.variant {
2951                        AbiVariant::GuestImport => {
2952                            results.push(format!("wit::{RESOURCE_IMPORT_BASE_CLASS_NAME}{{{op}}}"))
2953                        }
2954                        AbiVariant::GuestExport => {
2955                            let tmp = self.tmp();
2956                            let var = self.tempname("obj", tmp);
2957                            let tname = self.r#gen.type_name(
2958                                &Type::Id(*ty),
2959                                &self.namespace,
2960                                Flavor::Argument(self.variant),
2961                            );
2962
2963                            // Check if this is an imported or exported resource
2964                            let resource_ty = &self.r#gen.resolve.types[*ty];
2965                            let resource_ty = match &resource_ty.kind {
2966                                TypeDefKind::Type(Type::Id(id)) => &self.r#gen.resolve.types[*id],
2967                                _ => resource_ty,
2968                            };
2969                            let is_exported = self.r#gen.is_exported_type(resource_ty);
2970
2971                            if is_exported {
2972                                // Exported resources use ::Owned typedef
2973                                uwriteln!(
2974                                    self.src,
2975                                    "auto {var} = {tname}::Owned({tname}::ResourceRep({op}));"
2976                                );
2977                            } else {
2978                                // Imported resources construct from ResourceImportBase
2979                                uwriteln!(
2980                                    self.src,
2981                                    "auto {var} = {tname}(wit::{RESOURCE_IMPORT_BASE_CLASS_NAME}{{{op}}});"
2982                                );
2983                            }
2984
2985                            results.push(format!("std::move({var})"))
2986                        }
2987                        AbiVariant::GuestImportAsync => todo!(),
2988                        AbiVariant::GuestExportAsync => todo!(),
2989                        AbiVariant::GuestExportAsyncStackful => todo!(),
2990                    },
2991                    (Handle::Borrow(ty), true) => {
2992                        let tname = self.r#gen.type_name(
2993                            &Type::Id(*ty),
2994                            &self.namespace,
2995                            Flavor::Argument(self.variant),
2996                        );
2997                        results.push(format!("**{tname}::lookup_resource({op})"));
2998                    }
2999                    (Handle::Borrow(ty), false) => match self.variant {
3000                        AbiVariant::GuestImport => results.push(op.clone()),
3001                        AbiVariant::GuestExport => {
3002                            let tname = self.r#gen.type_name(
3003                                &Type::Id(*ty),
3004                                &self.namespace,
3005                                Flavor::Argument(self.variant),
3006                            );
3007                            results.push(format!("std::ref(*({tname} *){op})"));
3008                        }
3009                        AbiVariant::GuestImportAsync => todo!(),
3010                        AbiVariant::GuestExportAsync => todo!(),
3011                        AbiVariant::GuestExportAsyncStackful => todo!(),
3012                    },
3013                }
3014            }
3015            abi::Instruction::TupleLower { tuple, .. } => {
3016                let op = &operands[0];
3017                for n in 0..tuple.types.len() {
3018                    results.push(format!("std::get<{n}>({op})"));
3019                }
3020            }
3021            abi::Instruction::TupleLift { tuple, .. } => {
3022                let name = format!("tuple{}", self.tmp());
3023                uwrite!(self.src, "auto {name} = std::tuple<");
3024                self.src.push_str(
3025                    &(tuple
3026                        .types
3027                        .iter()
3028                        .map(|t| self.r#gen.type_name(t, &self.namespace, Flavor::InStruct)))
3029                    .collect::<Vec<_>>()
3030                    .join(", "),
3031                );
3032                self.src.push_str(">(");
3033                self.src.push_str(
3034                    &operands
3035                        .iter()
3036                        .map(|op| move_if_necessary(op))
3037                        .collect::<Vec<_>>()
3038                        .join(", "),
3039                );
3040                self.src.push_str(");\n");
3041                results.push(format!("std::move({name})"));
3042            }
3043            abi::Instruction::FlagsLower { flags, ty, .. } => {
3044                match wit_bindgen_c::flags_repr(flags) {
3045                    Int::U8 | Int::U16 | Int::U32 => {
3046                        results.push(format!("((int32_t){})", operands.pop().unwrap()));
3047                    }
3048                    Int::U64 => {
3049                        let name =
3050                            self.r#gen
3051                                .type_name(&Type::Id(*ty), &self.namespace, Flavor::InStruct);
3052                        let tmp = self.tmp();
3053                        let tempname = self.tempname("flags", tmp);
3054                        uwriteln!(self.src, "{name} {tempname} = {};", operands[0]);
3055                        results.push(format!("(int32_t)(((uint64_t){tempname}) & 0xffffffff)"));
3056                        results.push(format!(
3057                            "(int32_t)((((uint64_t){tempname}) >> 32) & 0xffffffff)"
3058                        ));
3059                    }
3060                }
3061            }
3062            abi::Instruction::FlagsLift { flags, ty, .. } => {
3063                let typename =
3064                    self.r#gen
3065                        .type_name(&Type::Id(*ty), &self.namespace, Flavor::InStruct);
3066                match wit_bindgen_c::flags_repr(flags) {
3067                    Int::U8 | Int::U16 | Int::U32 => {
3068                        results.push(format!("(({typename}){})", operands.pop().unwrap()));
3069                    }
3070                    Int::U64 => {
3071                        let op0 = &operands[0];
3072                        let op1 = &operands[1];
3073                        results.push(format!(
3074                            "(({typename})(({op0}) | (((uint64_t)({op1})) << 32)))"
3075                        ));
3076                    }
3077                }
3078            }
3079            abi::Instruction::VariantPayloadName => {
3080                let name = format!("payload{}", self.tmp());
3081                results.push(name.clone());
3082                self.payloads.push(name);
3083            }
3084            abi::Instruction::VariantLower {
3085                variant,
3086                results: result_types,
3087                ty: var_ty,
3088                name: _var_name,
3089                ..
3090            } => {
3091                let blocks = self
3092                    .blocks
3093                    .drain(self.blocks.len() - variant.cases.len()..)
3094                    .collect::<Vec<_>>();
3095                let payloads = self
3096                    .payloads
3097                    .drain(self.payloads.len() - variant.cases.len()..)
3098                    .collect::<Vec<_>>();
3099
3100                let mut variant_results = Vec::with_capacity(result_types.len());
3101                for ty in result_types.iter() {
3102                    let name = format!("variant{}", self.tmp());
3103                    results.push(name.clone());
3104                    self.src.push_str(wit_bindgen_c::wasm_type(*ty));
3105                    self.src.push_str(" ");
3106                    self.src.push_str(&name);
3107                    self.src.push_str(";\n");
3108                    variant_results.push(name);
3109                }
3110
3111                let expr_to_match = format!("({}).variants.index()", operands[0]);
3112                let elem_ns =
3113                    self.r#gen
3114                        .type_name(&Type::Id(*var_ty), &self.namespace, Flavor::InStruct);
3115
3116                uwriteln!(self.src, "switch ((int32_t) {}) {{", expr_to_match);
3117                for (i, ((case, (block, block_results)), payload)) in
3118                    variant.cases.iter().zip(blocks).zip(payloads).enumerate()
3119                {
3120                    uwriteln!(self.src, "case {}: {{", i);
3121                    if case.ty.is_some() {
3122                        let case =
3123                            format!("{elem_ns}::{}", to_c_ident(&case.name).to_pascal_case());
3124                        uwriteln!(
3125                            self.src,
3126                            "auto& {} = std::get<{case}>({}.variants).value;",
3127                            payload,
3128                            operands[0],
3129                        );
3130                    }
3131
3132                    self.src.push_str(&block);
3133
3134                    for (name, result) in variant_results.iter().zip(&block_results) {
3135                        uwriteln!(self.src, "{} = {};", name, result);
3136                    }
3137                    self.src.push_str("break;\n}\n");
3138                }
3139                self.src.push_str("}\n");
3140            }
3141            abi::Instruction::VariantLift { variant, ty, .. } => {
3142                let blocks = self
3143                    .blocks
3144                    .drain(self.blocks.len() - variant.cases.len()..)
3145                    .collect::<Vec<_>>();
3146
3147                let ty = self
3148                    .r#gen
3149                    .type_name(&Type::Id(*ty), &self.namespace, Flavor::InStruct);
3150                let resultno = self.tmp();
3151                let result = format!("variant{resultno}");
3152
3153                let op0 = &operands[0];
3154
3155                // Use std::optional to avoid default constructor issues
3156                self.r#gen.r#gen.dependencies.needs_optional = true;
3157                uwriteln!(self.src, "std::optional<{ty}> {result}_opt;");
3158                uwriteln!(self.src, "switch ({op0}) {{");
3159                for (i, (case, (block, block_results))) in
3160                    variant.cases.iter().zip(blocks).enumerate()
3161                {
3162                    let tp = to_c_ident(&case.name).to_pascal_case();
3163                    uwriteln!(self.src, "case {i}: {{ {block}");
3164                    uwriteln!(
3165                        self.src,
3166                        "{result}_opt = {ty}{{{{{ty}::{tp}{{{}}}}}}};",
3167                        move_if_necessary(&block_results.first().cloned().unwrap_or_default())
3168                    );
3169                    uwriteln!(self.src, "}} break;");
3170                }
3171                uwriteln!(self.src, "}}");
3172                uwriteln!(self.src, "{ty} {result} = std::move(*{result}_opt);");
3173
3174                results.push(result);
3175            }
3176            abi::Instruction::EnumLower { .. } => results.push(format!("int32_t({})", operands[0])),
3177            abi::Instruction::EnumLift { ty, .. } => {
3178                let typename =
3179                    self.r#gen
3180                        .type_name(&Type::Id(*ty), &self.namespace, Flavor::InStruct);
3181                results.push(format!("({typename}){}", &operands[0]));
3182            }
3183            abi::Instruction::OptionLower {
3184                payload,
3185                results: result_types,
3186                ..
3187            } => {
3188                let (mut some, some_results) = self.blocks.pop().unwrap();
3189                let (mut none, none_results) = self.blocks.pop().unwrap();
3190                let some_payload = self.payloads.pop().unwrap();
3191                let _none_payload = self.payloads.pop().unwrap();
3192
3193                for (i, ty) in result_types.iter().enumerate() {
3194                    let tmp = self.tmp();
3195                    let name = self.tempname("option", tmp);
3196                    results.push(name.clone());
3197                    self.src.push_str(wit_bindgen_c::wasm_type(*ty));
3198                    self.src.push_str(" ");
3199                    self.src.push_str(&name);
3200                    self.src.push_str(";\n");
3201                    let some_result = &some_results[i];
3202                    uwriteln!(some, "{name} = {some_result};");
3203                    let none_result = &none_results[i];
3204                    uwriteln!(none, "{name} = {none_result};");
3205                }
3206
3207                let op0 = &operands[0];
3208                let is_function_param = self.params.iter().any(|p| p == op0);
3209                let (flavor, value_extract) = if matches!(payload, Type::String)
3210                    && matches!(self.variant, AbiVariant::GuestImport)
3211                    && !is_function_param
3212                {
3213                    // Import from struct/variant field: optional<wit::string> needs .get_view()
3214                    (
3215                        Flavor::BorrowedArgument,
3216                        format!("(std::move({op0})).value().get_view()"),
3217                    )
3218                } else {
3219                    // Direct parameter, export, or non-string: just .value()
3220                    (
3221                        if let (Type::String, AbiVariant::GuestImport) = (payload, self.variant) {
3222                            Flavor::BorrowedArgument
3223                        } else {
3224                            Flavor::InStruct
3225                        },
3226                        format!("(std::move({op0})).value()"),
3227                    )
3228                };
3229                let ty = self.r#gen.type_name(payload, &self.namespace, flavor);
3230                let bind_some = format!("{ty} {some_payload} = {value_extract};");
3231
3232                uwrite!(
3233                    self.src,
3234                    "\
3235                    if (({op0}).has_value()) {{
3236                        {bind_some}
3237                        {some}}} else {{
3238                        {none}}}
3239                    "
3240                );
3241            }
3242            abi::Instruction::OptionLift { payload, .. } => {
3243                let (some, some_results) = self.blocks.pop().unwrap();
3244                let (_none, none_results) = self.blocks.pop().unwrap();
3245                assert!(none_results.is_empty());
3246                assert!(some_results.len() == 1);
3247                let flavor = if self.r#gen.r#gen.opts.api_style == APIStyle::Symmetric
3248                    && matches!(self.variant, AbiVariant::GuestExport)
3249                {
3250                    Flavor::BorrowedArgument
3251                } else {
3252                    Flavor::InStruct
3253                };
3254                let type_name = self.r#gen.type_name(payload, &self.namespace, flavor);
3255                let full_type = format!("std::optional<{type_name}>");
3256                let op0 = &operands[0];
3257
3258                let tmp = self.tmp();
3259                let resultname = self.tempname("option", tmp);
3260                let some_value = move_if_necessary(&some_results[0]);
3261                uwriteln!(
3262                    self.src,
3263                    "{full_type} {resultname};
3264                    if ({op0}) {{
3265                        {some}
3266                        {resultname}.emplace({some_value});
3267                    }}"
3268                );
3269                results.push(format!("std::move({resultname})"));
3270            }
3271            abi::Instruction::ResultLower {
3272                results: result_types,
3273                result,
3274                ..
3275            } => {
3276                let (mut err, err_results) = self.blocks.pop().unwrap();
3277                let (mut ok, ok_results) = self.blocks.pop().unwrap();
3278                let err_payload = self.payloads.pop().unwrap();
3279                let ok_payload = self.payloads.pop().unwrap();
3280
3281                for (i, ty) in result_types.iter().enumerate() {
3282                    let tmp = self.tmp();
3283                    let name = self.tempname("result", tmp);
3284                    results.push(name.clone());
3285                    self.src.push_str(wit_bindgen_c::wasm_type(*ty));
3286                    self.src.push_str(" ");
3287                    self.src.push_str(&name);
3288                    self.src.push_str(";\n");
3289                    let ok_result = &ok_results[i];
3290                    uwriteln!(ok, "{name} = {ok_result};");
3291                    let err_result = &err_results[i];
3292                    uwriteln!(err, "{name} = {err_result};");
3293                }
3294
3295                let op0 = &operands[0];
3296                let ok_ty = self.r#gen.optional_type_name(
3297                    result.ok.as_ref(),
3298                    &self.namespace,
3299                    Flavor::InStruct,
3300                );
3301                let err_ty = self.r#gen.optional_type_name(
3302                    result.err.as_ref(),
3303                    &self.namespace,
3304                    Flavor::InStruct,
3305                );
3306                let bind_ok = if let Some(_ok) = result.ok.as_ref() {
3307                    format!("{ok_ty} {ok_payload} = std::move({op0}).value();")
3308                } else {
3309                    String::new()
3310                };
3311                let bind_err = if let Some(_err) = result.err.as_ref() {
3312                    format!("{err_ty} {err_payload} = std::move({op0}).error();")
3313                } else {
3314                    String::new()
3315                };
3316
3317                uwrite!(
3318                    self.src,
3319                    "\
3320                    if (({op0}).has_value()) {{
3321                        {bind_ok}
3322                        {ok}}} else {{
3323                        {bind_err}
3324                        {err}}}
3325                    "
3326                );
3327            }
3328            abi::Instruction::ResultLift { result, .. } => {
3329                let (mut err, err_results) = self.blocks.pop().unwrap();
3330                let (mut ok, ok_results) = self.blocks.pop().unwrap();
3331                let mut ok_result = String::new();
3332                let err_result;
3333                if result.ok.is_none() {
3334                    ok.clear();
3335                } else {
3336                    ok_result = move_if_necessary(&ok_results[0]);
3337                }
3338                if result.err.is_none() {
3339                    err.clear();
3340                    self.r#gen.r#gen.dependencies.needs_wit = true;
3341                    err_result = String::from("wit::Void{}");
3342                } else {
3343                    err_result = move_if_necessary(&err_results[0]);
3344                }
3345                let ok_type = self.r#gen.optional_type_name(
3346                    result.ok.as_ref(),
3347                    &self.namespace,
3348                    Flavor::InStruct,
3349                );
3350                let err_type = result.err.as_ref().map_or(String::from("wit::Void"), |ty| {
3351                    self.r#gen.type_name(ty, &self.namespace, Flavor::InStruct)
3352                });
3353                let full_type = format!("std::expected<{ok_type}, {err_type}>",);
3354                let err_type = "std::unexpected";
3355                let operand = &operands[0];
3356
3357                let tmp = self.tmp();
3358                let resultname = self.tempname("result", tmp);
3359                // Use std::optional to avoid default constructor issues with std::expected
3360                self.r#gen.r#gen.dependencies.needs_optional = true;
3361                let ok_assign = if result.ok.is_some() {
3362                    format!("{resultname}_opt.emplace({full_type}({ok_result}));")
3363                } else {
3364                    format!("{resultname}_opt.emplace({full_type}());")
3365                };
3366                uwriteln!(
3367                    self.src,
3368                    "std::optional<{full_type}> {resultname}_opt;
3369                    if ({operand}==0) {{
3370                        {ok}
3371                        {ok_assign}
3372                    }} else {{
3373                        {err}
3374                        {resultname}_opt.emplace({err_type}{{{err_result}}});
3375                    }}
3376                    {full_type} {resultname} = std::move(*{resultname}_opt);"
3377                );
3378                results.push(resultname);
3379            }
3380            abi::Instruction::CallWasm { name, sig } => {
3381                let module_name = self
3382                    .r#gen
3383                    .wasm_import_module
3384                    .as_ref()
3385                    .map(|e| {
3386                        self.r#gen
3387                            .r#gen
3388                            .import_prefix
3389                            .as_ref()
3390                            .cloned()
3391                            .unwrap_or_default()
3392                            + e
3393                    })
3394                    .unwrap();
3395
3396                let func = self
3397                    .r#gen
3398                    .declare_import(&module_name, name, &sig.params, &sig.results);
3399
3400                // ... then call the function with all our operands
3401                if !sig.results.is_empty() {
3402                    self.src.push_str("auto ret = ");
3403                    results.push("ret".to_string());
3404                }
3405                self.src.push_str(&func);
3406                self.src.push_str("(");
3407                self.src.push_str(
3408                    &operands
3409                        .iter()
3410                        .map(|op| move_if_necessary(op))
3411                        .collect::<Vec<_>>()
3412                        .join(", "),
3413                );
3414                self.src.push_str(");\n");
3415            }
3416            abi::Instruction::CallInterface { func, .. } => {
3417                // dbg!(func);
3418                self.let_results(if func.result.is_some() { 1 } else { 0 }, results);
3419                let (namespace, func_name_h) = self.r#gen.func_namespace_name(func, true, true);
3420                if matches!(func.kind, FunctionKind::Method(_)) {
3421                    let this = operands.remove(0);
3422                    uwrite!(self.src, "({this}).get().");
3423                } else {
3424                    let mut relative = SourceWithState::default();
3425                    relative.qualify(&namespace);
3426                    self.push_str(&relative.src);
3427                }
3428                self.src.push_str(&func_name_h);
3429                self.push_str("(");
3430                self.push_str(
3431                    &operands
3432                        .iter()
3433                        .map(|op| move_if_necessary(op))
3434                        .collect::<Vec<_>>()
3435                        .join(", "),
3436                );
3437                self.push_str(");\n");
3438                if self.needs_dealloc {
3439                    uwriteln!(
3440                        self.src,
3441                        "for (auto i: _deallocate) {{ free(i); }}\n
3442                        _deallocate.clear();"
3443                    );
3444                }
3445            }
3446            abi::Instruction::Return { amt, func } => {
3447                match amt {
3448                    0 => {}
3449                    _ => {
3450                        assert!(*amt == operands.len());
3451                        // Fallible constructors return expected, not void
3452                        let is_fallible_constructor = self
3453                            .r#gen
3454                            .r#gen
3455                            .is_fallible_constructor(self.r#gen.resolve, func);
3456
3457                        match &func.kind {
3458                            FunctionKind::Constructor(_)
3459                                if self.r#gen.r#gen.opts.is_only_handle(self.variant)
3460                                    && !is_fallible_constructor =>
3461                            {
3462                                // strange but works
3463                                if matches!(self.variant, AbiVariant::GuestExport) {
3464                                    self.src.push_str("this->index = ");
3465                                } else {
3466                                    self.src.push_str("this->handle = ");
3467                                }
3468                            }
3469                            _ => self.src.push_str("return "),
3470                        }
3471                        if let Some(CabiPostInformation {
3472                            module: _,
3473                            name: _cabi_post_name,
3474                            ret_type: cabi_post_type,
3475                        }) = self.cabi_post.as_ref()
3476                        {
3477                            self.src.push_str("wit::guest_owned<");
3478                            self.src.push_str(cabi_post_type);
3479                            self.src.push_str(">(");
3480                        }
3481                        if *amt == 1 {
3482                            if operands[0].starts_with("std::move(") && !operands[0].contains('.') {
3483                                // remove the std::move due to return value optimization (and complex rules about when std::move harms)
3484                                self.src.push_str(&operands[0][9..]);
3485                            } else {
3486                                self.src.push_str(&operands[0]);
3487                            }
3488                        } else {
3489                            todo!();
3490                        }
3491                        if let Some(CabiPostInformation {
3492                            module: func_module,
3493                            name: func_name,
3494                            ret_type: _cabi_post_type,
3495                        }) = self.cabi_post.as_ref()
3496                        {
3497                            let cabi_post_name = self.r#gen.declare_import(
3498                                &format!("cabi_post_{func_module}"),
3499                                func_name,
3500                                &[WasmType::Pointer],
3501                                &[],
3502                            );
3503                            self.src.push_str(&format!(", ret, {cabi_post_name})"));
3504                        }
3505                        if matches!(func.kind, FunctionKind::Constructor(_))
3506                            && self.r#gen.r#gen.opts.is_only_handle(self.variant)
3507                            && !is_fallible_constructor
3508                        {
3509                            // we wrapped the handle in an object, so unpack it
3510
3511                            self.src.push_str(".into_handle()");
3512                        }
3513                        self.src.push_str(";\n");
3514                    }
3515                }
3516            }
3517            abi::Instruction::Malloc { .. } => todo!(),
3518            abi::Instruction::GuestDeallocate { .. } => {
3519                uwriteln!(self.src, "free((void*) ({}));", operands[0]);
3520            }
3521            abi::Instruction::GuestDeallocateString => {
3522                uwriteln!(self.src, "if (({}) > 0) {{", operands[1]);
3523                uwriteln!(
3524                    self.src,
3525                    "wit::string::drop_raw((void*) ({}));",
3526                    operands[0]
3527                );
3528                uwriteln!(self.src, "}}");
3529            }
3530            abi::Instruction::GuestDeallocateList { element } => {
3531                let (body, results) = self.blocks.pop().unwrap();
3532                assert!(results.is_empty());
3533                let tmp = self.tmp();
3534                let ptr = self.tempname("_ptr", tmp);
3535                let len = self.tempname("_len", tmp);
3536                uwriteln!(self.src, "uint8_t* {ptr} = {};", operands[0]);
3537                uwriteln!(self.src, "size_t {len} = {};", operands[1]);
3538                if !body.trim().is_empty() {
3539                    let i = self.tempname("i", tmp);
3540                    uwriteln!(self.src, "for (size_t {i} = 0; {i} < {len}; {i}++) {{");
3541                    let size = self.r#gen.sizes.size(element);
3542                    uwriteln!(
3543                        self.src,
3544                        "uint8_t* _base = {ptr} + {i} * {size};",
3545                        size = size.format(POINTER_SIZE_EXPRESSION)
3546                    );
3547                    uwriteln!(self.src, "(void) _base;");
3548                    uwrite!(self.src, "{body}");
3549                    uwriteln!(self.src, "}}");
3550                }
3551                uwriteln!(self.src, "if ({len} > 0) {{");
3552                uwriteln!(self.src, "free((void*) ({ptr}));");
3553                uwriteln!(self.src, "}}");
3554            }
3555            abi::Instruction::GuestDeallocateVariant { blocks } => {
3556                let blocks = self
3557                    .blocks
3558                    .drain(self.blocks.len() - blocks..)
3559                    .collect::<Vec<_>>();
3560
3561                uwriteln!(self.src, "switch ((int32_t) {}) {{", operands[0]);
3562                for (i, (block, results)) in blocks.into_iter().enumerate() {
3563                    assert!(results.is_empty());
3564                    uwriteln!(self.src, "case {}: {{", i);
3565                    self.src.push_str(&block);
3566                    self.src.push_str("break;\n}\n");
3567                }
3568                self.src.push_str("}\n");
3569            }
3570            abi::Instruction::PointerLoad { offset } => {
3571                let ptr_type = self.r#gen.r#gen.opts.ptr_type();
3572                self.load(ptr_type, *offset, operands, results)
3573            }
3574            abi::Instruction::LengthLoad { offset } => {
3575                self.load("size_t", *offset, operands, results)
3576            }
3577            abi::Instruction::PointerStore { offset } => {
3578                let ptr_type = self.r#gen.r#gen.opts.ptr_type();
3579                self.store(ptr_type, *offset, operands)
3580            }
3581            abi::Instruction::LengthStore { offset } => self.store("size_t", *offset, operands),
3582            abi::Instruction::FutureLower { .. } => todo!(),
3583            abi::Instruction::FutureLift { .. } => todo!(),
3584            abi::Instruction::StreamLower { .. } => todo!(),
3585            abi::Instruction::StreamLift { .. } => todo!(),
3586            abi::Instruction::ErrorContextLower { .. } => todo!(),
3587            abi::Instruction::ErrorContextLift { .. } => todo!(),
3588            abi::Instruction::Flush { amt } => {
3589                for i in operands.iter().take(*amt) {
3590                    let tmp = self.tmp();
3591                    let result = format!("result{tmp}");
3592                    uwriteln!(self.src, "auto {result} = {};", move_if_necessary(i));
3593                    results.push(result);
3594                }
3595            }
3596            abi::Instruction::AsyncTaskReturn { .. } => todo!(),
3597            abi::Instruction::DropHandle { .. } => todo!(),
3598            abi::Instruction::MapLower {
3599                key,
3600                value,
3601                realloc,
3602            } => {
3603                let tmp = self.tmp();
3604                let body = self.blocks.pop().unwrap();
3605                let val = format!("map{tmp}");
3606                let ptr = format!("ptr{tmp}");
3607                let len = format!("len{tmp}");
3608                let entry = self.r#gen.sizes.record([*key, *value]);
3609                let size = entry.size.format(POINTER_SIZE_EXPRESSION);
3610                let align = entry.align.format(POINTER_SIZE_EXPRESSION);
3611                // The canonical ABI entry layout can differ from the C++ entry
3612                // layout (see wit-bindgen#1592), so always allocate a fresh ABI
3613                // buffer rather than reusing the source map's storage.
3614                self.push_str(&format!("auto&& {val} = {};\n", operands[0]));
3615                self.push_str(&format!("auto {len} = {val}.size();\n"));
3616                uwriteln!(
3617                    self.src,
3618                    "auto {ptr} = static_cast<{ptr_type}>({len} > 0 ? cabi_realloc(nullptr, 0, {align}, {len} * {size}) : nullptr);",
3619                    ptr_type = self.r#gen.r#gen.opts.ptr_type()
3620                );
3621                uwriteln!(self.src, "for (size_t i = 0; i < {len}; ++i) {{");
3622                uwriteln!(self.src, "auto _base = {ptr} + i * {size};");
3623                uwriteln!(self.src, "(void) _base;");
3624                uwriteln!(self.src, "auto&& iter_entry = {val}.data()[i];");
3625                uwriteln!(self.src, "auto&& iter_map_key = iter_entry.first;");
3626                uwriteln!(self.src, "auto&& iter_map_value = iter_entry.second;");
3627                uwrite!(self.src, "{}", body.0);
3628                uwriteln!(self.src, "}}");
3629                if realloc.is_some() {
3630                    uwriteln!(self.src, "{}.leak();", operands[0]);
3631                }
3632                results.push(ptr);
3633                results.push(len);
3634            }
3635            abi::Instruction::MapLift { key, value, .. } => {
3636                let body = self.blocks.pop().unwrap();
3637                let tmp = self.tmp();
3638                let entry = self.r#gen.sizes.record([*key, *value]);
3639                let size = entry.size.format(POINTER_SIZE_EXPRESSION);
3640                let flavor = if self.r#gen.r#gen.opts.api_style == APIStyle::Symmetric
3641                    && matches!(self.variant, AbiVariant::GuestExport)
3642                {
3643                    Flavor::BorrowedArgument
3644                } else {
3645                    Flavor::InStruct
3646                };
3647                let key_type = self.r#gen.type_name(key, &self.namespace, flavor);
3648                let value_type = self.r#gen.type_name(value, &self.namespace, flavor);
3649                let len = format!("len{tmp}");
3650                let base = format!("base{tmp}");
3651                let result = format!("result{tmp}");
3652                uwriteln!(self.src, "auto {base} = {};", operands[0]);
3653                uwriteln!(self.src, "auto {len} = {};", operands[1]);
3654                uwriteln!(
3655                    self.src,
3656                    "auto {result} = wit::unordered_map<{key_type}, {value_type}>::allocate({len});"
3657                );
3658                if self.r#gen.r#gen.opts.api_style == APIStyle::Symmetric
3659                    && matches!(self.variant, AbiVariant::GuestExport)
3660                {
3661                    assert!(self.needs_dealloc);
3662                    uwriteln!(self.src, "if ({len}>0) _deallocate.push_back({base});");
3663                }
3664                uwriteln!(self.src, "for (unsigned i=0; i<{len}; ++i) {{");
3665                uwriteln!(self.src, "auto _base = {base} + i * {size};");
3666                uwriteln!(self.src, "(void) _base;");
3667                uwrite!(self.src, "{}", body.0);
3668                let body_key = &body.1[0];
3669                let body_value = &body.1[1];
3670                uwriteln!(
3671                    self.src,
3672                    "{result}.initialize(i, std::make_pair({}, {}));",
3673                    move_if_necessary(body_key),
3674                    move_if_necessary(body_value)
3675                );
3676                uwriteln!(self.src, "}}");
3677
3678                if self.r#gen.r#gen.opts.api_style == APIStyle::Symmetric
3679                    && matches!(self.variant, AbiVariant::GuestExport)
3680                {
3681                    self.r#gen.r#gen.dependencies.needs_wit = true;
3682                    self.r#gen.r#gen.dependencies.needs_span = true;
3683                    results.push(format!(
3684                        "std::span<std::pair<{key_type}, {value_type}> const>({result}.data(), {result}.size())"
3685                    ));
3686                    self.leak_on_insertion.replace(format!(
3687                        "if ({len}>0) _deallocate.push_back((void*){result}.leak());\n"
3688                    ));
3689                } else {
3690                    results.push(move_if_necessary(&result));
3691                }
3692            }
3693            abi::Instruction::IterMapKey { .. } => {
3694                results.push("iter_map_key".to_string());
3695            }
3696            abi::Instruction::IterMapValue { .. } => {
3697                results.push("iter_map_value".to_string());
3698            }
3699            abi::Instruction::GuestDeallocateMap { key, value } => {
3700                let (body, results) = self.blocks.pop().unwrap();
3701                assert!(results.is_empty());
3702                let tmp = self.tmp();
3703                let ptr = self.tempname("_ptr", tmp);
3704                let len = self.tempname("_len", tmp);
3705                uwriteln!(self.src, "uint8_t* {ptr} = {};", operands[0]);
3706                uwriteln!(self.src, "size_t {len} = {};", operands[1]);
3707                if !body.trim().is_empty() {
3708                    let i = self.tempname("i", tmp);
3709                    uwriteln!(self.src, "for (size_t {i} = 0; {i} < {len}; {i}++) {{");
3710                    let entry = self.r#gen.sizes.record([*key, *value]);
3711                    let size = entry.size.format(POINTER_SIZE_EXPRESSION);
3712                    uwriteln!(self.src, "uint8_t* _base = {ptr} + {i} * {size};");
3713                    uwriteln!(self.src, "(void) _base;");
3714                    uwrite!(self.src, "{body}");
3715                    uwriteln!(self.src, "}}");
3716                }
3717                uwriteln!(self.src, "if ({len} > 0) {{");
3718                uwriteln!(self.src, "free((void*) ({ptr}));");
3719                uwriteln!(self.src, "}}");
3720            }
3721        }
3722    }
3723
3724    fn return_pointer(&mut self, size: ArchitectureSize, align: Alignment) -> Self::Operand {
3725        // Track maximum return area requirements
3726        self.return_pointer_area_size = self.return_pointer_area_size.max(size);
3727        self.return_pointer_area_align = self.return_pointer_area_align.max(align);
3728
3729        // Generate pointer to shared ret_area
3730        let tmp = self.tmp();
3731        uwriteln!(
3732            self.src,
3733            "{} ptr{tmp} = ({0})(&ret_area);",
3734            self.r#gen.r#gen.opts.ptr_type(),
3735        );
3736
3737        format!("ptr{tmp}")
3738    }
3739
3740    fn push_block(&mut self) {
3741        let prev = core::mem::take(&mut self.src);
3742        self.block_storage.push(prev);
3743    }
3744
3745    fn finish_block(&mut self, operands: &mut Vec<Self::Operand>) {
3746        let to_restore = self.block_storage.pop().unwrap();
3747        let src = core::mem::replace(&mut self.src, to_restore);
3748        self.blocks.push((src.into(), core::mem::take(operands)));
3749    }
3750
3751    fn sizes(&self) -> &wit_bindgen_core::wit_parser::SizeAlign {
3752        &self.r#gen.sizes
3753    }
3754
3755    fn is_list_canonical(
3756        &self,
3757        resolve: &Resolve,
3758        ty: &wit_bindgen_core::wit_parser::Type,
3759    ) -> bool {
3760        if !resolve.all_bits_valid(ty) {
3761            return false;
3762        }
3763        match ty {
3764            Type::Id(id) => !self.r#gen.r#gen.types.get(*id).has_resource,
3765            _ => true,
3766        }
3767    }
3768}
3769
3770/// This describes the common ABI function referenced or implemented, the C++ side might correspond to a different type
3771enum SpecialMethod {
3772    None,
3773    ResourceDrop, // ([export]) [resource-drop]
3774    ResourceNew,  // [export][resource-new]
3775    ResourceRep,  // [export][resource-rep]
3776    Dtor,         // [dtor] (guest export only)
3777    Allocate,     // internal: allocate new object (called from generated code)
3778}
3779
3780fn is_special_method(func: &Function) -> SpecialMethod {
3781    if matches!(func.kind, FunctionKind::Static(_)) {
3782        if func.name.starts_with("[resource-drop]") {
3783            SpecialMethod::ResourceDrop
3784        } else if func.name.starts_with("[resource-new]") {
3785            SpecialMethod::ResourceNew
3786        } else if func.name.starts_with("[resource-rep]") {
3787            SpecialMethod::ResourceRep
3788        } else if func.name.starts_with("[dtor]") {
3789            SpecialMethod::Dtor
3790        } else if func.name == "$alloc" {
3791            SpecialMethod::Allocate
3792        } else {
3793            SpecialMethod::None
3794        }
3795    } else {
3796        SpecialMethod::None
3797    }
3798}
3799
3800/// Sort the specified types topologically, taking the parameter and result
3801/// types of resource functions into consideration.
3802fn sort_types<'a>(
3803    resolve: &Resolve,
3804    types: &'a IndexMap<String, TypeId>,
3805) -> IndexMap<&'a str, TypeId> {
3806    struct Visitor<'a> {
3807        resolve: &'a Resolve,
3808        sorted: IndexSet<TypeId>,
3809        visited: HashSet<TypeId>,
3810    }
3811
3812    impl TypeIdVisitor for Visitor<'_> {
3813        fn before_visit_type_id(&mut self, id: TypeId) -> bool {
3814            let ty = &self.resolve.types[id];
3815            if let TypeDefKind::Resource = &ty.kind {
3816                // Here we avoid infinite recursion by remembering if we've seen
3817                // this type already.
3818                if self.visited.contains(&id) {
3819                    false
3820                } else {
3821                    self.visited.insert(id);
3822
3823                    // TypeIdVisitor does not consider the parameter and return
3824                    // types of resource associated functions to be transitive
3825                    // types, so we need to handle that ourselves here.
3826                    if let TypeOwner::Interface(interface) = ty.owner {
3827                        for function in self.resolve.interfaces[interface].functions.values() {
3828                            if let Some(resource) = function.kind.resource()
3829                                && resource == id
3830                            {
3831                                for parameter in &function.params {
3832                                    self.visit_type(self.resolve, &parameter.ty);
3833                                }
3834
3835                                if let Some(ty) = function.result {
3836                                    self.visit_type(self.resolve, &ty);
3837                                }
3838                            }
3839                        }
3840                    }
3841
3842                    true
3843                }
3844            } else {
3845                true
3846            }
3847        }
3848
3849        fn after_visit_type_id(&mut self, id: TypeId) {
3850            self.sorted.insert(id);
3851        }
3852    }
3853
3854    let mut visitor = Visitor {
3855        resolve,
3856        sorted: Default::default(),
3857        visited: Default::default(),
3858    };
3859
3860    for &id in types.values() {
3861        visitor.visit_type_id(resolve, id);
3862    }
3863
3864    let names = types
3865        .iter()
3866        .map(|(k, v)| (*v, k.as_str()))
3867        .collect::<HashMap<_, _>>();
3868
3869    visitor
3870        .sorted
3871        .into_iter()
3872        .filter_map(|v| names.get(&v).map(|k| (*k, v)))
3873        .collect()
3874}