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