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