Skip to main content

wit_bindgen_cpp/
lib.rs

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