wit_bindgen_gen_guest_rust/
lib.rs

1use heck::*;
2use std::collections::{HashMap, HashSet};
3use std::fmt::Write as _;
4use std::io::{Read, Write};
5use std::mem;
6use std::process::{Command, Stdio};
7use wit_bindgen_core::wit_parser::abi::{AbiVariant, Bindgen, Instruction, LiftLower, WasmType};
8use wit_bindgen_core::{
9    uwrite, uwriteln, wit_parser::*, Files, InterfaceGenerator as _, Source, TypeInfo, Types,
10    WorldGenerator,
11};
12use wit_bindgen_gen_rust_lib::{
13    int_repr, to_rust_ident, wasm_type, FnSig, RustFlagsRepr, RustFunctionGenerator, RustGenerator,
14    TypeMode,
15};
16
17#[derive(Default)]
18struct RustWasm {
19    types: Types,
20    src: Source,
21    opts: Opts,
22    exports: Vec<Source>,
23    skip: HashSet<String>,
24    interface_names: HashMap<InterfaceId, String>,
25}
26
27#[derive(Default, Debug, Clone)]
28#[cfg_attr(feature = "clap", derive(clap::Args))]
29pub struct Opts {
30    /// Whether or not `rustfmt` is executed to format generated code.
31    #[cfg_attr(feature = "clap", arg(long))]
32    pub rustfmt: bool,
33
34    /// Whether or not the bindings assume interface values are always
35    /// well-formed or whether checks are performed.
36    #[cfg_attr(feature = "clap", arg(long))]
37    pub unchecked: bool,
38
39    /// If true, code generation should avoid any features that depend on `std`.
40    #[cfg_attr(feature = "clap", arg(long))]
41    pub no_std: bool,
42
43    /// If true, adds `#[macro_export]` to the `export_*!` macro generated to
44    /// export it from the Rust crate.
45    #[cfg_attr(feature = "clap", arg(long))]
46    pub macro_export: bool,
47
48    /// If true, code generation should pass borrowed string arguments as
49    /// `&[u8]` instead of `&str`. Strings are still required to be valid
50    /// UTF-8, but this avoids the need for Rust code to do its own UTF-8
51    /// validation if it doesn't already have a `&str`.
52    #[cfg_attr(feature = "clap", arg(long))]
53    pub raw_strings: bool,
54
55    /// The prefix to use when calling functions from within the generated
56    /// `export!` macro.
57    ///
58    /// This enables the generated `export!` macro to reference code from
59    /// another mod/crate.
60    #[cfg_attr(feature = "clap", arg(long))]
61    pub macro_call_prefix: Option<String>,
62
63    /// The name of the generated `export!` macro to use.
64    ///
65    /// If `None`, the name is derived from the name of the world in the
66    /// format `export_{world_name}!`.
67    #[cfg_attr(feature = "clap", arg(long))]
68    pub export_macro_name: Option<String>,
69
70    /// Names of functions to skip generating bindings for.
71    #[cfg_attr(feature = "clap", arg(long))]
72    pub skip: Vec<String>,
73}
74
75impl Opts {
76    pub fn build(self) -> Box<dyn WorldGenerator> {
77        let mut r = RustWasm::new();
78        r.skip = self.skip.iter().cloned().collect();
79        r.opts = self;
80        Box::new(r)
81    }
82}
83
84impl RustWasm {
85    fn new() -> RustWasm {
86        RustWasm::default()
87    }
88
89    fn interface<'a>(
90        &'a mut self,
91        wasm_import_module: Option<&'a str>,
92        resolve: &'a Resolve,
93        default_param_mode: TypeMode,
94        in_import: bool,
95    ) -> InterfaceGenerator<'a> {
96        let mut sizes = SizeAlign::default();
97        sizes.fill(resolve);
98
99        InterfaceGenerator {
100            current_interface: None,
101            wasm_import_module,
102            src: Source::default(),
103            in_import,
104            gen: self,
105            sizes,
106            resolve,
107            default_param_mode,
108            return_pointer_area_size: 0,
109            return_pointer_area_align: 0,
110        }
111    }
112}
113
114impl WorldGenerator for RustWasm {
115    fn preprocess(&mut self, resolve: &Resolve, _world: WorldId) {
116        self.types.analyze(resolve);
117    }
118
119    fn import_interface(
120        &mut self,
121        resolve: &Resolve,
122        name: &str,
123        id: InterfaceId,
124        _files: &mut Files,
125    ) {
126        let prev = self.interface_names.insert(id, name.to_snake_case());
127        assert!(prev.is_none());
128        let mut gen = self.interface(Some(name), resolve, TypeMode::AllBorrowed("'a"), true);
129        gen.current_interface = Some(id);
130        gen.types(id);
131
132        for (_, func) in resolve.interfaces[id].functions.iter() {
133            gen.generate_guest_import(func);
134        }
135
136        gen.finish_append_submodule(name);
137    }
138
139    fn import_funcs(
140        &mut self,
141        resolve: &Resolve,
142        _world: WorldId,
143        funcs: &[(&str, &Function)],
144        _files: &mut Files,
145    ) {
146        let mut gen = self.interface(Some("$root"), resolve, TypeMode::AllBorrowed("'a"), true);
147
148        for (_, func) in funcs {
149            gen.generate_guest_import(func);
150        }
151
152        let src = gen.finish();
153        self.src.push_str(&src);
154    }
155
156    fn export_interface(
157        &mut self,
158        resolve: &Resolve,
159        name: &str,
160        id: InterfaceId,
161        _files: &mut Files,
162    ) {
163        self.interface_names.insert(id, name.to_snake_case());
164        let mut gen = self.interface(None, resolve, TypeMode::Owned, false);
165        gen.current_interface = Some(id);
166        gen.types(id);
167        gen.generate_exports(name, Some(name), resolve.interfaces[id].functions.values());
168        gen.finish_append_submodule(name);
169    }
170
171    fn export_funcs(
172        &mut self,
173        resolve: &Resolve,
174        world: WorldId,
175        funcs: &[(&str, &Function)],
176        _files: &mut Files,
177    ) {
178        let name = &resolve.worlds[world].name;
179        let mut gen = self.interface(None, resolve, TypeMode::Owned, false);
180        gen.generate_exports(name, None, funcs.iter().map(|f| f.1));
181        let src = gen.finish();
182        self.src.push_str(&src);
183    }
184
185    fn export_types(
186        &mut self,
187        resolve: &Resolve,
188        _world: WorldId,
189        types: &[(&str, TypeId)],
190        _files: &mut Files,
191    ) {
192        let mut gen = self.interface(None, resolve, TypeMode::Owned, false);
193        for (name, ty) in types {
194            gen.define_type(name, *ty);
195        }
196        let src = gen.finish();
197        self.src.push_str(&src);
198    }
199
200    fn finish(&mut self, resolve: &Resolve, world: WorldId, files: &mut Files) {
201        let name = &resolve.worlds[world].name;
202        if !self.exports.is_empty() {
203            let macro_name = if let Some(name) = self.opts.export_macro_name.as_ref() {
204                name.to_snake_case()
205            } else {
206                format!("export_{}", name.to_snake_case())
207            };
208            let macro_export = if self.opts.macro_export {
209                "#[macro_export]"
210            } else {
211                ""
212            };
213            uwrite!(
214                self.src,
215                "
216                    /// Declares the export of the component's world for the
217                    /// given type.
218                    {macro_export}
219                    macro_rules! {macro_name}(($t:ident) => {{
220                        const _: () = {{
221                "
222            );
223            for src in self.exports.iter() {
224                self.src.push_str(src);
225            }
226            uwrite!(
227                self.src,
228                "
229                        }};
230
231                        #[used]
232                        #[doc(hidden)]
233                        #[cfg(target_arch = \"wasm32\")]
234                        static __FORCE_SECTION_REF: fn() = __force_section_ref;
235                        #[doc(hidden)]
236                        #[cfg(target_arch = \"wasm32\")]
237                        fn __force_section_ref() {{
238                            {prefix}__link_section()
239                        }}
240                    }});
241                ",
242                prefix = self.opts.macro_call_prefix.as_deref().unwrap_or("")
243            );
244        }
245
246        self.src.push_str("\n#[cfg(target_arch = \"wasm32\")]\n");
247
248        // The custom section name here must start with "component-type" but
249        // otherwise is attempted to be unique here to ensure that this doesn't get
250        // concatenated to other custom sections by LLD by accident since LLD will
251        // concatenate custom sections of the same name.
252        self.src
253            .push_str(&format!("#[link_section = \"component-type:{}\"]\n", name,));
254
255        let component_type =
256            wit_component::metadata::encode(resolve, world, wit_component::StringEncoding::UTF8)
257                .unwrap();
258        self.src.push_str(&format!(
259            "pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; {}] = ",
260            component_type.len()
261        ));
262        self.src.push_str(&format!("{:?};\n", component_type));
263
264        self.src.push_str(
265            "
266            #[inline(never)]
267            #[doc(hidden)]
268            #[cfg(target_arch = \"wasm32\")]
269            pub fn __link_section() {}
270        ",
271        );
272
273        let mut src = mem::take(&mut self.src);
274        if self.opts.rustfmt {
275            let mut child = Command::new("rustfmt")
276                .arg("--edition=2018")
277                .stdin(Stdio::piped())
278                .stdout(Stdio::piped())
279                .spawn()
280                .expect("failed to spawn `rustfmt`");
281            child
282                .stdin
283                .take()
284                .unwrap()
285                .write_all(src.as_bytes())
286                .unwrap();
287            src.as_mut_string().truncate(0);
288            child
289                .stdout
290                .take()
291                .unwrap()
292                .read_to_string(src.as_mut_string())
293                .unwrap();
294            let status = child.wait().unwrap();
295            assert!(status.success());
296        }
297
298        files.push(&format!("{name}.rs"), src.as_bytes());
299    }
300}
301
302struct InterfaceGenerator<'a> {
303    src: Source,
304    current_interface: Option<InterfaceId>,
305    in_import: bool,
306    sizes: SizeAlign,
307    gen: &'a mut RustWasm,
308    wasm_import_module: Option<&'a str>,
309    resolve: &'a Resolve,
310    default_param_mode: TypeMode,
311    return_pointer_area_size: usize,
312    return_pointer_area_align: usize,
313}
314
315impl InterfaceGenerator<'_> {
316    fn generate_exports<'a>(
317        &mut self,
318        name: &str,
319        interface_name: Option<&str>,
320        funcs: impl Iterator<Item = &'a Function> + Clone,
321    ) {
322        let camel = name.to_upper_camel_case();
323        uwriteln!(self.src, "pub trait {camel} {{");
324        for func in funcs.clone() {
325            if self.gen.skip.contains(&func.name) {
326                continue;
327            }
328            let mut sig = FnSig::default();
329            sig.private = true;
330            self.print_signature(func, TypeMode::Owned, &sig);
331            self.src.push_str(";\n");
332        }
333        uwriteln!(self.src, "}}");
334
335        for func in funcs {
336            self.generate_guest_export(name, func, interface_name);
337        }
338    }
339
340    fn finish(&mut self) -> String {
341        if self.return_pointer_area_align > 0 {
342            uwrite!(
343                self.src,
344                "
345                    #[allow(unused_imports)]
346                    use wit_bindgen::rt::{{alloc, vec::Vec, string::String}};
347
348                    #[repr(align({align}))]
349                    struct _RetArea([u8; {size}]);
350                    static mut _RET_AREA: _RetArea = _RetArea([0; {size}]);
351                ",
352                align = self.return_pointer_area_align,
353                size = self.return_pointer_area_size,
354            );
355        }
356
357        mem::take(&mut self.src).into()
358    }
359
360    fn finish_append_submodule(mut self, name: &str) {
361        let module = self.finish();
362        let snake = name.to_snake_case();
363        uwriteln!(
364            self.gen.src,
365            "
366                #[allow(clippy::all)]
367                pub mod {snake} {{
368                    {module}
369                }}
370            "
371        );
372    }
373
374    fn generate_guest_import(&mut self, func: &Function) {
375        if self.gen.skip.contains(&func.name) {
376            return;
377        }
378
379        let sig = FnSig::default();
380        let param_mode = TypeMode::AllBorrowed("'_");
381        match &func.kind {
382            FunctionKind::Freestanding => {}
383        }
384        self.src.push_str("#[allow(clippy::all)]\n");
385        let params = self.print_signature(func, param_mode, &sig);
386        self.src.push_str("{\n");
387        self.src.push_str(
388            "
389                #[allow(unused_imports)]
390                use wit_bindgen::rt::{{alloc, vec::Vec, string::String}};
391            ",
392        );
393        self.src.push_str("unsafe {\n");
394
395        let mut f = FunctionBindgen::new(self, params);
396        f.gen.resolve.call(
397            AbiVariant::GuestImport,
398            LiftLower::LowerArgsLiftResults,
399            func,
400            &mut f,
401        );
402        let FunctionBindgen {
403            needs_cleanup_list,
404            src,
405            import_return_pointer_area_size,
406            import_return_pointer_area_align,
407            ..
408        } = f;
409
410        if needs_cleanup_list {
411            self.src.push_str("let mut cleanup_list = Vec::new();\n");
412        }
413        if import_return_pointer_area_size > 0 {
414            uwrite!(
415                self.src,
416                "
417                    #[repr(align({import_return_pointer_area_align}))]
418                    struct RetArea([u8; {import_return_pointer_area_size}]);
419                    let mut ret_area = core::mem::MaybeUninit::<RetArea>::uninit();
420                ",
421            );
422        }
423        self.src.push_str(&String::from(src));
424
425        self.src.push_str("}\n");
426        self.src.push_str("}\n");
427
428        match &func.kind {
429            FunctionKind::Freestanding => {}
430        }
431    }
432
433    fn generate_guest_export(
434        &mut self,
435        module_name: &str,
436        func: &Function,
437        interface_name: Option<&str>,
438    ) {
439        if self.gen.skip.contains(&func.name) {
440            return;
441        }
442
443        let module_name = module_name.to_snake_case();
444        let trait_bound = module_name.to_upper_camel_case();
445        let name_snake = func.name.to_snake_case();
446        let export_name = func.core_export_name(interface_name);
447        let mut macro_src = Source::default();
448        // Generate, simultaneously, the actual lifting/lowering function within
449        // the original module (`call_{name_snake}`) as well as the function
450        // which will ge exported from the wasm module itself through the export
451        // macro, `export_...` here.
452        //
453        // Both have the same type signature, but the one in the module is
454        // generic while the one in the macro uses `$t` as the name to delegate
455        // to and substitute as the generic.
456        uwrite!(
457            self.src,
458            "
459                #[doc(hidden)]
460                pub unsafe fn call_{name_snake}<T: {trait_bound}>(\
461            ",
462        );
463        uwrite!(
464            macro_src,
465            "
466                #[doc(hidden)]
467                #[export_name = \"{export_name}\"]
468                #[allow(non_snake_case)]
469                unsafe extern \"C\" fn __export_{module_name}_{name_snake}(\
470            ",
471        );
472
473        let sig = self.resolve.wasm_signature(AbiVariant::GuestExport, func);
474        let mut params = Vec::new();
475        for (i, param) in sig.params.iter().enumerate() {
476            let name = format!("arg{}", i);
477            uwrite!(self.src, "{name}: {},", wasm_type(*param));
478            uwrite!(macro_src, "{name}: {},", wasm_type(*param));
479            params.push(name);
480        }
481        self.src.push_str(")");
482        macro_src.push_str(")");
483
484        match sig.results.len() {
485            0 => {}
486            1 => {
487                uwrite!(self.src, " -> {}", wasm_type(sig.results[0]));
488                uwrite!(macro_src, " -> {}", wasm_type(sig.results[0]));
489            }
490            _ => unimplemented!(),
491        }
492
493        self.push_str(" {\n");
494
495        uwrite!(
496            self.src,
497            "
498                #[allow(unused_imports)]
499                use wit_bindgen::rt::{{alloc, vec::Vec, string::String}};
500            "
501        );
502
503        // Finish out the macro-generated export implementation.
504        macro_src.push_str(" {\n");
505        let prefix = format!(
506            "{}{}",
507            self.gen.opts.macro_call_prefix.as_deref().unwrap_or(""),
508            match interface_name {
509                Some(_) => format!("{module_name}::"),
510                None => String::new(),
511            },
512        );
513
514        uwrite!(macro_src, "{prefix}call_{name_snake}::<$t>(",);
515        for param in params.iter() {
516            uwrite!(macro_src, "{param},");
517        }
518        uwriteln!(macro_src, ")\n}}");
519
520        let mut f = FunctionBindgen::new(self, params);
521        f.gen.resolve.call(
522            AbiVariant::GuestExport,
523            LiftLower::LiftArgsLowerResults,
524            func,
525            &mut f,
526        );
527        let FunctionBindgen {
528            needs_cleanup_list,
529            src,
530            ..
531        } = f;
532        assert!(!needs_cleanup_list);
533        self.src.push_str(&String::from(src));
534        self.src.push_str("}\n");
535
536        if self.resolve.guest_export_needs_post_return(func) {
537            // Like above, generate both a generic function in the module itself
538            // as well as something to go in the export macro.
539            uwrite!(
540                self.src,
541                "
542                    #[doc(hidden)]
543                    pub unsafe fn post_return_{name_snake}<T: {trait_bound}>(\
544                "
545            );
546            uwrite!(
547                macro_src,
548                "
549                    #[doc(hidden)]
550                    #[export_name = \"cabi_post_{export_name}\"]
551                    #[allow(non_snake_case)]
552                    unsafe extern \"C\" fn __post_return_{module_name}_{name_snake}(\
553                "
554            );
555            let mut params = Vec::new();
556            for (i, result) in sig.results.iter().enumerate() {
557                let name = format!("arg{}", i);
558                uwrite!(self.src, "{name}: {},", wasm_type(*result));
559                uwrite!(macro_src, "{name}: {},", wasm_type(*result));
560                params.push(name);
561            }
562            self.src.push_str(") {\n");
563            macro_src.push_str(") {\n");
564
565            // Finish out the macro here
566            uwrite!(macro_src, "{prefix}post_return_{name_snake}::<$t>(");
567            for param in params.iter() {
568                uwrite!(macro_src, "{param},");
569            }
570            uwriteln!(macro_src, ")\n}}");
571
572            let mut f = FunctionBindgen::new(self, params);
573            f.gen.resolve.post_return(func, &mut f);
574            let FunctionBindgen {
575                needs_cleanup_list,
576                src,
577                ..
578            } = f;
579            assert!(!needs_cleanup_list);
580            self.src.push_str(&String::from(src));
581            self.src.push_str("}\n");
582        }
583
584        self.gen.exports.push(macro_src);
585    }
586}
587
588impl<'a> RustGenerator<'a> for InterfaceGenerator<'a> {
589    fn resolve(&self) -> &'a Resolve {
590        self.resolve
591    }
592
593    fn path_to_interface(&self, interface: InterfaceId) -> Option<String> {
594        match self.current_interface {
595            Some(id) if id == interface => None,
596            _ => {
597                let name = &self.gen.interface_names[&interface];
598                Some(if self.current_interface.is_some() {
599                    format!("super::{name}")
600                } else {
601                    name.clone()
602                })
603            }
604        }
605    }
606
607    fn use_std(&self) -> bool {
608        !self.gen.opts.no_std
609    }
610
611    fn use_raw_strings(&self) -> bool {
612        self.gen.opts.raw_strings
613    }
614
615    fn vec_name(&self) -> &'static str {
616        "wit_bindgen::rt::vec::Vec"
617    }
618
619    fn string_name(&self) -> &'static str {
620        "wit_bindgen::rt::string::String"
621    }
622
623    fn default_param_mode(&self) -> TypeMode {
624        self.default_param_mode
625    }
626
627    fn push_str(&mut self, s: &str) {
628        self.src.push_str(s);
629    }
630
631    fn info(&self, ty: TypeId) -> TypeInfo {
632        self.gen.types.get(ty)
633    }
634
635    fn types_mut(&mut self) -> &mut Types {
636        &mut self.gen.types
637    }
638
639    fn print_borrowed_slice(&mut self, mutbl: bool, ty: &Type, lifetime: &'static str) {
640        self.print_rust_slice(mutbl, ty, lifetime);
641    }
642
643    fn print_borrowed_str(&mut self, lifetime: &'static str) {
644        self.push_str("&");
645        if lifetime != "'_" {
646            self.push_str(lifetime);
647            self.push_str(" ");
648        }
649        if self.gen.opts.raw_strings {
650            self.push_str("[u8]");
651        } else {
652            self.push_str("str");
653        }
654    }
655}
656
657impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
658    fn resolve(&self) -> &'a Resolve {
659        self.resolve
660    }
661
662    fn type_record(&mut self, id: TypeId, _name: &str, record: &Record, docs: &Docs) {
663        self.print_typedef_record(id, record, docs, false);
664    }
665
666    fn type_tuple(&mut self, id: TypeId, _name: &str, tuple: &Tuple, docs: &Docs) {
667        self.print_typedef_tuple(id, tuple, docs);
668    }
669
670    fn type_flags(&mut self, _id: TypeId, name: &str, flags: &Flags, docs: &Docs) {
671        self.src.push_str("wit_bindgen::bitflags::bitflags! {\n");
672        self.rustdoc(docs);
673        let repr = RustFlagsRepr::new(flags);
674        self.src.push_str(&format!(
675            "pub struct {}: {repr} {{\n",
676            name.to_upper_camel_case(),
677        ));
678        for (i, flag) in flags.flags.iter().enumerate() {
679            self.rustdoc(&flag.docs);
680            self.src.push_str(&format!(
681                "const {} = 1 << {};\n",
682                flag.name.to_shouty_snake_case(),
683                i,
684            ));
685        }
686        self.src.push_str("}\n");
687        self.src.push_str("}\n");
688
689        // Add a `from_bits_preserve` method.
690        self.src
691            .push_str(&format!("impl {} {{\n", name.to_upper_camel_case()));
692        self.src.push_str(&format!(
693            "    /// Convert from a raw integer, preserving any unknown bits. See\n"
694        ));
695        self.src.push_str(&format!(
696            "    /// <https://github.com/bitflags/bitflags/issues/263#issuecomment-957088321>\n"
697        ));
698        self.src.push_str(&format!(
699            "    pub fn from_bits_preserve(bits: {repr}) -> Self {{\n",
700        ));
701        self.src.push_str(&format!("        Self {{ bits }}\n"));
702        self.src.push_str(&format!("    }}\n"));
703        self.src.push_str(&format!("}}\n"));
704    }
705
706    fn type_variant(&mut self, id: TypeId, _name: &str, variant: &Variant, docs: &Docs) {
707        self.print_typedef_variant(id, variant, docs, false);
708    }
709
710    fn type_union(&mut self, id: TypeId, _name: &str, union: &Union, docs: &Docs) {
711        self.print_typedef_union(id, union, docs, false);
712    }
713
714    fn type_option(&mut self, id: TypeId, _name: &str, payload: &Type, docs: &Docs) {
715        self.print_typedef_option(id, payload, docs);
716    }
717
718    fn type_result(&mut self, id: TypeId, _name: &str, result: &Result_, docs: &Docs) {
719        self.print_typedef_result(id, result, docs);
720    }
721
722    fn type_enum(&mut self, id: TypeId, name: &str, enum_: &Enum, docs: &Docs) {
723        self.print_typedef_enum(id, name, enum_, docs, &[], Box::new(|_| String::new()));
724    }
725
726    fn type_alias(&mut self, id: TypeId, _name: &str, ty: &Type, docs: &Docs) {
727        self.print_typedef_alias(id, ty, docs);
728    }
729
730    fn type_list(&mut self, id: TypeId, _name: &str, ty: &Type, docs: &Docs) {
731        self.print_type_list(id, ty, docs);
732    }
733
734    fn type_builtin(&mut self, _id: TypeId, name: &str, ty: &Type, docs: &Docs) {
735        self.rustdoc(docs);
736        self.src
737            .push_str(&format!("pub type {}", name.to_upper_camel_case()));
738        self.src.push_str(" = ");
739        self.print_ty(ty, TypeMode::Owned);
740        self.src.push_str(";\n");
741    }
742}
743
744struct FunctionBindgen<'a, 'b> {
745    gen: &'b mut InterfaceGenerator<'a>,
746    params: Vec<String>,
747    src: Source,
748    blocks: Vec<String>,
749    block_storage: Vec<(Source, Vec<(String, String)>)>,
750    tmp: usize,
751    needs_cleanup_list: bool,
752    cleanup: Vec<(String, String)>,
753    import_return_pointer_area_size: usize,
754    import_return_pointer_area_align: usize,
755}
756
757impl<'a, 'b> FunctionBindgen<'a, 'b> {
758    fn new(gen: &'b mut InterfaceGenerator<'a>, params: Vec<String>) -> FunctionBindgen<'a, 'b> {
759        FunctionBindgen {
760            gen,
761            params,
762            src: Default::default(),
763            blocks: Vec::new(),
764            block_storage: Vec::new(),
765            tmp: 0,
766            needs_cleanup_list: false,
767            cleanup: Vec::new(),
768            import_return_pointer_area_size: 0,
769            import_return_pointer_area_align: 0,
770        }
771    }
772
773    fn emit_cleanup(&mut self) {
774        for (ptr, layout) in mem::take(&mut self.cleanup) {
775            self.push_str(&format!(
776                "if {layout}.size() != 0 {{\nalloc::dealloc({ptr}, {layout});\n}}\n"
777            ));
778        }
779        if self.needs_cleanup_list {
780            self.push_str(
781                "for (ptr, layout) in cleanup_list {\n
782                    if layout.size() != 0 {\n
783                        alloc::dealloc(ptr, layout);\n
784                    }\n
785                }\n",
786            );
787        }
788    }
789
790    fn declare_import(
791        &mut self,
792        module_name: &str,
793        name: &str,
794        params: &[WasmType],
795        results: &[WasmType],
796    ) -> String {
797        // Define the actual function we're calling inline
798        uwriteln!(
799            self.src,
800            "
801                #[link(wasm_import_module = \"{module_name}\")]
802                extern \"C\" {{
803                    #[cfg_attr(target_arch = \"wasm32\", link_name = \"{name}\")]
804                    #[cfg_attr(not(target_arch = \"wasm32\"), link_name = \"{module_name}_{name}\")]
805                    fn wit_import(\
806            "
807        );
808        for param in params.iter() {
809            self.push_str("_: ");
810            self.push_str(wasm_type(*param));
811            self.push_str(", ");
812        }
813        self.push_str(")");
814        assert!(results.len() < 2);
815        for result in results.iter() {
816            self.push_str(" -> ");
817            self.push_str(wasm_type(*result));
818        }
819        self.push_str(";\n}\n");
820        "wit_import".to_string()
821    }
822}
823
824impl RustFunctionGenerator for FunctionBindgen<'_, '_> {
825    fn push_str(&mut self, s: &str) {
826        self.src.push_str(s);
827    }
828
829    fn tmp(&mut self) -> usize {
830        let ret = self.tmp;
831        self.tmp += 1;
832        ret
833    }
834
835    fn rust_gen(&self) -> &dyn RustGenerator {
836        self.gen
837    }
838
839    fn lift_lower(&self) -> LiftLower {
840        if self.gen.in_import {
841            LiftLower::LowerArgsLiftResults
842        } else {
843            LiftLower::LiftArgsLowerResults
844        }
845    }
846}
847
848impl Bindgen for FunctionBindgen<'_, '_> {
849    type Operand = String;
850
851    fn push_block(&mut self) {
852        let prev_src = mem::take(&mut self.src);
853        let prev_cleanup = mem::take(&mut self.cleanup);
854        self.block_storage.push((prev_src, prev_cleanup));
855    }
856
857    fn finish_block(&mut self, operands: &mut Vec<String>) {
858        if self.cleanup.len() > 0 {
859            self.needs_cleanup_list = true;
860            self.push_str("cleanup_list.extend_from_slice(&[");
861            for (ptr, layout) in mem::take(&mut self.cleanup) {
862                self.push_str("(");
863                self.push_str(&ptr);
864                self.push_str(", ");
865                self.push_str(&layout);
866                self.push_str("),");
867            }
868            self.push_str("]);\n");
869        }
870        let (prev_src, prev_cleanup) = self.block_storage.pop().unwrap();
871        let src = mem::replace(&mut self.src, prev_src);
872        self.cleanup = prev_cleanup;
873        let expr = match operands.len() {
874            0 => "()".to_string(),
875            1 => operands[0].clone(),
876            _ => format!("({})", operands.join(", ")),
877        };
878        if src.is_empty() {
879            self.blocks.push(expr);
880        } else if operands.is_empty() {
881            self.blocks.push(format!("{{\n{}\n}}", &src[..]));
882        } else {
883            self.blocks.push(format!("{{\n{}\n{}\n}}", &src[..], expr));
884        }
885    }
886
887    fn return_pointer(&mut self, size: usize, align: usize) -> String {
888        let tmp = self.tmp();
889
890        // Imports get a per-function return area to facilitate using the
891        // stack whereas exports use a per-module return area to cut down on
892        // stack usage. Note that for imports this also facilitates "adapter
893        // modules" for components to not have data segments.
894        if self.gen.in_import {
895            self.import_return_pointer_area_size = self.import_return_pointer_area_size.max(size);
896            self.import_return_pointer_area_align =
897                self.import_return_pointer_area_align.max(align);
898            uwrite!(self.src, "let ptr{tmp} = ret_area.as_mut_ptr() as i32;");
899        } else {
900            self.gen.return_pointer_area_size = self.gen.return_pointer_area_size.max(size);
901            self.gen.return_pointer_area_align = self.gen.return_pointer_area_align.max(align);
902            uwriteln!(self.src, "let ptr{tmp} = _RET_AREA.0.as_mut_ptr() as i32;");
903        }
904        format!("ptr{}", tmp)
905    }
906
907    fn sizes(&self) -> &SizeAlign {
908        &self.gen.sizes
909    }
910
911    fn is_list_canonical(&self, resolve: &Resolve, ty: &Type) -> bool {
912        resolve.all_bits_valid(ty)
913    }
914
915    fn emit(
916        &mut self,
917        _resolve: &Resolve,
918        inst: &Instruction<'_>,
919        operands: &mut Vec<String>,
920        results: &mut Vec<String>,
921    ) {
922        let unchecked = self.gen.gen.opts.unchecked;
923        let mut top_as = |cvt: &str| {
924            let mut s = operands.pop().unwrap();
925            s.push_str(" as ");
926            s.push_str(cvt);
927            results.push(s);
928        };
929
930        match inst {
931            Instruction::GetArg { nth } => results.push(self.params[*nth].clone()),
932            Instruction::I32Const { val } => results.push(format!("{}i32", val)),
933            Instruction::ConstZero { tys } => {
934                for ty in tys.iter() {
935                    match ty {
936                        WasmType::I32 => results.push("0i32".to_string()),
937                        WasmType::I64 => results.push("0i64".to_string()),
938                        WasmType::F32 => results.push("0.0f32".to_string()),
939                        WasmType::F64 => results.push("0.0f64".to_string()),
940                    }
941                }
942            }
943
944            Instruction::I64FromU64 | Instruction::I64FromS64 => {
945                let s = operands.pop().unwrap();
946                results.push(format!("wit_bindgen::rt::as_i64({})", s));
947            }
948            Instruction::I32FromChar
949            | Instruction::I32FromU8
950            | Instruction::I32FromS8
951            | Instruction::I32FromU16
952            | Instruction::I32FromS16
953            | Instruction::I32FromU32
954            | Instruction::I32FromS32 => {
955                let s = operands.pop().unwrap();
956                results.push(format!("wit_bindgen::rt::as_i32({})", s));
957            }
958
959            Instruction::F32FromFloat32 => {
960                let s = operands.pop().unwrap();
961                results.push(format!("wit_bindgen::rt::as_f32({})", s));
962            }
963            Instruction::F64FromFloat64 => {
964                let s = operands.pop().unwrap();
965                results.push(format!("wit_bindgen::rt::as_f64({})", s));
966            }
967            Instruction::Float32FromF32
968            | Instruction::Float64FromF64
969            | Instruction::S32FromI32
970            | Instruction::S64FromI64 => {
971                results.push(operands.pop().unwrap());
972            }
973            Instruction::S8FromI32 => top_as("i8"),
974            Instruction::U8FromI32 => top_as("u8"),
975            Instruction::S16FromI32 => top_as("i16"),
976            Instruction::U16FromI32 => top_as("u16"),
977            Instruction::U32FromI32 => top_as("u32"),
978            Instruction::U64FromI64 => top_as("u64"),
979            Instruction::CharFromI32 => {
980                if unchecked {
981                    results.push(format!(
982                        "core::char::from_u32_unchecked({} as u32)",
983                        operands[0]
984                    ));
985                } else {
986                    results.push(format!(
987                        "core::char::from_u32({} as u32).unwrap()",
988                        operands[0]
989                    ));
990                }
991            }
992
993            Instruction::Bitcasts { casts } => {
994                wit_bindgen_gen_rust_lib::bitcast(casts, operands, results)
995            }
996
997            Instruction::I32FromBool => {
998                results.push(format!("match {} {{ true => 1, false => 0 }}", operands[0]));
999            }
1000            Instruction::BoolFromI32 => {
1001                if unchecked {
1002                    results.push(format!(
1003                        "core::mem::transmute::<u8, bool>({} as u8)",
1004                        operands[0],
1005                    ));
1006                } else {
1007                    results.push(format!(
1008                        "match {} {{
1009                            0 => false,
1010                            1 => true,
1011                            _ => panic!(\"invalid bool discriminant\"),
1012                        }}",
1013                        operands[0],
1014                    ));
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_upper_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(*ty, record, &operands[0], results);
1042            }
1043            Instruction::RecordLift { ty, record, .. } => {
1044                self.record_lift(*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(*ty);
1070                for (case, block) in variant.cases.iter().zip(blocks) {
1071                    let case_name = case.name.to_upper_camel_case();
1072                    self.push_str(&format!("{name}::{case_name}"));
1073                    if case.ty.is_some() {
1074                        self.push_str(&format!("(e) => {block},\n"));
1075                    } else {
1076                        self.push_str(&format!(" => {{\n{block}\n}}\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.is_none()) && unchecked =>
1086            {
1087                self.blocks.drain(self.blocks.len() - variant.cases.len()..);
1088                let mut result = format!("core::mem::transmute::<_, ");
1089                result.push_str(&name.to_upper_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_str(")");
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(*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.is_some() {
1113                        format!("({block})")
1114                    } else {
1115                        String::new()
1116                    };
1117                    let case = case.name.to_upper_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_str("}");
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(*ty);
1141                for (case_name, block) in self.gen.union_case_names(union).into_iter().zip(blocks) {
1142                    self.push_str(&format!("{name}::{case_name}(e) => {block},\n"));
1143                }
1144                self.push_str("};\n");
1145            }
1146
1147            Instruction::UnionLift { union, ty, .. } => {
1148                let blocks = self
1149                    .blocks
1150                    .drain(self.blocks.len() - union.cases.len()..)
1151                    .collect::<Vec<_>>();
1152                let op0 = &operands[0];
1153                let mut result = format!("match {op0} {{\n");
1154                for (i, (case_name, block)) in self
1155                    .gen
1156                    .union_case_names(union)
1157                    .into_iter()
1158                    .zip(blocks)
1159                    .enumerate()
1160                {
1161                    let pat = if i == union.cases.len() - 1 && unchecked {
1162                        String::from("_")
1163                    } else {
1164                        i.to_string()
1165                    };
1166                    let name = self.typename_lift(*ty);
1167                    result.push_str(&format!("{pat} => {name}::{case_name}({block}),\n"));
1168                }
1169                if !unchecked {
1170                    result.push_str("_ => panic!(\"invalid union discriminant\"),\n");
1171                }
1172                result.push_str("}");
1173                results.push(result);
1174            }
1175
1176            Instruction::OptionLower {
1177                results: result_types,
1178                ..
1179            } => {
1180                let some = self.blocks.pop().unwrap();
1181                let none = self.blocks.pop().unwrap();
1182                self.let_results(result_types.len(), results);
1183                let operand = &operands[0];
1184                self.push_str(&format!(
1185                    "match {operand} {{
1186                        Some(e) => {some},
1187                        None => {{\n{none}\n}},
1188                    }};"
1189                ));
1190            }
1191
1192            Instruction::OptionLift { .. } => {
1193                let some = self.blocks.pop().unwrap();
1194                let none = self.blocks.pop().unwrap();
1195                assert_eq!(none, "()");
1196                let operand = &operands[0];
1197                let invalid = if unchecked {
1198                    "core::hint::unreachable_unchecked()"
1199                } else {
1200                    "panic!(\"invalid enum discriminant\")"
1201                };
1202                results.push(format!(
1203                    "match {operand} {{
1204                        0 => None,
1205                        1 => Some({some}),
1206                        _ => {invalid},
1207                    }}"
1208                ));
1209            }
1210
1211            Instruction::ResultLower {
1212                results: result_types,
1213                result,
1214                ..
1215            } => {
1216                let err = self.blocks.pop().unwrap();
1217                let ok = self.blocks.pop().unwrap();
1218                self.let_results(result_types.len(), results);
1219                let operand = &operands[0];
1220                let ok_binding = if result.ok.is_some() { "e" } else { "_" };
1221                let err_binding = if result.err.is_some() { "e" } else { "_" };
1222                self.push_str(&format!(
1223                    "match {operand} {{
1224                        Ok({ok_binding}) => {{ {ok} }},
1225                        Err({err_binding}) => {{ {err} }},
1226                    }};"
1227                ));
1228            }
1229
1230            Instruction::ResultLift { .. } => {
1231                let err = self.blocks.pop().unwrap();
1232                let ok = self.blocks.pop().unwrap();
1233                let operand = &operands[0];
1234                let invalid = if unchecked {
1235                    "core::hint::unreachable_unchecked()"
1236                } else {
1237                    "panic!(\"invalid enum discriminant\")"
1238                };
1239                results.push(format!(
1240                    "match {operand} {{
1241                        0 => Ok({ok}),
1242                        1 => Err({err}),
1243                        _ => {invalid},
1244                    }}"
1245                ));
1246            }
1247
1248            Instruction::EnumLower { enum_, name, .. } => {
1249                let mut result = format!("match {} {{\n", operands[0]);
1250                let name = name.to_upper_camel_case();
1251                for (i, case) in enum_.cases.iter().enumerate() {
1252                    let case = case.name.to_upper_camel_case();
1253                    result.push_str(&format!("{name}::{case} => {i},\n"));
1254                }
1255                result.push_str("}");
1256                results.push(result);
1257            }
1258
1259            // In unchecked mode when this type is a named enum then we know we
1260            // defined the type so we can transmute directly into it.
1261            Instruction::EnumLift { enum_, name, .. } if unchecked => {
1262                let mut result = format!("core::mem::transmute::<_, ");
1263                result.push_str(&name.to_upper_camel_case());
1264                result.push_str(">(");
1265                result.push_str(&operands[0]);
1266                result.push_str(" as ");
1267                result.push_str(int_repr(enum_.tag()));
1268                result.push_str(")");
1269                results.push(result);
1270            }
1271
1272            Instruction::EnumLift { enum_, name, .. } => {
1273                let mut result = format!("match ");
1274                result.push_str(&operands[0]);
1275                result.push_str(" {\n");
1276                let name = name.to_upper_camel_case();
1277                for (i, case) in enum_.cases.iter().enumerate() {
1278                    let case = case.name.to_upper_camel_case();
1279                    result.push_str(&format!("{i} => {name}::{case},\n"));
1280                }
1281                result.push_str("_ => panic!(\"invalid enum discriminant\"),\n");
1282                result.push_str("}");
1283                results.push(result);
1284            }
1285
1286            Instruction::ListCanonLower { realloc, .. } => {
1287                let tmp = self.tmp();
1288                let val = format!("vec{}", tmp);
1289                let ptr = format!("ptr{}", tmp);
1290                let len = format!("len{}", tmp);
1291                if realloc.is_none() {
1292                    self.push_str(&format!("let {} = {};\n", val, operands[0]));
1293                } else {
1294                    let op0 = operands.pop().unwrap();
1295                    self.push_str(&format!("let {} = ({}).into_boxed_slice();\n", val, op0));
1296                }
1297                self.push_str(&format!("let {} = {}.as_ptr() as i32;\n", ptr, val));
1298                self.push_str(&format!("let {} = {}.len() as i32;\n", len, val));
1299                if realloc.is_some() {
1300                    self.push_str(&format!("core::mem::forget({});\n", val));
1301                }
1302                results.push(ptr);
1303                results.push(len);
1304            }
1305
1306            Instruction::ListCanonLift { .. } => {
1307                let tmp = self.tmp();
1308                let len = format!("len{}", tmp);
1309                self.push_str(&format!("let {} = {} as usize;\n", len, operands[1]));
1310                let result = format!(
1311                    "Vec::from_raw_parts({} as *mut _, {1}, {1})",
1312                    operands[0], len
1313                );
1314                results.push(result);
1315            }
1316
1317            Instruction::StringLower { realloc } => {
1318                let tmp = self.tmp();
1319                let val = format!("vec{}", tmp);
1320                let ptr = format!("ptr{}", tmp);
1321                let len = format!("len{}", tmp);
1322                if realloc.is_none() {
1323                    self.push_str(&format!("let {} = {};\n", val, operands[0]));
1324                } else {
1325                    let op0 = format!("{}.into_bytes()", operands[0]);
1326                    self.push_str(&format!("let {} = ({}).into_boxed_slice();\n", val, op0));
1327                }
1328                self.push_str(&format!("let {} = {}.as_ptr() as i32;\n", ptr, val));
1329                self.push_str(&format!("let {} = {}.len() as i32;\n", len, val));
1330                if realloc.is_some() {
1331                    self.push_str(&format!("core::mem::forget({});\n", val));
1332                }
1333                results.push(ptr);
1334                results.push(len);
1335            }
1336
1337            Instruction::StringLift => {
1338                let tmp = self.tmp();
1339                let len = format!("len{}", tmp);
1340                self.push_str(&format!("let {} = {} as usize;\n", len, operands[1]));
1341                let result = format!(
1342                    "Vec::from_raw_parts({} as *mut _, {1}, {1})",
1343                    operands[0], len
1344                );
1345                if self.gen.gen.opts.raw_strings {
1346                    results.push(result);
1347                } else if unchecked {
1348                    results.push(format!("String::from_utf8_unchecked({})", result));
1349                } else {
1350                    results.push(format!("String::from_utf8({}).unwrap()", result));
1351                }
1352            }
1353
1354            Instruction::ListLower { element, realloc } => {
1355                let body = self.blocks.pop().unwrap();
1356                let tmp = self.tmp();
1357                let vec = format!("vec{tmp}");
1358                let result = format!("result{tmp}");
1359                let layout = format!("layout{tmp}");
1360                let len = format!("len{tmp}");
1361                self.push_str(&format!(
1362                    "let {vec} = {operand0};\n",
1363                    operand0 = operands[0]
1364                ));
1365                self.push_str(&format!("let {len} = {vec}.len() as i32;\n"));
1366                let size = self.gen.sizes.size(element);
1367                let align = self.gen.sizes.align(element);
1368                self.push_str(&format!(
1369                    "let {layout} = alloc::Layout::from_size_align_unchecked({vec}.len() * {size}, {align});\n",
1370                ));
1371                self.push_str(&format!(
1372                    "let {result} = if {layout}.size() != 0\n{{\nlet ptr = alloc::alloc({layout});\n",
1373                ));
1374                self.push_str(&format!(
1375                    "if ptr.is_null()\n{{\nalloc::handle_alloc_error({layout});\n}}\nptr\n}}",
1376                ));
1377                self.push_str(&format!("else {{\ncore::ptr::null_mut()\n}};\n",));
1378                self.push_str(&format!("for (i, e) in {vec}.into_iter().enumerate() {{\n",));
1379                self.push_str(&format!(
1380                    "let base = {result} as i32 + (i as i32) * {size};\n",
1381                ));
1382                self.push_str(&body);
1383                self.push_str("}\n");
1384                results.push(format!("{result} as i32"));
1385                results.push(len);
1386
1387                if realloc.is_none() {
1388                    // If an allocator isn't requested then we must clean up the
1389                    // allocation ourselves since our callee isn't taking
1390                    // ownership.
1391                    self.cleanup.push((result, layout));
1392                }
1393            }
1394
1395            Instruction::ListLift { element, .. } => {
1396                let body = self.blocks.pop().unwrap();
1397                let tmp = self.tmp();
1398                let size = self.gen.sizes.size(element);
1399                let align = self.gen.sizes.align(element);
1400                let len = format!("len{tmp}");
1401                let base = format!("base{tmp}");
1402                let result = format!("result{tmp}");
1403                self.push_str(&format!(
1404                    "let {base} = {operand0};\n",
1405                    operand0 = operands[0]
1406                ));
1407                self.push_str(&format!(
1408                    "let {len} = {operand1};\n",
1409                    operand1 = operands[1]
1410                ));
1411                self.push_str(&format!(
1412                    "let mut {result} = Vec::with_capacity({len} as usize);\n",
1413                ));
1414
1415                self.push_str("for i in 0..");
1416                self.push_str(&len);
1417                self.push_str(" {\n");
1418                self.push_str("let base = ");
1419                self.push_str(&base);
1420                self.push_str(" + i *");
1421                self.push_str(&size.to_string());
1422                self.push_str(";\n");
1423                self.push_str(&result);
1424                self.push_str(".push(");
1425                self.push_str(&body);
1426                self.push_str(");\n");
1427                self.push_str("}\n");
1428                results.push(result);
1429                self.push_str(&format!(
1430                    "wit_bindgen::rt::dealloc({base}, ({len} as usize) * {size}, {align});\n",
1431                ));
1432            }
1433
1434            Instruction::IterElem { .. } => results.push("e".to_string()),
1435
1436            Instruction::IterBasePointer => results.push("base".to_string()),
1437
1438            Instruction::CallWasm { name, sig, .. } => {
1439                let func = self.declare_import(
1440                    self.gen.wasm_import_module.unwrap(),
1441                    name,
1442                    &sig.params,
1443                    &sig.results,
1444                );
1445
1446                // ... then call the function with all our operands
1447                if sig.results.len() > 0 {
1448                    self.push_str("let ret = ");
1449                    results.push("ret".to_string());
1450                }
1451                self.push_str(&func);
1452                self.push_str("(");
1453                self.push_str(&operands.join(", "));
1454                self.push_str(");\n");
1455            }
1456
1457            Instruction::CallInterface { func, .. } => {
1458                self.let_results(func.results.len(), results);
1459                match &func.kind {
1460                    FunctionKind::Freestanding => {
1461                        self.push_str(&format!("T::{}", to_rust_ident(&func.name)));
1462                    }
1463                }
1464                self.push_str("(");
1465                self.push_str(&operands.join(", "));
1466                self.push_str(")");
1467                self.push_str(";\n");
1468            }
1469
1470            Instruction::Return { amt, .. } => {
1471                self.emit_cleanup();
1472                match amt {
1473                    0 => {}
1474                    1 => {
1475                        self.push_str(&operands[0]);
1476                        self.push_str("\n");
1477                    }
1478                    _ => {
1479                        self.push_str("(");
1480                        self.push_str(&operands.join(", "));
1481                        self.push_str(")\n");
1482                    }
1483                }
1484            }
1485
1486            Instruction::I32Load { offset } => {
1487                results.push(format!("*(({} + {}) as *const i32)", operands[0], offset));
1488            }
1489            Instruction::I32Load8U { offset } => {
1490                results.push(format!(
1491                    "i32::from(*(({} + {}) as *const u8))",
1492                    operands[0], offset
1493                ));
1494            }
1495            Instruction::I32Load8S { offset } => {
1496                results.push(format!(
1497                    "i32::from(*(({} + {}) as *const i8))",
1498                    operands[0], offset
1499                ));
1500            }
1501            Instruction::I32Load16U { offset } => {
1502                results.push(format!(
1503                    "i32::from(*(({} + {}) as *const u16))",
1504                    operands[0], offset
1505                ));
1506            }
1507            Instruction::I32Load16S { offset } => {
1508                results.push(format!(
1509                    "i32::from(*(({} + {}) as *const i16))",
1510                    operands[0], offset
1511                ));
1512            }
1513            Instruction::I64Load { offset } => {
1514                results.push(format!("*(({} + {}) as *const i64)", operands[0], offset));
1515            }
1516            Instruction::F32Load { offset } => {
1517                results.push(format!("*(({} + {}) as *const f32)", operands[0], offset));
1518            }
1519            Instruction::F64Load { offset } => {
1520                results.push(format!("*(({} + {}) as *const f64)", operands[0], offset));
1521            }
1522            Instruction::I32Store { offset } => {
1523                self.push_str(&format!(
1524                    "*(({} + {}) as *mut i32) = {};\n",
1525                    operands[1], offset, operands[0]
1526                ));
1527            }
1528            Instruction::I32Store8 { offset } => {
1529                self.push_str(&format!(
1530                    "*(({} + {}) as *mut u8) = ({}) as u8;\n",
1531                    operands[1], offset, operands[0]
1532                ));
1533            }
1534            Instruction::I32Store16 { offset } => {
1535                self.push_str(&format!(
1536                    "*(({} + {}) as *mut u16) = ({}) as u16;\n",
1537                    operands[1], offset, operands[0]
1538                ));
1539            }
1540            Instruction::I64Store { offset } => {
1541                self.push_str(&format!(
1542                    "*(({} + {}) as *mut i64) = {};\n",
1543                    operands[1], offset, operands[0]
1544                ));
1545            }
1546            Instruction::F32Store { offset } => {
1547                self.push_str(&format!(
1548                    "*(({} + {}) as *mut f32) = {};\n",
1549                    operands[1], offset, operands[0]
1550                ));
1551            }
1552            Instruction::F64Store { offset } => {
1553                self.push_str(&format!(
1554                    "*(({} + {}) as *mut f64) = {};\n",
1555                    operands[1], offset, operands[0]
1556                ));
1557            }
1558
1559            Instruction::Malloc { .. } => unimplemented!(),
1560
1561            Instruction::GuestDeallocate { size, align } => {
1562                self.push_str(&format!(
1563                    "wit_bindgen::rt::dealloc({}, {}, {});\n",
1564                    operands[0], size, align
1565                ));
1566            }
1567
1568            Instruction::GuestDeallocateString => {
1569                self.push_str(&format!(
1570                    "wit_bindgen::rt::dealloc({}, ({}) as usize, 1);\n",
1571                    operands[0], operands[1],
1572                ));
1573            }
1574
1575            Instruction::GuestDeallocateVariant { blocks } => {
1576                let max = blocks - 1;
1577                let blocks = self
1578                    .blocks
1579                    .drain(self.blocks.len() - blocks..)
1580                    .collect::<Vec<_>>();
1581                let op0 = &operands[0];
1582                self.src.push_str(&format!("match {op0} {{\n"));
1583                for (i, block) in blocks.into_iter().enumerate() {
1584                    let pat = if i == max {
1585                        String::from("_")
1586                    } else {
1587                        i.to_string()
1588                    };
1589                    self.src.push_str(&format!("{pat} => {block},\n"));
1590                }
1591                self.src.push_str("}\n");
1592            }
1593
1594            Instruction::GuestDeallocateList { element } => {
1595                let body = self.blocks.pop().unwrap();
1596                let tmp = self.tmp();
1597                let size = self.gen.sizes.size(element);
1598                let align = self.gen.sizes.align(element);
1599                let len = format!("len{tmp}");
1600                let base = format!("base{tmp}");
1601                self.push_str(&format!(
1602                    "let {base} = {operand0};\n",
1603                    operand0 = operands[0]
1604                ));
1605                self.push_str(&format!(
1606                    "let {len} = {operand1};\n",
1607                    operand1 = operands[1]
1608                ));
1609
1610                if body != "()" {
1611                    self.push_str("for i in 0..");
1612                    self.push_str(&len);
1613                    self.push_str(" {\n");
1614                    self.push_str("let base = ");
1615                    self.push_str(&base);
1616                    self.push_str(" + i *");
1617                    self.push_str(&size.to_string());
1618                    self.push_str(";\n");
1619                    self.push_str(&body);
1620                    self.push_str("\n}\n");
1621                }
1622                self.push_str(&format!(
1623                    "wit_bindgen::rt::dealloc({base}, ({len} as usize) * {size}, {align});\n",
1624                ));
1625            }
1626        }
1627    }
1628}