cosmian_wit_bindgen_gen_rust_wasm/
lib.rs

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