wit_bindgen_cpp/
lib.rs

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