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 #[cfg_attr(feature = "structopt", structopt(long))]
34 pub rustfmt: bool,
35
36 #[cfg_attr(feature = "structopt", structopt(long))]
38 pub multi_module: bool,
39
40 #[cfg_attr(feature = "structopt", structopt(long))]
43 pub unchecked: bool,
44
45 #[cfg_attr(feature = "structopt", structopt(skip))]
48 pub symbol_namespace: String,
49
50 #[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 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 TypeMode::AllBorrowed("'a")
93 } else {
94 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 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 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 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 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 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 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 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 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 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 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 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 self.cleanup.push((result, layout));
1247 }
1248 }
1249
1250 Instruction::ListLift { element, free, .. } => {
1251 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 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 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 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 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 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 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}