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