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