Skip to main content

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