Skip to main content

wit_bindgen_cpp/
lib.rs

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