wasmer_wit_bindgen_gen_rust_wasm/
lib.rs

1use heck::*;
2use std::collections::BTreeMap;
3use std::io::{Read, Write};
4use std::mem;
5use std::process::{Command, Stdio};
6use wasmer_wit_bindgen_gen_core::wit_parser::abi::{
7    AbiVariant, Bindgen, Instruction, LiftLower, WasmType,
8};
9use wasmer_wit_bindgen_gen_core::{wit_parser::*, Direction, Files, Generator, Source, TypeInfo, Types};
10use wasmer_wit_bindgen_gen_rust::{
11    int_repr, wasm_type, FnSig, RustFlagsRepr, RustFunctionGenerator, RustGenerator, TypeMode,
12};
13
14#[derive(Default)]
15pub struct RustWasm {
16    src: Source,
17    opts: Opts,
18    types: Types,
19    in_import: bool,
20    traits: BTreeMap<String, Trait>,
21    in_trait: bool,
22    trait_name: String,
23    return_pointer_area_size: usize,
24    return_pointer_area_align: usize,
25    sizes: SizeAlign,
26}
27
28#[derive(Default, Debug, Clone)]
29#[cfg_attr(feature = "structopt", derive(structopt::StructOpt))]
30pub struct Opts {
31    /// Whether or not `rustfmt` is executed to format generated code.
32    #[cfg_attr(feature = "structopt", structopt(long))]
33    pub rustfmt: bool,
34
35    /// Adds the wit module name into import binding names when enabled.
36    #[cfg_attr(feature = "structopt", structopt(long))]
37    pub multi_module: bool,
38
39    /// Whether or not the bindings assume interface values are always
40    /// well-formed or whether checks are performed.
41    #[cfg_attr(feature = "structopt", structopt(long))]
42    pub unchecked: bool,
43
44    /// A prefix to prepend to all exported symbols. Note that this is only
45    /// intended for testing because it breaks the general form of the ABI.
46    #[cfg_attr(feature = "structopt", structopt(skip))]
47    pub symbol_namespace: String,
48
49    /// If true, the code generation is intended for standalone crates.
50    ///
51    /// Standalone mode generates bindings without a wrapping module.
52    ///
53    /// For exported interfaces, an `export!` macro is also generated
54    /// that can be used to export an implementation from a different
55    /// crate.
56    #[cfg_attr(feature = "structopt", structopt(skip))]
57    pub standalone: bool,
58}
59
60#[derive(Default)]
61struct Trait {
62    methods: Vec<String>,
63    resource_methods: BTreeMap<ResourceId, Vec<String>>,
64}
65
66impl Opts {
67    pub fn build(self) -> RustWasm {
68        let mut r = RustWasm::new();
69        r.opts = self;
70        r
71    }
72}
73
74impl RustWasm {
75    pub fn new() -> RustWasm {
76        RustWasm::default()
77    }
78
79    fn abi_variant(dir: Direction) -> AbiVariant {
80        // This generator uses the obvious direction to ABI variant mapping.
81        match dir {
82            Direction::Export => AbiVariant::GuestExport,
83            Direction::Import => AbiVariant::GuestImport,
84        }
85    }
86
87    fn ret_area_name(iface: &Interface) -> String {
88        format!("{}_RET_AREA", iface.name.to_shouty_snake_case())
89    }
90}
91
92impl RustGenerator for RustWasm {
93    fn default_param_mode(&self) -> TypeMode {
94        if self.in_import {
95            // We default to borrowing as much as possible to maximize the ability
96            // for host to take views into our memory without forcing wasm modules
97            // to allocate anything.
98            TypeMode::AllBorrowed("'a")
99        } else {
100            // In exports everythig is always owned, slices and handles and all.
101            // Nothing is borrowed.
102            TypeMode::Owned
103        }
104    }
105
106    fn handle_projection(&self) -> Option<(&'static str, String)> {
107        None
108    }
109
110    fn handle_in_super(&self) -> bool {
111        !self.in_import
112    }
113
114    fn handle_wrapper(&self) -> Option<&'static str> {
115        if self.in_import {
116            None
117        } else {
118            Some("wit_bindgen_rust::Handle")
119        }
120    }
121
122    fn push_str(&mut self, s: &str) {
123        self.src.push_str(s);
124    }
125
126    fn info(&self, ty: TypeId) -> TypeInfo {
127        self.types.get(ty)
128    }
129
130    fn types_mut(&mut self) -> &mut Types {
131        &mut self.types
132    }
133
134    fn print_borrowed_slice(
135        &mut self,
136        iface: &Interface,
137        mutbl: bool,
138        ty: &Type,
139        lifetime: &'static str,
140    ) {
141        self.print_rust_slice(iface, mutbl, ty, lifetime);
142    }
143
144    fn print_borrowed_str(&mut self, lifetime: &'static str) {
145        self.push_str("&");
146        if lifetime != "'_" {
147            self.push_str(lifetime);
148            self.push_str(" ");
149        }
150        self.push_str(" str");
151    }
152}
153
154impl Generator for RustWasm {
155    fn preprocess_one(&mut self, iface: &Interface, dir: Direction) {
156        let variant = Self::abi_variant(dir);
157        self.in_import = variant == AbiVariant::GuestImport;
158        self.types.analyze(iface);
159        self.trait_name = iface.name.to_camel_case();
160
161        if !self.opts.standalone {
162            self.src.push_str(&format!(
163                "#[allow(clippy::all)]\nmod {} {{\n",
164                iface.name.to_snake_case(),
165            ));
166        }
167
168        self.sizes.fill(iface);
169    }
170
171    fn type_record(
172        &mut self,
173        iface: &Interface,
174        id: TypeId,
175        _name: &str,
176        record: &Record,
177        docs: &Docs,
178        generate_structs: bool,
179    ) {
180        self.print_typedef_record(iface, id, record, docs, generate_structs);
181    }
182
183    fn type_tuple(
184        &mut self,
185        iface: &Interface,
186        id: TypeId,
187        _name: &str,
188        tuple: &Tuple,
189        docs: &Docs,
190        generate_structs: bool,
191    ) {
192        self.print_typedef_tuple(iface, id, tuple, docs, generate_structs);
193    }
194
195    fn type_flags(
196        &mut self,
197        _iface: &Interface,
198        _id: TypeId,
199        name: &str,
200        flags: &Flags,
201        docs: &Docs,
202        generate_structs: bool,
203    ) {
204        self.src
205            .push_str("wit_bindgen_rust::bitflags::bitflags! {\n");
206        self.rustdoc(docs);
207        let repr = RustFlagsRepr::new(flags);
208        self.src
209            .push_str(&format!("pub struct {}: {repr} {{\n", name.to_camel_case(),));
210        for (i, flag) in flags.flags.iter().enumerate() {
211            self.rustdoc(&flag.docs);
212            self.src.push_str(&format!(
213                "const {} = 1 << {};\n",
214                flag.name.to_shouty_snake_case(),
215                i,
216            ));
217        }
218        self.src.push_str("}\n");
219        self.src.push_str("}\n");
220
221        // Add a `from_bits_preserve` method.
222        self.src
223            .push_str(&format!("impl {} {{\n", name.to_camel_case()));
224        self.src.push_str(&format!(
225            "    /// Convert from a raw integer, preserving any unknown bits. See\n"
226        ));
227        self.src.push_str(&format!(
228            "    /// <https://github.com/bitflags/bitflags/issues/263#issuecomment-957088321>\n"
229        ));
230        self.src.push_str(&format!(
231            "    pub fn from_bits_preserve(bits: {repr}) -> Self {{\n",
232        ));
233        self.src.push_str(&format!("        Self {{ bits }}\n"));
234        self.src.push_str(&format!("    }}\n"));
235        self.src.push_str(&format!("}}\n"));
236    }
237
238    fn type_variant(
239        &mut self,
240        iface: &Interface,
241        id: TypeId,
242        _name: &str,
243        variant: &Variant,
244        docs: &Docs,
245        generate_structs: bool,
246    ) {
247        self.print_typedef_variant(iface, id, variant, docs, generate_structs);
248    }
249
250    fn type_union(
251        &mut self,
252        iface: &Interface,
253        id: TypeId,
254        _name: &str,
255        union: &Union,
256        docs: &Docs,
257        generate_structs: bool,
258    ) {
259        self.print_typedef_union(iface, id, union, docs, generate_structs);
260    }
261
262    fn type_option(
263        &mut self,
264        iface: &Interface,
265        id: TypeId,
266        _name: &str,
267        payload: &Type,
268        docs: &Docs,
269        generate_structs: bool,
270    ) {
271        self.print_typedef_option(iface, id, payload, docs, generate_structs);
272    }
273
274    fn type_expected(
275        &mut self,
276        iface: &Interface,
277        id: TypeId,
278        _name: &str,
279        expected: &Expected,
280        docs: &Docs,
281        generate_structs: bool,
282    ) {
283        self.print_typedef_expected(iface, id, expected, docs, generate_structs);
284    }
285
286    fn type_enum(
287        &mut self,
288        _iface: &Interface,
289        id: TypeId,
290        name: &str,
291        enum_: &Enum,
292        docs: &Docs,
293        generate_structs: bool,
294    ) {
295        self.print_typedef_enum(id, name, enum_, docs, generate_structs);
296    }
297
298    fn type_resource(&mut self, iface: &Interface, ty: ResourceId) {
299        // For exported handles we synthesize some trait implementations
300        // automatically for runtime-required traits.
301        if !self.in_import {
302            let panic = "
303                #[cfg(not(target_arch = \"wasm32\"))]
304                {
305                    panic!(\"handles can only be used on wasm32\");
306                }
307                #[cfg(target_arch = \"wasm32\")]
308            ";
309            self.src.push_str(&format!(
310                "
311                    unsafe impl wit_bindgen_rust::HandleType for super::{ty} {{
312                        #[inline]
313                        fn clone(_val: i32) -> i32 {{
314                            {panic_not_wasm}
315                            {{
316                                #[link(wasm_import_module = \"canonical_abi\")]
317                                extern \"C\" {{
318                                    #[link_name = \"resource_clone_{name}\"]
319                                    fn clone(val: i32) -> i32;
320                                }}
321                                unsafe {{ clone(_val) }}
322                            }}
323                        }}
324
325                        #[inline]
326                        fn drop(_val: i32) {{
327                            {panic_not_wasm}
328                            {{
329                                #[link(wasm_import_module = \"canonical_abi\")]
330                                extern \"C\" {{
331                                    #[link_name = \"resource_drop_{name}\"]
332                                    fn drop(val: i32);
333                                }}
334                                unsafe {{ drop(_val) }}
335                            }}
336                        }}
337                    }}
338
339                    unsafe impl wit_bindgen_rust::LocalHandle for super::{ty} {{
340                        #[inline]
341                        fn new(_val: i32) -> i32 {{
342                            {panic_not_wasm}
343                            {{
344                                #[link(wasm_import_module = \"canonical_abi\")]
345                                extern \"C\" {{
346                                    #[link_name = \"resource_new_{name}\"]
347                                    fn new(val: i32) -> i32;
348                                }}
349                                unsafe {{ new(_val) }}
350                            }}
351                        }}
352
353                        #[inline]
354                        fn get(_val: i32) -> i32 {{
355                            {panic_not_wasm}
356                            {{
357                                #[link(wasm_import_module = \"canonical_abi\")]
358                                extern \"C\" {{
359                                    #[link_name = \"resource_get_{name}\"]
360                                    fn get(val: i32) -> i32;
361                                }}
362                                unsafe {{ get(_val) }}
363                            }}
364                        }}
365                    }}
366
367                    const _: () = {{
368                        #[export_name = \"{ns}canonical_abi_drop_{name}\"]
369                        extern \"C\" fn drop(ty: Box<super::{ty}>) {{
370                            <super::{iface} as {iface}>::drop_{name_snake}(*ty)
371                        }}
372                    }};
373                ",
374                ty = iface.resources[ty].name.to_camel_case(),
375                name = iface.resources[ty].name,
376                name_snake = iface.resources[ty].name.to_snake_case(),
377                iface = iface.name.to_camel_case(),
378                ns = self.opts.symbol_namespace,
379                panic_not_wasm = panic,
380            ));
381            let trait_ = self
382                .traits
383                .entry(iface.name.to_camel_case())
384                .or_insert(Trait::default());
385            trait_.methods.push(format!(
386                "
387                    /// An optional callback invoked when a handle is finalized
388                    /// and destroyed.
389                    fn drop_{}(val: super::{}) {{
390                        drop(val);
391                    }}
392                ",
393                iface.resources[ty].name.to_snake_case(),
394                iface.resources[ty].name.to_camel_case(),
395            ));
396            return;
397        }
398
399        let resource = &iface.resources[ty];
400        let name = &resource.name;
401
402        self.rustdoc(&resource.docs);
403        self.src.push_str("#[derive(Debug)]\n");
404        self.src.push_str("#[repr(transparent)]\n");
405        self.src
406            .push_str(&format!("pub struct {}(i32);\n", name.to_camel_case()));
407        self.src.push_str("impl ");
408        self.src.push_str(&name.to_camel_case());
409        self.src.push_str(
410            " {
411                pub unsafe fn from_raw(raw: i32) -> Self {
412                    Self(raw)
413                }
414
415                pub fn into_raw(self) -> i32 {
416                    let ret = self.0;
417                    core::mem::forget(self);
418                    return ret;
419                }
420
421                pub fn as_raw(&self) -> i32 {
422                    self.0
423                }
424            }\n",
425        );
426
427        self.src.push_str("impl Drop for ");
428        self.src.push_str(&name.to_camel_case());
429        self.src.push_str(&format!(
430            "{{
431                fn drop(&mut self) {{
432                    #[link(wasm_import_module = \"canonical_abi\")]
433                    extern \"C\" {{
434                        #[link_name = \"resource_drop_{}\"]
435                        fn close(fd: i32);
436                    }}
437                    unsafe {{
438                        close(self.0);
439                    }}
440                }}
441            }}\n",
442            name,
443        ));
444
445        self.src.push_str("impl Clone for ");
446        self.src.push_str(&name.to_camel_case());
447        self.src.push_str(&format!(
448            "{{
449                fn clone(&self) -> Self {{
450                    #[link(wasm_import_module = \"canonical_abi\")]
451                    extern \"C\" {{
452                        #[link_name = \"resource_clone_{}\"]
453                        fn clone(val: i32) -> i32;
454                    }}
455                    unsafe {{
456                        Self(clone(self.0))
457                    }}
458                }}
459            }}\n",
460            name,
461        ));
462    }
463
464    fn type_alias(
465        &mut self,
466        iface: &Interface,
467        id: TypeId,
468        _name: &str,
469        ty: &Type,
470        docs: &Docs,
471        generate_structs: bool,
472    ) {
473        self.print_typedef_alias(iface, id, ty, docs, generate_structs);
474    }
475
476    fn type_list(
477        &mut self,
478        iface: &Interface,
479        id: TypeId,
480        _name: &str,
481        ty: &Type,
482        docs: &Docs,
483        generate_structs: bool,
484    ) {
485        self.print_type_list(iface, id, ty, docs, generate_structs);
486    }
487
488    fn type_builtin(
489        &mut self,
490        iface: &Interface,
491        _id: TypeId,
492        name: &str,
493        ty: &Type,
494        docs: &Docs,
495        generate_structs: bool,
496    ) {
497        self.rustdoc(docs);
498        self.src
499            .push_str(&format!("pub type {}", name.to_camel_case()));
500        self.src.push_str(" = ");
501        self.print_ty(iface, ty, TypeMode::Owned);
502        self.src.push_str(";\n");
503    }
504
505    fn preprocess_functions(&mut self, _iface: &Interface, dir: Direction) {
506        if self.opts.standalone && dir == Direction::Export {
507            self.src.push_str(
508                "/// Declares the export of the interface for the given type.\n\
509                 #[macro_export]\n\
510                 macro_rules! export(($t:ident) => {\n",
511            );
512        }
513    }
514
515    fn import(&mut self, iface: &Interface, func: &Function, generate_structs: bool) {
516        let mut sig = FnSig::default();
517        let param_mode = TypeMode::AllBorrowed("'_");
518        sig.async_ = func.is_async;
519        match &func.kind {
520            FunctionKind::Freestanding => {}
521            FunctionKind::Static { resource, .. } | FunctionKind::Method { resource, .. } => {
522                sig.use_item_name = true;
523                self.src.push_str(&format!(
524                    "impl {} {{\n",
525                    iface.resources[*resource].name.to_camel_case()
526                ));
527            }
528        }
529        if let FunctionKind::Method { .. } = func.kind {
530            sig.self_arg = Some("&self".to_string());
531            sig.self_is_first_param = true;
532        }
533        let params = self.print_signature(iface, func, param_mode, &sig);
534        self.src.push_str("{\n");
535        self.src.push_str("unsafe {\n");
536
537        let mut f = FunctionBindgen::new(self, params);
538        iface.call(
539            AbiVariant::GuestImport,
540            LiftLower::LowerArgsLiftResults,
541            func,
542            &mut f,
543        );
544        let FunctionBindgen {
545            needs_cleanup_list,
546            src,
547            ..
548        } = f;
549
550        if needs_cleanup_list {
551            self.src.push_str("let mut cleanup_list = Vec::new();\n");
552        }
553        self.src.push_str(&String::from(src));
554
555        self.src.push_str("}\n");
556        self.src.push_str("}\n");
557
558        match &func.kind {
559            FunctionKind::Freestanding => {}
560            FunctionKind::Static { .. } | FunctionKind::Method { .. } => {
561                self.src.push_str("}\n");
562            }
563        }
564    }
565
566    fn export(&mut self, iface: &Interface, func: &Function, generate_structs: bool) {
567        let iface_name = iface.name.to_snake_case();
568
569        self.src.push_str("#[export_name = \"");
570        match &iface.module {
571            Some(module) => {
572                self.src.push_str(module);
573                self.src.push_str("#");
574                self.src.push_str(&func.name);
575            }
576            None => {
577                self.src.push_str(&self.opts.symbol_namespace);
578                self.src.push_str(&func.name);
579            }
580        }
581        self.src.push_str("\"]\n");
582        self.src.push_str("unsafe extern \"C\" fn __wit_bindgen_");
583        self.src.push_str(&iface_name);
584        self.src.push_str("_");
585        self.src.push_str(&func.name.to_snake_case());
586        self.src.push_str("(");
587        let sig = iface.wasm_signature(AbiVariant::GuestExport, func);
588        let mut params = Vec::new();
589        for (i, param) in sig.params.iter().enumerate() {
590            let name = format!("arg{}", i);
591            self.src.push_str(&name);
592            self.src.push_str(": ");
593            self.wasm_type(*param);
594            self.src.push_str(", ");
595            params.push(name);
596        }
597        self.src.push_str(")");
598
599        match sig.results.len() {
600            0 => {}
601            1 => {
602                self.src.push_str(" -> ");
603                self.wasm_type(sig.results[0]);
604            }
605            _ => unimplemented!(),
606        }
607
608        self.push_str("{\n");
609
610        if self.opts.standalone {
611            // Force the macro code to reference wit_bindgen_rust for standalone crates.
612            // Also ensure any referenced types are also used from the external crate.
613            self.src
614                .push_str("#[allow(unused_imports)]\nuse wasmer_wit_bindgen_rust;\nuse ");
615            self.src.push_str(&iface_name);
616            self.src.push_str("::*;\n");
617        }
618
619        if func.is_async {
620            self.src.push_str("let future = async move {\n");
621        }
622
623        let mut f = FunctionBindgen::new(self, params);
624        iface.call(
625            AbiVariant::GuestExport,
626            LiftLower::LiftArgsLowerResults,
627            func,
628            &mut f,
629        );
630        let FunctionBindgen {
631            needs_cleanup_list,
632            src,
633            ..
634        } = f;
635        assert!(!needs_cleanup_list);
636        self.src.push_str(&String::from(src));
637        if func.is_async {
638            self.src.push_str("};\n");
639            self.src
640                .push_str("wit_bindgen_rust::rt::execute(Box::pin(future));\n");
641        }
642        self.src.push_str("}\n");
643
644        let prev = mem::take(&mut self.src);
645        self.in_trait = true;
646        let mut sig = FnSig::default();
647        sig.private = true;
648        sig.async_ = func.is_async;
649        match &func.kind {
650            FunctionKind::Freestanding => {}
651            FunctionKind::Static { .. } => sig.use_item_name = true,
652            FunctionKind::Method { .. } => {
653                sig.use_item_name = true;
654                sig.self_is_first_param = true;
655                sig.self_arg = Some("&self".to_string());
656            }
657        }
658        self.print_signature(iface, func, TypeMode::Owned, &sig);
659        self.src.push_str(";");
660        self.in_trait = false;
661        let trait_ = self
662            .traits
663            .entry(iface.name.to_camel_case())
664            .or_insert(Trait::default());
665        let dst = match &func.kind {
666            FunctionKind::Freestanding => &mut trait_.methods,
667            FunctionKind::Static { resource, .. } | FunctionKind::Method { resource, .. } => trait_
668                .resource_methods
669                .entry(*resource)
670                .or_insert(Vec::new()),
671        };
672        dst.push(mem::replace(&mut self.src, prev).into());
673    }
674
675    fn finish_functions(&mut self, iface: &Interface, dir: Direction) {
676        if self.return_pointer_area_align > 0 {
677            self.src.push_str(&format!(
678                "
679                    #[repr(align({align}))]
680                    struct RetArea([u8; {size}]);
681                    static mut {name}: RetArea = RetArea([0; {size}]);
682                ",
683                name = Self::ret_area_name(iface),
684                align = self.return_pointer_area_align,
685                size = self.return_pointer_area_size,
686            ));
687        }
688
689        // For standalone generation, close the export! macro
690        if self.opts.standalone && dir == Direction::Export {
691            self.src.push_str("});\n");
692        }
693    }
694
695    fn finish_one(&mut self, iface: &Interface, files: &mut Files) {
696        let mut src = mem::take(&mut self.src);
697
698        let any_async = iface.functions.iter().any(|f| f.is_async);
699        for (name, trait_) in self.traits.iter() {
700            if any_async {
701                src.push_str("#[wit_bindgen_rust::async_trait(?Send)]\n");
702            }
703            src.push_str("pub trait ");
704            src.push_str(&name);
705            src.push_str(" {\n");
706            for f in trait_.methods.iter() {
707                src.push_str(&f);
708                src.push_str("\n");
709            }
710            src.push_str("}\n");
711
712            for (id, methods) in trait_.resource_methods.iter() {
713                if any_async {
714                    src.push_str("#[wit_bindgen_rust::async_trait(?Send)]\n");
715                }
716                src.push_str(&format!(
717                    "pub trait {} {{\n",
718                    iface.resources[*id].name.to_camel_case()
719                ));
720                for f in methods {
721                    src.push_str(&f);
722                    src.push_str("\n");
723                }
724                src.push_str("}\n");
725            }
726        }
727
728        // Close the opening `mod`.
729        if !self.opts.standalone {
730            src.push_str("}\n");
731        }
732
733        if self.opts.rustfmt {
734            let mut child = Command::new("rustfmt")
735                .stdin(Stdio::piped())
736                .stdout(Stdio::piped())
737                .spawn()
738                .expect("failed to spawn `rustfmt`");
739            child
740                .stdin
741                .take()
742                .unwrap()
743                .write_all(src.as_bytes())
744                .unwrap();
745            src.as_mut_string().truncate(0);
746            child
747                .stdout
748                .take()
749                .unwrap()
750                .read_to_string(src.as_mut_string())
751                .unwrap();
752            let status = child.wait().unwrap();
753            assert!(status.success());
754        }
755
756        files.push("bindings.rs", src.as_bytes());
757    }
758}
759
760struct FunctionBindgen<'a> {
761    gen: &'a mut RustWasm,
762    params: Vec<String>,
763    src: Source,
764    blocks: Vec<String>,
765    block_storage: Vec<(Source, Vec<(String, String)>)>,
766    tmp: usize,
767    needs_cleanup_list: bool,
768    cleanup: Vec<(String, String)>,
769}
770
771impl FunctionBindgen<'_> {
772    fn new(gen: &mut RustWasm, params: Vec<String>) -> FunctionBindgen<'_> {
773        FunctionBindgen {
774            gen,
775            params,
776            src: Default::default(),
777            blocks: Vec::new(),
778            block_storage: Vec::new(),
779            tmp: 0,
780            needs_cleanup_list: false,
781            cleanup: Vec::new(),
782        }
783    }
784
785    fn emit_cleanup(&mut self) {
786        for (ptr, layout) in mem::take(&mut self.cleanup) {
787            self.push_str(&format!("std::alloc::dealloc({}, {});\n", ptr, layout));
788        }
789        if self.needs_cleanup_list {
790            self.push_str(
791                "for (ptr, layout) in cleanup_list {
792                    std::alloc::dealloc(ptr, layout);
793                }\n",
794            );
795        }
796    }
797
798    fn declare_import(
799        &mut self,
800        iface: &Interface,
801        name: &str,
802        params: &[WasmType],
803        results: &[WasmType],
804    ) -> String {
805        let module = iface.module.as_deref().unwrap_or(&iface.name);
806
807        // Define the actual function we're calling inline
808        self.push_str("#[link(wasm_import_module = \"");
809        self.push_str(module);
810        self.push_str("\")]\n");
811        self.push_str("extern \"C\" {\n");
812        self.push_str("#[cfg_attr(target_arch = \"wasm32\", link_name = \"");
813        self.push_str(name);
814        self.push_str("\")]\n");
815        self.push_str("#[cfg_attr(not(target_arch = \"wasm32\"), link_name = \"");
816        self.push_str(module);
817        self.push_str("_");
818        self.push_str(name);
819        self.push_str("\")]\n");
820        self.push_str("fn wit_import(");
821        for param in params.iter() {
822            self.push_str("_: ");
823            self.push_str(wasm_type(*param));
824            self.push_str(", ");
825        }
826        self.push_str(")");
827        assert!(results.len() < 2);
828        for result in results.iter() {
829            self.push_str(" -> ");
830            self.push_str(wasm_type(*result));
831        }
832        self.push_str(";\n}\n");
833        "wit_import".to_string()
834    }
835}
836
837impl RustFunctionGenerator for FunctionBindgen<'_> {
838    fn push_str(&mut self, s: &str) {
839        self.src.push_str(s);
840    }
841
842    fn tmp(&mut self) -> usize {
843        let ret = self.tmp;
844        self.tmp += 1;
845        ret
846    }
847
848    fn rust_gen(&self) -> &dyn RustGenerator {
849        self.gen
850    }
851
852    fn lift_lower(&self) -> LiftLower {
853        if self.gen.in_import {
854            LiftLower::LowerArgsLiftResults
855        } else {
856            LiftLower::LiftArgsLowerResults
857        }
858    }
859}
860
861impl Bindgen for FunctionBindgen<'_> {
862    type Operand = String;
863
864    fn push_block(&mut self) {
865        let prev_src = mem::take(&mut self.src);
866        let prev_cleanup = mem::take(&mut self.cleanup);
867        self.block_storage.push((prev_src, prev_cleanup));
868    }
869
870    fn finish_block(&mut self, operands: &mut Vec<String>) {
871        if self.cleanup.len() > 0 {
872            self.needs_cleanup_list = true;
873            self.push_str("cleanup_list.extend_from_slice(&[");
874            for (ptr, layout) in mem::take(&mut self.cleanup) {
875                self.push_str("(");
876                self.push_str(&ptr);
877                self.push_str(", ");
878                self.push_str(&layout);
879                self.push_str("),");
880            }
881            self.push_str("]);\n");
882        }
883        let (prev_src, prev_cleanup) = self.block_storage.pop().unwrap();
884        let src = mem::replace(&mut self.src, prev_src);
885        self.cleanup = prev_cleanup;
886        let expr = match operands.len() {
887            0 => "()".to_string(),
888            1 => operands[0].clone(),
889            _ => format!("({})", operands.join(", ")),
890        };
891        if src.is_empty() {
892            self.blocks.push(expr);
893        } else if operands.is_empty() {
894            self.blocks.push(format!("{{\n{}\n}}", &src[..]));
895        } else {
896            self.blocks.push(format!("{{\n{}\n{}\n}}", &src[..], expr));
897        }
898    }
899
900    fn return_pointer(&mut self, iface: &Interface, size: usize, align: usize) -> String {
901        self.gen.return_pointer_area_size = self.gen.return_pointer_area_size.max(size);
902        self.gen.return_pointer_area_align = self.gen.return_pointer_area_align.max(align);
903        let tmp = self.tmp();
904
905        self.push_str(&format!(
906            "let ptr{} = {}.0.as_mut_ptr() as i32;\n",
907            tmp,
908            RustWasm::ret_area_name(iface),
909        ));
910        format!("ptr{}", tmp)
911    }
912
913    fn sizes(&self) -> &SizeAlign {
914        &self.gen.sizes
915    }
916
917    fn is_list_canonical(&self, iface: &Interface, ty: &Type) -> bool {
918        iface.all_bits_valid(ty)
919    }
920
921    fn emit(
922        &mut self,
923        iface: &Interface,
924        inst: &Instruction<'_>,
925        operands: &mut Vec<String>,
926        results: &mut Vec<String>,
927    ) {
928        let unchecked = self.gen.opts.unchecked;
929        let mut top_as = |cvt: &str| {
930            let mut s = operands.pop().unwrap();
931            s.push_str(" as ");
932            s.push_str(cvt);
933            results.push(s);
934        };
935
936        match inst {
937            Instruction::GetArg { nth } => results.push(self.params[*nth].clone()),
938            Instruction::I32Const { val } => results.push(format!("{}i32", val)),
939            Instruction::ConstZero { tys } => {
940                for ty in tys.iter() {
941                    match ty {
942                        WasmType::I32 => results.push("0i32".to_string()),
943                        WasmType::I64 => results.push("0i64".to_string()),
944                        WasmType::F32 => results.push("0.0f32".to_string()),
945                        WasmType::F64 => results.push("0.0f64".to_string()),
946                    }
947                }
948            }
949
950            Instruction::I64FromU64 | Instruction::I64FromS64 => {
951                let s = operands.pop().unwrap();
952                results.push(format!("wit_bindgen_rust::rt::as_i64({})", s));
953            }
954            Instruction::I32FromChar
955            | Instruction::I32FromU8
956            | Instruction::I32FromS8
957            | Instruction::I32FromU16
958            | Instruction::I32FromS16
959            | Instruction::I32FromU32
960            | Instruction::I32FromS32 => {
961                let s = operands.pop().unwrap();
962                results.push(format!("wit_bindgen_rust::rt::as_i32({})", s));
963            }
964
965            Instruction::F32FromFloat32 => {
966                let s = operands.pop().unwrap();
967                results.push(format!("wit_bindgen_rust::rt::as_f32({})", s));
968            }
969            Instruction::F64FromFloat64 => {
970                let s = operands.pop().unwrap();
971                results.push(format!("wit_bindgen_rust::rt::as_f64({})", s));
972            }
973            Instruction::Float32FromF32
974            | Instruction::Float64FromF64
975            | Instruction::S32FromI32
976            | Instruction::S64FromI64 => {
977                results.push(operands.pop().unwrap());
978            }
979            Instruction::S8FromI32 => top_as("i8"),
980            Instruction::U8FromI32 => top_as("u8"),
981            Instruction::S16FromI32 => top_as("i16"),
982            Instruction::U16FromI32 => top_as("u16"),
983            Instruction::U32FromI32 => top_as("u32"),
984            Instruction::U64FromI64 => top_as("u64"),
985            Instruction::CharFromI32 => {
986                if unchecked {
987                    results.push(format!(
988                        "core::char::from_u32_unchecked({} as u32)",
989                        operands[0]
990                    ));
991                } else {
992                    results.push(format!(
993                        "core::char::from_u32({} as u32).unwrap()",
994                        operands[0]
995                    ));
996                }
997            }
998
999            Instruction::Bitcasts { casts } => {
1000                wasmer_wit_bindgen_gen_rust::bitcast(casts, operands, results)
1001            }
1002
1003            Instruction::UnitLower => {
1004                self.push_str(&format!("let () = {};\n", operands[0]));
1005            }
1006            Instruction::UnitLift => {
1007                results.push("()".to_string());
1008            }
1009
1010            Instruction::I32FromBool => {
1011                results.push(format!("match {} {{ true => 1, false => 0 }}", operands[0]));
1012            }
1013            Instruction::BoolFromI32 => {
1014                if unchecked {
1015                    results.push(format!(
1016                        "core::mem::transmute::<u8, bool>({} as u8)",
1017                        operands[0],
1018                    ));
1019                } else {
1020                    results.push(format!(
1021                        "match {} {{
1022                            0 => false,
1023                            1 => true,
1024                            _ => panic!(\"invalid bool discriminant\"),
1025                        }}",
1026                        operands[0],
1027                    ));
1028                }
1029            }
1030
1031            // handles in exports
1032            Instruction::I32FromOwnedHandle { .. } => {
1033                results.push(format!(
1034                    "wit_bindgen_rust::Handle::into_raw({})",
1035                    operands[0]
1036                ));
1037            }
1038            Instruction::HandleBorrowedFromI32 { .. } => {
1039                results.push(format!(
1040                    "wit_bindgen_rust::Handle::from_raw({})",
1041                    operands[0],
1042                ));
1043            }
1044
1045            // handles in imports
1046            Instruction::I32FromBorrowedHandle { .. } => {
1047                results.push(format!("{}.0", operands[0]));
1048            }
1049            Instruction::HandleOwnedFromI32 { ty } => {
1050                results.push(format!(
1051                    "{}({})",
1052                    iface.resources[*ty].name.to_camel_case(),
1053                    operands[0]
1054                ));
1055            }
1056
1057            Instruction::FlagsLower { flags, .. } => {
1058                let tmp = self.tmp();
1059                self.push_str(&format!("let flags{} = {};\n", tmp, operands[0]));
1060                for i in 0..flags.repr().count() {
1061                    results.push(format!("(flags{}.bits() >> {}) as i32", tmp, i * 32));
1062                }
1063            }
1064            Instruction::FlagsLift { name, flags, .. } => {
1065                let repr = RustFlagsRepr::new(flags);
1066                let name = name.to_camel_case();
1067                let mut result = format!("{}::empty()", name);
1068                for (i, op) in operands.iter().enumerate() {
1069                    result.push_str(&format!(
1070                        " | {}::from_bits_preserve((({} as {repr}) << {}) as _)",
1071                        name,
1072                        op,
1073                        i * 32
1074                    ));
1075                }
1076                results.push(result);
1077            }
1078
1079            Instruction::RecordLower { ty, record, .. } => {
1080                self.record_lower(iface, *ty, record, &operands[0], results);
1081            }
1082            Instruction::RecordLift { ty, record, .. } => {
1083                self.record_lift(iface, *ty, record, operands, results);
1084            }
1085
1086            Instruction::TupleLower { tuple, .. } => {
1087                self.tuple_lower(tuple, &operands[0], results);
1088            }
1089            Instruction::TupleLift { .. } => {
1090                self.tuple_lift(operands, results);
1091            }
1092
1093            Instruction::VariantPayloadName => results.push("e".to_string()),
1094
1095            Instruction::VariantLower {
1096                variant,
1097                results: result_types,
1098                ty,
1099                ..
1100            } => {
1101                let blocks = self
1102                    .blocks
1103                    .drain(self.blocks.len() - variant.cases.len()..)
1104                    .collect::<Vec<_>>();
1105                self.let_results(result_types.len(), results);
1106                let op0 = &operands[0];
1107                self.push_str(&format!("match {op0} {{\n"));
1108                let name = self.typename_lower(iface, *ty);
1109                for (case, block) in variant.cases.iter().zip(blocks) {
1110                    let case_name = case.name.to_camel_case();
1111                    self.push_str(&format!("{name}::{case_name}"));
1112                    if case.ty == Type::Unit {
1113                        self.push_str(&format!(" => {{\nlet e = ();\n{block}\n}}\n"));
1114                    } else {
1115                        self.push_str(&format!("(e) => {block},\n"));
1116                    }
1117                }
1118                self.push_str("};\n");
1119            }
1120
1121            // In unchecked mode when this type is a named enum then we know we
1122            // defined the type so we can transmute directly into it.
1123            Instruction::VariantLift { name, variant, .. }
1124                if variant.cases.iter().all(|c| c.ty == Type::Unit) && unchecked =>
1125            {
1126                self.blocks.drain(self.blocks.len() - variant.cases.len()..);
1127                let mut result = format!("core::mem::transmute::<_, ");
1128                result.push_str(&name.to_camel_case());
1129                result.push_str(">(");
1130                result.push_str(&operands[0]);
1131                result.push_str(" as ");
1132                result.push_str(int_repr(variant.tag()));
1133                result.push_str(")");
1134                results.push(result);
1135            }
1136
1137            Instruction::VariantLift { variant, ty, .. } => {
1138                let blocks = self
1139                    .blocks
1140                    .drain(self.blocks.len() - variant.cases.len()..)
1141                    .collect::<Vec<_>>();
1142                let op0 = &operands[0];
1143                let mut result = format!("match {op0} {{\n");
1144                let name = self.typename_lift(iface, *ty);
1145                for (i, (case, block)) in variant.cases.iter().zip(blocks).enumerate() {
1146                    let pat = if i == variant.cases.len() - 1 && unchecked {
1147                        String::from("_")
1148                    } else {
1149                        i.to_string()
1150                    };
1151                    let block = if case.ty != Type::Unit {
1152                        format!("({block})")
1153                    } else {
1154                        String::new()
1155                    };
1156                    let case = case.name.to_camel_case();
1157                    result.push_str(&format!("{pat} => {name}::{case}{block},\n"));
1158                }
1159                if !unchecked {
1160                    result.push_str("_ => panic!(\"invalid enum discriminant\"),\n");
1161                }
1162                result.push_str("}");
1163                results.push(result);
1164            }
1165
1166            Instruction::UnionLower {
1167                union,
1168                results: result_types,
1169                ty,
1170                ..
1171            } => {
1172                let blocks = self
1173                    .blocks
1174                    .drain(self.blocks.len() - union.cases.len()..)
1175                    .collect::<Vec<_>>();
1176                self.let_results(result_types.len(), results);
1177                let op0 = &operands[0];
1178                self.push_str(&format!("match {op0} {{\n"));
1179                let name = self.typename_lower(iface, *ty);
1180                for (case_name, block) in self
1181                    .gen
1182                    .union_case_names(iface, union)
1183                    .into_iter()
1184                    .zip(blocks)
1185                {
1186                    self.push_str(&format!("{name}::{case_name}(e) => {block},\n"));
1187                }
1188                self.push_str("};\n");
1189            }
1190
1191            Instruction::UnionLift { union, ty, .. } => {
1192                let blocks = self
1193                    .blocks
1194                    .drain(self.blocks.len() - union.cases.len()..)
1195                    .collect::<Vec<_>>();
1196                let op0 = &operands[0];
1197                let mut result = format!("match {op0} {{\n");
1198                for (i, (case_name, block)) in self
1199                    .gen
1200                    .union_case_names(iface, union)
1201                    .into_iter()
1202                    .zip(blocks)
1203                    .enumerate()
1204                {
1205                    let pat = if i == union.cases.len() - 1 && unchecked {
1206                        String::from("_")
1207                    } else {
1208                        i.to_string()
1209                    };
1210                    let name = self.typename_lift(iface, *ty);
1211                    result.push_str(&format!("{pat} => {name}::{case_name}({block}),\n"));
1212                }
1213                if !unchecked {
1214                    result.push_str("_ => panic!(\"invalid union discriminant\"),\n");
1215                }
1216                result.push_str("}");
1217                results.push(result);
1218            }
1219
1220            Instruction::OptionLower {
1221                results: result_types,
1222                ..
1223            } => {
1224                let some = self.blocks.pop().unwrap();
1225                let none = self.blocks.pop().unwrap();
1226                self.let_results(result_types.len(), results);
1227                let operand = &operands[0];
1228                self.push_str(&format!(
1229                    "match {operand} {{
1230                        Some(e) => {some},
1231                        None => {{\nlet e = ();\n{none}\n}},
1232                    }};"
1233                ));
1234            }
1235
1236            Instruction::OptionLift { .. } => {
1237                let some = self.blocks.pop().unwrap();
1238                let none = self.blocks.pop().unwrap();
1239                assert_eq!(none, "()");
1240                let operand = &operands[0];
1241                let invalid = if unchecked {
1242                    "std::hint::unreachable_unchecked()"
1243                } else {
1244                    "panic!(\"invalid enum discriminant\")"
1245                };
1246                results.push(format!(
1247                    "match {operand} {{
1248                        0 => None,
1249                        1 => Some({some}),
1250                        _ => {invalid},
1251                    }}"
1252                ));
1253            }
1254
1255            Instruction::ExpectedLower {
1256                results: result_types,
1257                ..
1258            } => {
1259                let err = self.blocks.pop().unwrap();
1260                let ok = self.blocks.pop().unwrap();
1261                self.let_results(result_types.len(), results);
1262                let operand = &operands[0];
1263                self.push_str(&format!(
1264                    "match {operand} {{
1265                        Ok(e) => {{ {ok} }},
1266                        Err(e) => {{ {err} }},
1267                    }};"
1268                ));
1269            }
1270
1271            Instruction::ExpectedLift { .. } => {
1272                let err = self.blocks.pop().unwrap();
1273                let ok = self.blocks.pop().unwrap();
1274                let operand = &operands[0];
1275                let invalid = if unchecked {
1276                    "std::hint::unreachable_unchecked()"
1277                } else {
1278                    "panic!(\"invalid enum discriminant\")"
1279                };
1280                results.push(format!(
1281                    "match {operand} {{
1282                        0 => Ok({ok}),
1283                        1 => Err({err}),
1284                        _ => {invalid},
1285                    }}"
1286                ));
1287            }
1288
1289            Instruction::EnumLower { enum_, name, .. } => {
1290                let mut result = format!("match {} {{\n", operands[0]);
1291                let name = name.to_camel_case();
1292                for (i, case) in enum_.cases.iter().enumerate() {
1293                    let case = case.name.to_camel_case();
1294                    result.push_str(&format!("{name}::{case} => {i},\n"));
1295                }
1296                result.push_str("}");
1297                results.push(result);
1298            }
1299
1300            // In unchecked mode when this type is a named enum then we know we
1301            // defined the type so we can transmute directly into it.
1302            Instruction::EnumLift { enum_, name, .. } if unchecked => {
1303                let mut result = format!("core::mem::transmute::<_, ");
1304                result.push_str(&name.to_camel_case());
1305                result.push_str(">(");
1306                result.push_str(&operands[0]);
1307                result.push_str(" as ");
1308                result.push_str(int_repr(enum_.tag()));
1309                result.push_str(")");
1310                results.push(result);
1311            }
1312
1313            Instruction::EnumLift { enum_, name, .. } => {
1314                let mut result = format!("match ");
1315                result.push_str(&operands[0]);
1316                result.push_str(" {\n");
1317                let name = name.to_camel_case();
1318                for (i, case) in enum_.cases.iter().enumerate() {
1319                    let case = case.name.to_camel_case();
1320                    result.push_str(&format!("{i} => {name}::{case},\n"));
1321                }
1322                result.push_str("_ => panic!(\"invalid enum discriminant\"),\n");
1323                result.push_str("}");
1324                results.push(result);
1325            }
1326
1327            Instruction::ListCanonLower { realloc, .. } => {
1328                let tmp = self.tmp();
1329                let val = format!("vec{}", tmp);
1330                let ptr = format!("ptr{}", tmp);
1331                let len = format!("len{}", tmp);
1332                if realloc.is_none() {
1333                    self.push_str(&format!("let {} = {};\n", val, operands[0]));
1334                } else {
1335                    let op0 = operands.pop().unwrap();
1336                    self.push_str(&format!("let {} = ({}).into_boxed_slice();\n", val, op0));
1337                }
1338                self.push_str(&format!("let {} = {}.as_ptr() as i32;\n", ptr, val));
1339                self.push_str(&format!("let {} = {}.len() as i32;\n", len, val));
1340                if realloc.is_some() {
1341                    self.push_str(&format!("core::mem::forget({});\n", val));
1342                }
1343                results.push(ptr);
1344                results.push(len);
1345            }
1346
1347            Instruction::ListCanonLift { free, .. } => {
1348                // This only happens when we're receiving a list from the
1349                // outside world, so `free` should always be `Some`.
1350                assert!(free.is_some());
1351                let tmp = self.tmp();
1352                let len = format!("len{}", tmp);
1353                self.push_str(&format!("let {} = {} as usize;\n", len, operands[1]));
1354                let result = format!(
1355                    "Vec::from_raw_parts({} as *mut _, {1}, {1})",
1356                    operands[0], len
1357                );
1358                results.push(result);
1359            }
1360
1361            Instruction::StringLower { realloc } => {
1362                let tmp = self.tmp();
1363                let val = format!("vec{}", tmp);
1364                let ptr = format!("ptr{}", tmp);
1365                let len = format!("len{}", tmp);
1366                if realloc.is_none() {
1367                    self.push_str(&format!("let {} = {};\n", val, operands[0]));
1368                } else {
1369                    let op0 = format!("{}.into_bytes()", operands[0]);
1370                    self.push_str(&format!("let {} = ({}).into_boxed_slice();\n", val, op0));
1371                }
1372                self.push_str(&format!("let {} = {}.as_ptr() as i32;\n", ptr, val));
1373                self.push_str(&format!("let {} = {}.len() as i32;\n", len, val));
1374                if realloc.is_some() {
1375                    self.push_str(&format!("core::mem::forget({});\n", val));
1376                }
1377                results.push(ptr);
1378                results.push(len);
1379            }
1380
1381            Instruction::StringLift { free, .. } => {
1382                // This only happens when we're receiving a string from the
1383                // outside world, so `free` should always be `Some`.
1384                assert!(free.is_some());
1385                let tmp = self.tmp();
1386                let len = format!("len{}", tmp);
1387                self.push_str(&format!("let {} = {} as usize;\n", len, operands[1]));
1388                let result = format!(
1389                    "Vec::from_raw_parts({} as *mut _, {1}, {1})",
1390                    operands[0], len
1391                );
1392                if unchecked {
1393                    results.push(format!("String::from_utf8_unchecked({})", result));
1394                } else {
1395                    results.push(format!("String::from_utf8({}).unwrap()", result));
1396                }
1397            }
1398
1399            Instruction::ListLower { element, realloc } => {
1400                let body = self.blocks.pop().unwrap();
1401                let tmp = self.tmp();
1402                let vec = format!("vec{}", tmp);
1403                let result = format!("result{}", tmp);
1404                let layout = format!("layout{}", tmp);
1405                let len = format!("len{}", tmp);
1406                self.push_str(&format!("let {} = {};\n", vec, operands[0]));
1407                self.push_str(&format!("let {} = {}.len() as i32;\n", len, vec));
1408                let size = self.gen.sizes.size(element);
1409                let align = self.gen.sizes.align(element);
1410                self.push_str(&format!(
1411                    "let {} = core::alloc::Layout::from_size_align_unchecked({}.len() * {}, {});\n",
1412                    layout, vec, size, align,
1413                ));
1414                self.push_str(&format!(
1415                    "let {} = std::alloc::alloc({});\n",
1416                    result, layout,
1417                ));
1418                self.push_str(&format!(
1419                    "if {}.is_null() {{ std::alloc::handle_alloc_error({}); }}\n",
1420                    result, layout,
1421                ));
1422                self.push_str(&format!(
1423                    "for (i, e) in {}.into_iter().enumerate() {{\n",
1424                    vec
1425                ));
1426                self.push_str(&format!(
1427                    "let base = {} as i32 + (i as i32) * {};\n",
1428                    result, size,
1429                ));
1430                self.push_str(&body);
1431                self.push_str("}\n");
1432                results.push(format!("{} as i32", result));
1433                results.push(len);
1434
1435                if realloc.is_none() {
1436                    // If an allocator isn't requested then we must clean up the
1437                    // allocation ourselves since our callee isn't taking
1438                    // ownership.
1439                    self.cleanup.push((result, layout));
1440                }
1441            }
1442
1443            Instruction::ListLift { element, free, .. } => {
1444                // This only happens when we're receiving a list from the
1445                // outside world, so `free` should always be `Some`.
1446                assert!(free.is_some());
1447                let body = self.blocks.pop().unwrap();
1448                let tmp = self.tmp();
1449                let size = self.gen.sizes.size(element);
1450                let align = self.gen.sizes.align(element);
1451                let len = format!("len{}", tmp);
1452                let base = format!("base{}", tmp);
1453                let result = format!("result{}", tmp);
1454                self.push_str(&format!("let {} = {};\n", base, operands[0]));
1455                self.push_str(&format!("let {} = {};\n", len, operands[1],));
1456                self.push_str(&format!(
1457                    "let mut {} = Vec::with_capacity({} as usize);\n",
1458                    result, len,
1459                ));
1460
1461                self.push_str("for i in 0..");
1462                self.push_str(&len);
1463                self.push_str(" {\n");
1464                self.push_str("let base = ");
1465                self.push_str(&base);
1466                self.push_str(" + i *");
1467                self.push_str(&size.to_string());
1468                self.push_str(";\n");
1469                self.push_str(&result);
1470                self.push_str(".push(");
1471                self.push_str(&body);
1472                self.push_str(");\n");
1473                self.push_str("}\n");
1474                results.push(result);
1475                self.push_str(&format!(
1476                    "std::alloc::dealloc(
1477                        {} as *mut _,
1478                        std::alloc::Layout::from_size_align_unchecked(
1479                            ({} as usize) * {},
1480                            {},
1481                        ),
1482                    );\n",
1483                    base, len, size, align
1484                ));
1485            }
1486
1487            Instruction::IterElem { .. } => results.push("e".to_string()),
1488
1489            Instruction::IterBasePointer => results.push("base".to_string()),
1490
1491            Instruction::CallWasm { iface, name, sig } => {
1492                let func = self.declare_import(iface, name, &sig.params, &sig.results);
1493
1494                // ... then call the function with all our operands
1495                if sig.results.len() > 0 {
1496                    self.push_str("let ret = ");
1497                    results.push("ret".to_string());
1498                }
1499                self.push_str(&func);
1500                self.push_str("(");
1501                self.push_str(&operands.join(", "));
1502                self.push_str(");\n");
1503            }
1504
1505            Instruction::CallWasmAsyncImport {
1506                iface,
1507                name,
1508                params: wasm_params,
1509                results: wasm_results,
1510            } => {
1511                // The first thing we do here is define the completion callback
1512                // which the host will invoke when the asynchronous call
1513                // actually finishes. This receives our own custom state
1514                // parameter as the first parameter which is the `Sender`
1515                // converted to a `usize`. Afterwards it receives all the
1516                // results which we'll transfer ove the `sender`, the canonical
1517                // ABI of the results.
1518                self.push_str("unsafe extern \"C\" fn completion_callback(sender: usize");
1519                for (i, result) in wasm_results.iter().enumerate() {
1520                    self.push_str(", ");
1521                    self.push_str(&format!("ret{}: ", i));
1522                    self.push_str(wasm_type(*result));
1523                }
1524                self.push_str(") {\n");
1525                self.push_str("wit_bindgen_rust::rt::Sender::from_usize(sender).send((");
1526                for i in 0..wasm_results.len() {
1527                    self.push_str(&format!("ret{},", i));
1528                }
1529                self.push_str("));\n");
1530                self.push_str("}\n");
1531
1532                // Next we create the future channel which will be used to track
1533                // the state of this import. The "oneshot" here means that the
1534                // sender (`tx`) will send something once over `rx`. The type of
1535                // the `Oneshot` is the type of the `wasm_results` which is the
1536                // canonical ABI of the results that this function produces.
1537                self.push_str("let (rx, tx) = wit_bindgen_rust::rt::Oneshot::<(");
1538                for ty in *wasm_results {
1539                    self.push_str(wasm_type(*ty));
1540                    self.push_str(", ");
1541                }
1542                self.push_str(")>::new();\n");
1543
1544                // Then we can actually call the function now that we have
1545                // all the parameters. The first parameters to the import are
1546                // the canonical ABI `operands` we were provided, and the last
1547                // two arguments are our completion callback and the context for
1548                // the callback, our `tx` sender.
1549                let func = self.declare_import(iface, name, wasm_params, &[]);
1550                self.push_str(&func);
1551                self.push_str("(");
1552                for op in operands {
1553                    self.push_str(op);
1554                    self.push_str(", ");
1555                }
1556                self.push_str("completion_callback as i32, ");
1557                self.push_str("tx.into_usize() as i32");
1558                self.push_str(");\n");
1559
1560                // And finally we want to "appear synchronous" with an async
1561                // function, so we immediately `.await` the results of the
1562                // oneshot. This binds all the canonical ABI results to then get
1563                // translated in further instructions to the result of this
1564                // function call.
1565                let tmp = self.tmp();
1566                self.push_str("let (");
1567                for i in 0..wasm_results.len() {
1568                    let name = format!("ret{}_{}", tmp, i);
1569                    self.push_str(&name);
1570                    self.push_str(",");
1571                    results.push(name);
1572                }
1573                self.push_str(") = rx.await;\n");
1574            }
1575
1576            Instruction::CallWasmAsyncExport { .. } => unreachable!(),
1577
1578            Instruction::CallInterface { module, func } => {
1579                self.push_str("let result = ");
1580                results.push("result".to_string());
1581                match &func.kind {
1582                    FunctionKind::Freestanding => {
1583                        if self.gen.opts.standalone {
1584                            // For standalone mode, use the macro identifier
1585                            self.push_str(&format!(
1586                                "<$t as {t}>::{}",
1587                                func.name.to_snake_case(),
1588                                t = module.to_camel_case(),
1589                            ));
1590                        } else {
1591                            self.push_str(&format!(
1592                                "<super::{m} as {m}>::{}",
1593                                func.name.to_snake_case(),
1594                                m = module.to_camel_case()
1595                            ));
1596                        }
1597                    }
1598                    FunctionKind::Static { resource, name }
1599                    | FunctionKind::Method { resource, name } => {
1600                        self.push_str(&format!(
1601                            "<super::{r} as {r}>::{}",
1602                            name.to_snake_case(),
1603                            r = iface.resources[*resource].name.to_camel_case(),
1604                        ));
1605                    }
1606                }
1607                self.push_str("(");
1608                if let FunctionKind::Method { .. } = func.kind {
1609                    self.push_str("&");
1610                }
1611                self.push_str(&operands.join(", "));
1612                self.push_str(")");
1613                if func.is_async {
1614                    self.push_str(".await");
1615                }
1616                self.push_str(";\n");
1617            }
1618
1619            Instruction::Return { amt, .. } => {
1620                self.emit_cleanup();
1621                match amt {
1622                    0 => {}
1623                    1 => {
1624                        self.push_str(&operands[0]);
1625                        self.push_str("\n");
1626                    }
1627                    _ => {
1628                        self.push_str("(");
1629                        self.push_str(&operands.join(", "));
1630                        self.push_str(")\n");
1631                    }
1632                }
1633            }
1634
1635            Instruction::ReturnAsyncExport { .. } => {
1636                self.emit_cleanup();
1637                self.push_str(&format!(
1638                    "wit_bindgen_rust::rt::async_export_done({}, {});\n",
1639                    operands[0], operands[1]
1640                ));
1641            }
1642            Instruction::ReturnAsyncImport { .. } => unreachable!(),
1643
1644            Instruction::I32Load { offset } => {
1645                results.push(format!("*(({} + {}) as *const i32)", operands[0], offset));
1646            }
1647            Instruction::I32Load8U { offset } => {
1648                results.push(format!(
1649                    "i32::from(*(({} + {}) as *const u8))",
1650                    operands[0], offset
1651                ));
1652            }
1653            Instruction::I32Load8S { offset } => {
1654                results.push(format!(
1655                    "i32::from(*(({} + {}) as *const i8))",
1656                    operands[0], offset
1657                ));
1658            }
1659            Instruction::I32Load16U { offset } => {
1660                results.push(format!(
1661                    "i32::from(*(({} + {}) as *const u16))",
1662                    operands[0], offset
1663                ));
1664            }
1665            Instruction::I32Load16S { offset } => {
1666                results.push(format!(
1667                    "i32::from(*(({} + {}) as *const i16))",
1668                    operands[0], offset
1669                ));
1670            }
1671            Instruction::I64Load { offset } => {
1672                results.push(format!("*(({} + {}) as *const i64)", operands[0], offset));
1673            }
1674            Instruction::F32Load { offset } => {
1675                results.push(format!("*(({} + {}) as *const f32)", operands[0], offset));
1676            }
1677            Instruction::F64Load { offset } => {
1678                results.push(format!("*(({} + {}) as *const f64)", operands[0], offset));
1679            }
1680            Instruction::I32Store { offset } => {
1681                self.push_str(&format!(
1682                    "*(({} + {}) as *mut i32) = {};\n",
1683                    operands[1], offset, operands[0]
1684                ));
1685            }
1686            Instruction::I32Store8 { offset } => {
1687                self.push_str(&format!(
1688                    "*(({} + {}) as *mut u8) = ({}) as u8;\n",
1689                    operands[1], offset, operands[0]
1690                ));
1691            }
1692            Instruction::I32Store16 { offset } => {
1693                self.push_str(&format!(
1694                    "*(({} + {}) as *mut u16) = ({}) as u16;\n",
1695                    operands[1], offset, operands[0]
1696                ));
1697            }
1698            Instruction::I64Store { offset } => {
1699                self.push_str(&format!(
1700                    "*(({} + {}) as *mut i64) = {};\n",
1701                    operands[1], offset, operands[0]
1702                ));
1703            }
1704            Instruction::F32Store { offset } => {
1705                self.push_str(&format!(
1706                    "*(({} + {}) as *mut f32) = {};\n",
1707                    operands[1], offset, operands[0]
1708                ));
1709            }
1710            Instruction::F64Store { offset } => {
1711                self.push_str(&format!(
1712                    "*(({} + {}) as *mut f64) = {};\n",
1713                    operands[1], offset, operands[0]
1714                ));
1715            }
1716
1717            Instruction::Malloc { .. } => unimplemented!(),
1718            Instruction::Free {
1719                free: _,
1720                size,
1721                align,
1722            } => {
1723                self.push_str(&format!(
1724                    "wit_bindgen_rust::rt::canonical_abi_free({} as *mut u8, {}, {});\n",
1725                    operands[0], size, align
1726                ));
1727            }
1728        }
1729    }
1730}