wit_bindgen_cpp/
lib.rs

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