wit_bindgen_cpp/
lib.rs

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