1use anyhow::bail;
2use heck::{ToPascalCase, ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase};
3use std::{
4 collections::{HashMap, HashSet},
5 fmt::{self, Display, Write as FmtWrite},
6 io::{Read, Write},
7 path::PathBuf,
8 process::{Command, Stdio},
9 str::FromStr,
10};
11use symbol_name::{make_external_component, make_external_symbol};
12use wit_bindgen_c::to_c_ident;
13use wit_bindgen_core::{
14 abi::{self, AbiVariant, Bindgen, Bitcast, LiftLower, WasmSignature, WasmType},
15 uwrite, uwriteln,
16 wit_parser::{
17 Alignment, ArchitectureSize, Docs, Function, FunctionKind, Handle, Int, InterfaceId,
18 Resolve, SizeAlign, Stability, Type, TypeDef, TypeDefKind, TypeId, TypeOwner, WorldId,
19 WorldKey,
20 },
21 Files, InterfaceGenerator, Source, Types, WorldGenerator,
22};
23
24mod symbol_name;
26
27pub const RESOURCE_IMPORT_BASE_CLASS_NAME: &str = "ResourceImportBase";
28pub const RESOURCE_EXPORT_BASE_CLASS_NAME: &str = "ResourceExportBase";
29pub const RESOURCE_TABLE_NAME: &str = "ResourceTable";
30pub const OWNED_CLASS_NAME: &str = "Owned";
31pub const POINTER_SIZE_EXPRESSION: &str = "sizeof(void*)";
32
33type CppType = String;
34
35#[derive(Clone, Copy, Debug)]
36enum Flavor {
37 Argument(AbiVariant),
38 Result(AbiVariant),
39 InStruct,
40 BorrowedArgument,
41}
42
43#[derive(Default)]
44struct HighlevelSignature {
45 const_member: bool,
48 static_member: bool,
49 result: CppType,
50 arguments: Vec<(String, CppType)>,
51 name: String,
52 namespace: Vec<String>,
53 implicit_self: bool,
54 post_return: bool,
55}
56
57#[derive(Default)]
60struct Includes {
61 needs_vector: bool,
62 needs_expected: bool,
63 needs_string: bool,
64 needs_string_view: bool,
65 needs_optional: bool,
66 needs_cstring: bool,
67 needs_imported_resources: bool,
68 needs_exported_resources: bool,
69 needs_variant: bool,
70 needs_tuple: bool,
71 needs_assert: bool,
72 needs_bit: bool,
73 needs_span: bool,
74 needs_wit: bool,
76 needs_memory: bool,
77}
78
79#[derive(Default)]
80struct SourceWithState {
81 src: Source,
82 namespace: Vec<String>,
83}
84
85#[derive(Eq, Hash, PartialEq, Clone, Copy, Debug)]
86enum Direction {
87 Import,
88 Export,
89}
90
91#[derive(Default)]
92struct Cpp {
93 opts: Opts,
94 c_src: SourceWithState,
95 h_src: SourceWithState,
96 c_src_head: Source,
97 extern_c_decls: Source,
98 dependencies: Includes,
99 includes: Vec<String>,
100 world: String,
101 world_id: Option<WorldId>,
102 imported_interfaces: HashSet<InterfaceId>,
103 user_class_files: HashMap<String, String>,
104 defined_types: HashSet<(Vec<String>, String)>,
105 types: Types,
106
107 interface_prefixes: HashMap<(Direction, WorldKey), String>,
109 import_prefix: Option<String>,
110}
111
112#[derive(Default, Debug, Clone)]
113#[cfg_attr(feature = "clap", derive(clap::Args))]
114pub struct Opts {
115 #[cfg_attr(feature = "clap", arg(long, default_value_t = bool::default()))]
117 pub format: bool,
118
119 #[cfg_attr(feature = "clap", arg(long, default_value_t = bool::default()))]
122 pub split_interfaces: bool,
123
124 #[cfg_attr(feature = "clap", arg(long))]
128 pub export_prefix: Option<String>,
129
130 #[cfg_attr(feature = "clap", arg(long))]
134 pub internal_prefix: Option<String>,
135
136 #[cfg_attr(
138 feature = "clap",
139 arg(
140 long,
141 default_value_t = APIStyle::default(),
142 value_name = "STYLE",
143 ),
144 )]
145 pub api_style: APIStyle,
146
147 #[cfg_attr(feature = "clap", arg(long, default_value_t = Ownership::Owning))]
163 pub ownership: Ownership,
164
165 #[cfg_attr(feature = "clap", arg(skip))]
167 out_dir: Option<PathBuf>,
168}
169
170#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
172pub enum APIStyle {
173 #[default]
175 Asymmetric,
176 Symmetric,
178}
179
180impl Display for APIStyle {
181 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
182 match self {
183 APIStyle::Asymmetric => write!(f, "asymmetric"),
184 APIStyle::Symmetric => write!(f, "symmetric"),
185 }
186 }
187}
188
189impl FromStr for APIStyle {
190 type Err = anyhow::Error;
191
192 fn from_str(s: &str) -> Result<Self, Self::Err> {
193 match s {
194 "asymmetric" => Ok(APIStyle::Asymmetric),
195 "symmetric" => Ok(APIStyle::Symmetric),
196 _ => bail!(
197 "unrecognized API style: `{}`; expected `asymmetric` or `symmetric`",
198 s
199 ),
200 }
201 }
202}
203
204#[derive(Default, Debug, Clone, Copy)]
205pub enum Ownership {
206 #[default]
209 Owning,
210
211 CoarseBorrowing,
215
216 FineBorrowing,
220}
221
222impl FromStr for Ownership {
223 type Err = String;
224
225 fn from_str(s: &str) -> Result<Self, Self::Err> {
226 match s {
227 "owning" => Ok(Self::Owning),
228 "coarse-borrowing" => Ok(Self::CoarseBorrowing),
229 "fine-borrowing" => Ok(Self::FineBorrowing),
230 _ => Err(format!(
231 "unrecognized ownership: `{s}`; \
232 expected `owning`, `coarse-borrowing`, or `fine-borrowing`"
233 )),
234 }
235 }
236}
237
238impl fmt::Display for Ownership {
239 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
240 f.write_str(match self {
241 Ownership::Owning => "owning",
242 Ownership::CoarseBorrowing => "coarse-borrowing",
243 Ownership::FineBorrowing => "fine-borrowing",
244 })
245 }
246}
247
248impl Opts {
249 pub fn build(mut self, out_dir: Option<&PathBuf>) -> Box<dyn WorldGenerator> {
250 let mut r = Cpp::new();
251 self.out_dir = out_dir.cloned();
252 r.opts = self;
253 Box::new(r)
254 }
255
256 fn is_only_handle(&self, variant: AbiVariant) -> bool {
257 !matches!(variant, AbiVariant::GuestExport)
258 }
259
260 fn ptr_type(&self) -> &'static str {
261 "uint8_t*"
262 }
263}
264
265impl Cpp {
266 fn new() -> Cpp {
267 Cpp::default()
268 }
269
270 pub fn is_first_definition(&mut self, ns: &Vec<String>, name: &str) -> bool {
271 let owned = (ns.to_owned(), name.to_owned());
272 if !self.defined_types.contains(&owned) {
273 self.defined_types.insert(owned);
274 true
275 } else {
276 false
277 }
278 }
279
280 fn include(&mut self, s: &str) {
281 self.includes.push(s.to_string());
282 }
283
284 fn interface<'a>(
285 &'a mut self,
286 resolve: &'a Resolve,
287 name: Option<&'a WorldKey>,
288 in_guest_import: bool,
289 wasm_import_module: Option<String>,
290 ) -> CppInterfaceGenerator<'a> {
291 let mut sizes = SizeAlign::default();
292 sizes.fill(resolve);
293
294 CppInterfaceGenerator {
295 _src: Source::default(),
296 gen: self,
297 resolve,
298 interface: None,
299 _name: name,
300 sizes,
301 in_guest_import,
302 wasm_import_module,
303 }
304 }
305
306 fn clang_format(code: &mut String) {
307 let mut child = Command::new("clang-format")
308 .stdin(Stdio::piped())
309 .stdout(Stdio::piped())
310 .spawn()
311 .expect("failed to spawn `clang-format`");
312 child
313 .stdin
314 .take()
315 .unwrap()
316 .write_all(code.as_bytes())
317 .unwrap();
318 code.truncate(0);
319 child.stdout.take().unwrap().read_to_string(code).unwrap();
320 let status = child.wait().unwrap();
321 assert!(status.success());
322 }
323
324 fn perform_cast(&mut self, op: &str, cast: &Bitcast) -> String {
325 match cast {
326 Bitcast::I32ToF32 | Bitcast::I64ToF32 => {
327 self.dependencies.needs_bit = true;
328 format!("std::bit_cast<float, int32_t>({})", op)
329 }
330 Bitcast::F32ToI32 | Bitcast::F32ToI64 => {
331 self.dependencies.needs_bit = true;
332 format!("std::bit_cast<int32_t, float>({})", op)
333 }
334 Bitcast::I64ToF64 => {
335 self.dependencies.needs_bit = true;
336 format!("std::bit_cast<double, int64_t>({})", op)
337 }
338 Bitcast::F64ToI64 => {
339 self.dependencies.needs_bit = true;
340 format!("std::bit_cast<int64_t, double>({})", op)
341 }
342 Bitcast::I32ToI64 | Bitcast::LToI64 | Bitcast::PToP64 => {
343 format!("(int64_t) {}", op)
344 }
345 Bitcast::I64ToI32 | Bitcast::PToI32 | Bitcast::LToI32 => {
346 format!("(int32_t) {}", op)
347 }
348 Bitcast::P64ToI64 | Bitcast::None | Bitcast::I64ToP64 => op.to_string(),
349 Bitcast::P64ToP | Bitcast::I32ToP | Bitcast::LToP => {
350 format!("(uint8_t*) {}", op)
351 }
352 Bitcast::PToL | Bitcast::I32ToL | Bitcast::I64ToL => {
353 format!("(size_t) {}", op)
354 }
355 Bitcast::Sequence(sequence) => {
356 let [first, second] = &**sequence;
357 let inner = self.perform_cast(op, first);
358 self.perform_cast(&inner, second)
359 }
360 }
361 }
362
363 fn finish_includes(&mut self) {
364 self.include("<cstdint>");
365 self.include("<utility>"); if self.dependencies.needs_string {
367 self.include("<string>");
368 }
369 if self.dependencies.needs_string_view {
370 self.include("<string_view>");
371 }
372 if self.dependencies.needs_vector {
373 self.include("<vector>");
374 }
375 if self.dependencies.needs_expected {
376 self.include("<expected>");
377 }
378 if self.dependencies.needs_optional {
379 self.include("<optional>");
380 }
381 if self.dependencies.needs_cstring {
382 self.include("<cstring>");
383 }
384 if self.dependencies.needs_imported_resources {
385 self.include("<cassert>");
386 }
387 if self.dependencies.needs_exported_resources {
388 self.include("<map>");
389 }
390 if self.dependencies.needs_variant {
391 self.include("<variant>");
392 }
393 if self.dependencies.needs_tuple {
394 self.include("<tuple>");
395 }
396 if self.dependencies.needs_wit {
397 self.include("\"wit.h\"");
398 }
399 if self.dependencies.needs_memory {
400 self.include("<memory>");
401 }
402 if self.dependencies.needs_bit {
403 self.include("<bit>");
404 }
405 }
406
407 fn start_new_file(&mut self, condition: Option<bool>) -> FileContext {
408 if condition == Some(true) || self.opts.split_interfaces {
409 FileContext {
410 includes: std::mem::take(&mut self.includes),
411 src: std::mem::take(&mut self.h_src),
412 dependencies: std::mem::take(&mut self.dependencies),
413 }
414 } else {
415 Default::default()
416 }
417 }
418
419 fn finish_file(&mut self, namespace: &[String], store: FileContext) {
420 if !store.src.src.is_empty() {
421 let mut header = String::default();
422 self.finish_includes();
423 self.h_src.change_namespace(&[]);
424 uwriteln!(header, "#pragma once");
425 for include in self.includes.iter() {
426 uwriteln!(header, "#include {include}");
427 }
428 header.push_str(&self.h_src.src);
429 let mut filename = namespace.join("-");
430 filename.push_str(".h");
431 if self.opts.format {
432 Self::clang_format(&mut header);
433 }
434 self.user_class_files.insert(filename.clone(), header);
435
436 let _ = std::mem::replace(&mut self.includes, store.includes);
437 let _ = std::mem::replace(&mut self.h_src, store.src);
438 let _ = std::mem::replace(&mut self.dependencies, store.dependencies);
439 self.includes.push(String::from("\"") + &filename + "\"");
440 }
441 }
442}
443
444#[derive(Default)]
445struct FileContext {
446 includes: Vec<String>,
447 src: SourceWithState,
448 dependencies: Includes,
449}
450
451impl WorldGenerator for Cpp {
452 fn preprocess(&mut self, resolve: &Resolve, world: WorldId) {
453 let name = &resolve.worlds[world].name;
454 self.world = name.to_string();
455 self.types.analyze(resolve);
456 self.world_id = Some(world);
457 uwriteln!(
458 self.c_src_head,
459 r#"#include "{}_cpp.h"
460 #include <cstdlib> // realloc
461
462 extern "C" void *cabi_realloc(void *ptr, size_t old_size, size_t align, size_t new_size);
463
464 __attribute__((__weak__, __export_name__("cabi_realloc")))
465 void *cabi_realloc(void *ptr, size_t old_size, size_t align, size_t new_size) {{
466 (void) old_size;
467 if (new_size == 0) return (void*) align;
468 void *ret = realloc(ptr, new_size);
469 if (!ret) abort();
470 return ret;
471 }}
472
473 "#,
474 self.world.to_snake_case(),
475 );
476 }
477
478 fn import_interface(
479 &mut self,
480 resolve: &Resolve,
481 name: &WorldKey,
482 id: InterfaceId,
483 _files: &mut Files,
484 ) -> anyhow::Result<()> {
485 if let Some(prefix) = self
486 .interface_prefixes
487 .get(&(Direction::Import, name.clone()))
488 {
489 self.import_prefix = Some(prefix.clone());
490 }
491
492 let store = self.start_new_file(None);
493 self.imported_interfaces.insert(id);
494 let wasm_import_module = resolve.name_world_key(name);
495 let binding = Some(name);
496 let mut gen = self.interface(resolve, binding, true, Some(wasm_import_module));
497 gen.interface = Some(id);
498 gen.types(id);
499 let namespace = namespace(resolve, &TypeOwner::Interface(id), false, &gen.gen.opts);
500
501 for (_name, func) in resolve.interfaces[id].functions.iter() {
502 if matches!(func.kind, FunctionKind::Freestanding) {
503 gen.gen.h_src.change_namespace(&namespace);
504 gen.generate_function(func, &TypeOwner::Interface(id), AbiVariant::GuestImport);
505 }
506 }
507 self.finish_file(&namespace, store);
508 let _ = self.import_prefix.take();
509 Ok(())
510 }
511
512 fn export_interface(
513 &mut self,
514 resolve: &Resolve,
515 name: &WorldKey,
516 id: InterfaceId,
517 _files: &mut Files,
518 ) -> anyhow::Result<()> {
519 let old_prefix = self.opts.export_prefix.clone();
520 if let Some(prefix) = self
521 .interface_prefixes
522 .get(&(Direction::Export, name.clone()))
523 {
524 self.opts.export_prefix =
525 Some(prefix.clone() + old_prefix.as_ref().unwrap_or(&String::new()));
526 }
527 let store = self.start_new_file(None);
528 self.h_src
529 .src
530 .push_str(&format!("// export_interface {name:?}\n"));
531 self.imported_interfaces.remove(&id);
532 let wasm_import_module = resolve.name_world_key(name);
533 let binding = Some(name);
534 let mut gen = self.interface(resolve, binding, false, Some(wasm_import_module));
535 gen.interface = Some(id);
536 gen.types(id);
537 let namespace = namespace(resolve, &TypeOwner::Interface(id), true, &gen.gen.opts);
538
539 for (_name, func) in resolve.interfaces[id].functions.iter() {
540 if matches!(func.kind, FunctionKind::Freestanding) {
541 gen.gen.h_src.change_namespace(&namespace);
542 gen.generate_function(func, &TypeOwner::Interface(id), AbiVariant::GuestExport);
543 }
544 }
545 self.finish_file(&namespace, store);
546 self.opts.export_prefix = old_prefix;
547 Ok(())
548 }
549
550 fn import_funcs(
551 &mut self,
552 resolve: &Resolve,
553 world: WorldId,
554 funcs: &[(&str, &Function)],
555 _files: &mut Files,
556 ) {
557 let name = WorldKey::Name("$root".to_string()); let wasm_import_module = resolve.name_world_key(&name);
559 let binding = Some(name);
560 let mut gen = self.interface(resolve, binding.as_ref(), true, Some(wasm_import_module));
561 let namespace = namespace(resolve, &TypeOwner::World(world), false, &gen.gen.opts);
562
563 for (_name, func) in funcs.iter() {
564 if matches!(func.kind, FunctionKind::Freestanding) {
565 gen.gen.h_src.change_namespace(&namespace);
566 gen.generate_function(func, &TypeOwner::World(world), AbiVariant::GuestImport);
567 }
568 }
569 }
570
571 fn export_funcs(
572 &mut self,
573 resolve: &Resolve,
574 world: WorldId,
575 funcs: &[(&str, &Function)],
576 _files: &mut Files,
577 ) -> anyhow::Result<()> {
578 let name = WorldKey::Name(resolve.worlds[world].name.clone());
579 let binding = Some(name);
580 let mut gen = self.interface(resolve, binding.as_ref(), false, None);
581 let namespace = namespace(resolve, &TypeOwner::World(world), true, &gen.gen.opts);
582
583 for (_name, func) in funcs.iter() {
584 if matches!(func.kind, FunctionKind::Freestanding) {
585 gen.gen.h_src.change_namespace(&namespace);
586 gen.generate_function(func, &TypeOwner::World(world), AbiVariant::GuestExport);
587 }
588 }
589 Ok(())
590 }
591
592 fn import_types(
593 &mut self,
594 _resolve: &Resolve,
595 _world: WorldId,
596 types: &[(&str, TypeId)],
597 _files: &mut Files,
598 ) {
599 for i in types.iter() {
600 uwriteln!(self.h_src.src, "// import_type {}", i.0);
601 }
602 }
603
604 fn finish(
605 &mut self,
606 resolve: &Resolve,
607 world_id: WorldId,
608 files: &mut Files,
609 ) -> std::result::Result<(), anyhow::Error> {
610 let world = &resolve.worlds[world_id];
611 let snake = world.name.to_snake_case();
612 let linking_symbol = wit_bindgen_c::component_type_object::linking_symbol(&world.name);
613
614 let mut h_str = SourceWithState::default();
615 let mut c_str = SourceWithState::default();
616
617 let version = env!("CARGO_PKG_VERSION");
618 uwriteln!(
619 h_str.src,
620 "// Generated by `wit-bindgen` {version}. DO NOT EDIT!"
621 );
622
623 uwrite!(
624 h_str.src,
625 "#ifndef __CPP_GUEST_BINDINGS_{0}_H
626 #define __CPP_GUEST_BINDINGS_{0}_H\n",
627 world.name.to_shouty_snake_case(),
628 );
629 self.finish_includes();
630
631 for include in self.includes.iter() {
632 uwriteln!(h_str.src, "#include {include}");
633 }
634
635 uwriteln!(
636 c_str.src,
637 "// Generated by `wit-bindgen` {version}. DO NOT EDIT!"
638 );
639 uwriteln!(
640 c_str.src,
641 "\n// Ensure that the *_component_type.o object is linked in"
642 );
643 uwrite!(
644 c_str.src,
645 "#ifdef __wasm32__
646 extern \"C\" void {linking_symbol}(void);
647 __attribute__((used))
648 void {linking_symbol}_public_use_in_this_compilation_unit(void) {{
649 {linking_symbol}();
650 }}
651 #endif
652 ",
653 );
654 if self.dependencies.needs_assert {
655 uwriteln!(c_str.src, "#include <assert.h>");
656 }
657
658 h_str.change_namespace(&Vec::default());
659
660 self.c_src.change_namespace(&Vec::default());
661 c_str.src.push_str(&self.c_src_head);
662 c_str.src.push_str(&self.extern_c_decls);
663 c_str.src.push_str(&self.c_src.src);
664 self.h_src.change_namespace(&Vec::default());
665 h_str.src.push_str(&self.h_src.src);
666
667 uwriteln!(c_str.src, "\n// Component Adapters");
668
669 uwriteln!(
670 h_str.src,
671 "
672 #endif"
673 );
674
675 if self.opts.format {
676 Self::clang_format(c_str.src.as_mut_string());
677 Self::clang_format(h_str.src.as_mut_string());
678 }
679
680 files.push(&format!("{snake}.cpp"), c_str.src.as_bytes());
681 files.push(&format!("{snake}_cpp.h"), h_str.src.as_bytes());
682 for (name, content) in self.user_class_files.iter() {
683 let dst = match &self.opts.out_dir {
685 Some(path) => path.join(name),
686 None => name.into(),
687 };
688 if std::path::Path::exists(&dst) {
689 files.push(&(String::from(name) + ".template"), content.as_bytes());
690 } else {
691 files.push(name, content.as_bytes());
692 }
693 }
694 files.push(
695 &format!("{snake}_component_type.o",),
696 wit_bindgen_c::component_type_object::object(
697 resolve,
698 world_id,
699 &world.name,
700 wit_component::StringEncoding::UTF8,
701 None,
702 )
703 .unwrap()
704 .as_slice(),
705 );
706
707 if self.dependencies.needs_wit {
708 files.push(&format!("wit.h"), include_bytes!("../helper-types/wit.h"));
709 }
710 Ok(())
711 }
712}
713
714fn namespace(resolve: &Resolve, owner: &TypeOwner, guest_export: bool, opts: &Opts) -> Vec<String> {
716 let mut result = Vec::default();
717 if let Some(prefix) = &opts.internal_prefix {
718 result.push(prefix.clone());
719 }
720 if guest_export {
721 result.push(String::from("exports"));
722 }
723 match owner {
724 TypeOwner::World(w) => result.push(resolve.worlds[*w].name.to_snake_case()),
725 TypeOwner::Interface(i) => {
726 let iface = &resolve.interfaces[*i];
727 let pkg = &resolve.packages[iface.package.unwrap()];
728 result.push(pkg.name.namespace.to_snake_case());
729 result.push(pkg.name.name.to_snake_case());
730 if let Some(name) = &iface.name {
731 result.push(name.to_snake_case());
732 }
733 }
734 TypeOwner::None => (),
735 }
736 result
737}
738
739impl SourceWithState {
740 fn change_namespace(&mut self, target: &[String]) {
741 let mut same = 0;
742 for (a, b) in self.namespace.iter().zip(target.iter()) {
744 if a == b {
745 same += 1;
746 } else {
747 break;
748 }
749 }
750 for _i in same..self.namespace.len() {
751 uwrite!(self.src, "}}\n");
752 }
753 self.namespace.truncate(same);
754 for i in target.iter().skip(same) {
755 uwrite!(self.src, "namespace {} {{\n", i);
756 self.namespace.push(i.clone());
757 }
758 }
759
760 fn qualify(&mut self, target: &[String]) {
761 let mut same = 0;
762 for (a, b) in self.namespace.iter().zip(target.iter()) {
764 if a == b {
765 same += 1;
766 } else {
767 break;
768 }
769 }
770 if same == 0 && !target.is_empty() {
771 if self.namespace.contains(target.first().unwrap()) {
773 self.src.push_str("::");
774 }
775 }
776 if same == target.len() && self.namespace.len() != target.len() && same > 0 {
777 uwrite!(self.src, "{}::", target[same - 1]);
779 } else {
780 for i in target.iter().skip(same) {
781 uwrite!(self.src, "{i}::");
782 }
783 }
784 }
785}
786
787struct CppInterfaceGenerator<'a> {
788 _src: Source,
789 gen: &'a mut Cpp,
790 resolve: &'a Resolve,
791 interface: Option<InterfaceId>,
792 _name: Option<&'a WorldKey>,
793 sizes: SizeAlign,
794 in_guest_import: bool,
795 pub wasm_import_module: Option<String>,
796}
797
798impl CppInterfaceGenerator<'_> {
799 fn types(&mut self, iface: InterfaceId) {
800 let iface = &self.resolve().interfaces[iface];
801 for (name, id) in iface.types.iter() {
802 self.define_type(name, *id);
803 }
804 }
805
806 fn define_type(&mut self, name: &str, id: TypeId) {
807 let ty = &self.resolve().types[id];
808 match &ty.kind {
809 TypeDefKind::Record(record) => self.type_record(id, name, record, &ty.docs),
810 TypeDefKind::Resource => self.type_resource(id, name, &ty.docs),
811 TypeDefKind::Flags(flags) => self.type_flags(id, name, flags, &ty.docs),
812 TypeDefKind::Tuple(tuple) => self.type_tuple(id, name, tuple, &ty.docs),
813 TypeDefKind::Enum(enum_) => self.type_enum(id, name, enum_, &ty.docs),
814 TypeDefKind::Variant(variant) => self.type_variant(id, name, variant, &ty.docs),
815 TypeDefKind::Option(t) => self.type_option(id, name, t, &ty.docs),
816 TypeDefKind::Result(r) => self.type_result(id, name, r, &ty.docs),
817 TypeDefKind::List(t) => self.type_list(id, name, t, &ty.docs),
818 TypeDefKind::Type(t) => self.type_alias(id, name, t, &ty.docs),
819 TypeDefKind::Future(_) => todo!("generate for future"),
820 TypeDefKind::Stream(_) => todo!("generate for stream"),
821 TypeDefKind::Handle(_) => todo!("generate for handle"),
822 TypeDefKind::FixedSizeList(_, _) => todo!(),
823 TypeDefKind::Unknown => unreachable!(),
824 }
825 }
826
827 fn func_namespace_name(
829 &self,
830 func: &Function,
831 guest_export: bool,
832 cpp_file: bool,
833 ) -> (Vec<String>, String) {
834 let (object, owner) = match &func.kind {
835 FunctionKind::Freestanding => None,
836 FunctionKind::Method(i) => Some(i),
837 FunctionKind::Static(i) => Some(i),
838 FunctionKind::Constructor(i) => Some(i),
839 FunctionKind::AsyncFreestanding => todo!(),
840 FunctionKind::AsyncMethod(_id) => todo!(),
841 FunctionKind::AsyncStatic(_id) => todo!(),
842 }
843 .map(|i| {
844 let ty = &self.resolve.types[*i];
845 (ty.name.as_ref().unwrap().to_pascal_case(), ty.owner)
846 })
847 .unwrap_or((
848 Default::default(),
849 self.interface
850 .map(TypeOwner::Interface)
851 .unwrap_or(TypeOwner::World(self.gen.world_id.unwrap())),
852 ));
853 let mut namespace = namespace(self.resolve, &owner, guest_export, &self.gen.opts);
854 let is_drop = is_special_method(func);
855 let func_name_h = if !matches!(&func.kind, FunctionKind::Freestanding) {
856 namespace.push(object.clone());
857 if let FunctionKind::Constructor(_i) = &func.kind {
858 if guest_export && cpp_file {
859 String::from("New")
860 } else {
861 object.clone()
862 }
863 } else {
864 match is_drop {
865 SpecialMethod::ResourceDrop => {
866 if guest_export {
867 "ResourceDrop".to_string()
868 } else {
869 "~".to_string() + &object
870 }
871 }
872 SpecialMethod::Dtor => "Dtor".to_string(),
873 SpecialMethod::ResourceNew => "ResourceNew".to_string(),
874 SpecialMethod::ResourceRep => "ResourceRep".to_string(),
875 SpecialMethod::Allocate => "New".to_string(),
876 SpecialMethod::None => func.item_name().to_pascal_case(),
877 }
878 }
879 } else {
880 func.name.to_pascal_case()
881 };
882 (namespace, func_name_h)
883 }
884
885 fn print_export_signature(&mut self, func: &Function, variant: AbiVariant) -> Vec<String> {
887 let is_drop = is_special_method(func);
888 let id_type = WasmType::I32;
889 let signature = match is_drop {
890 SpecialMethod::ResourceDrop => WasmSignature {
891 params: vec![id_type],
892 results: Vec::new(),
893 indirect_params: false,
894 retptr: false,
895 },
896 SpecialMethod::ResourceRep => WasmSignature {
897 params: vec![id_type],
898 results: vec![WasmType::Pointer],
899 indirect_params: false,
900 retptr: false,
901 },
902 SpecialMethod::Dtor => WasmSignature {
903 params: vec![WasmType::Pointer],
904 results: Vec::new(),
905 indirect_params: false,
906 retptr: false,
907 },
908 SpecialMethod::ResourceNew => WasmSignature {
909 params: vec![WasmType::Pointer],
910 results: vec![id_type],
911 indirect_params: false,
912 retptr: false,
913 },
914 SpecialMethod::None => {
915 self.resolve.wasm_signature(variant, func)
917 }
918 SpecialMethod::Allocate => WasmSignature {
919 params: vec![],
920 results: vec![],
921 indirect_params: false,
922 retptr: false,
923 },
924 };
925 let mut module_name = self.wasm_import_module.clone();
926 let symbol_variant = variant;
927 if matches!(variant, AbiVariant::GuestExport)
928 && matches!(
929 is_drop,
930 SpecialMethod::ResourceNew
931 | SpecialMethod::ResourceDrop
932 | SpecialMethod::ResourceRep
933 )
934 {
935 module_name = Some(String::from("[export]") + &module_name.unwrap());
936 }
937 let func_name = func.name.clone();
938 let module_prefix = module_name.as_ref().map_or(String::default(), |name| {
939 let mut res = name.clone();
940 res.push('#');
941 res
942 });
943 uwriteln!(
944 self.gen.c_src.src,
945 r#"extern "C" __attribute__((__export_name__("{module_prefix}{func_name}")))"#
946 );
947 let return_via_pointer = false;
948 self.gen
949 .c_src
950 .src
951 .push_str(if signature.results.is_empty() || return_via_pointer {
952 "void"
953 } else {
954 wit_bindgen_c::wasm_type(signature.results[0])
955 });
956 self.gen.c_src.src.push_str(" ");
957 let export_name = match module_name {
958 Some(ref module_name) => make_external_symbol(module_name, &func_name, symbol_variant),
959 None => make_external_component(&func_name),
960 };
961 if let Some(prefix) = self.gen.opts.export_prefix.as_ref() {
962 self.gen.c_src.src.push_str(prefix);
963 }
964 self.gen.c_src.src.push_str(&export_name);
965 self.gen.c_src.src.push_str("(");
966 let mut first_arg = true;
967 let mut params = Vec::new();
968 for (n, ty) in signature.params.iter().enumerate() {
969 let name = format!("arg{n}");
970 if !first_arg {
971 self.gen.c_src.src.push_str(", ");
972 } else {
973 first_arg = false;
974 }
975 self.gen.c_src.src.push_str(wit_bindgen_c::wasm_type(*ty));
976 self.gen.c_src.src.push_str(" ");
977 self.gen.c_src.src.push_str(&name);
978 params.push(name);
979 }
980 if return_via_pointer {
981 if !first_arg {
982 self.gen.c_src.src.push_str(", ");
983 }
984 self.gen.c_src.src.push_str(self.gen.opts.ptr_type());
985 self.gen.c_src.src.push_str(" resultptr");
986 params.push("resultptr".into());
987 }
988 self.gen.c_src.src.push_str(")\n");
989 params
990 }
991
992 fn high_level_signature(
993 &mut self,
994 func: &Function,
995 abi_variant: AbiVariant,
996 outer_namespace: &[String],
997 ) -> HighlevelSignature {
998 let mut res = HighlevelSignature::default();
999
1000 let (namespace, func_name_h) =
1001 self.func_namespace_name(func, matches!(abi_variant, AbiVariant::GuestExport), false);
1002 res.name = func_name_h;
1003 res.namespace = namespace;
1004 let is_drop = is_special_method(func);
1005 if !matches!(&func.kind, FunctionKind::Constructor(_))
1009 && !(matches!(is_drop, SpecialMethod::ResourceDrop)
1010 && matches!(abi_variant, AbiVariant::GuestImport))
1011 {
1012 if matches!(is_drop, SpecialMethod::Allocate) {
1013 res.result.push_str("Owned");
1014 } else if let Some(ty) = &func.result {
1015 res.result.push_str(
1016 &(self.type_name(ty, outer_namespace, Flavor::Result(abi_variant))
1017 + if matches!(is_drop, SpecialMethod::ResourceRep) {
1018 "*"
1019 } else {
1020 ""
1021 }),
1022 );
1023 } else {
1024 res.result = "void".into();
1025 }
1026 if matches!(abi_variant, AbiVariant::GuestExport)
1027 && abi::guest_export_needs_post_return(self.resolve, func)
1028 {
1029 res.post_return = true;
1030 }
1031 }
1032 if matches!(func.kind, FunctionKind::Static(_))
1033 && !(matches!(&is_drop, SpecialMethod::ResourceDrop)
1034 && matches!(abi_variant, AbiVariant::GuestImport))
1035 {
1036 res.static_member = true;
1037 }
1038 for (i, (name, param)) in func.params.iter().enumerate() {
1039 if i == 0
1040 && name == "self"
1041 && (matches!(&func.kind, FunctionKind::Method(_))
1042 || (matches!(&is_drop, SpecialMethod::ResourceDrop)
1043 && matches!(abi_variant, AbiVariant::GuestImport)))
1044 {
1045 res.implicit_self = true;
1046 continue;
1047 }
1048 let is_pointer = if i == 0
1049 && name == "self"
1050 && matches!(&is_drop, SpecialMethod::Dtor | SpecialMethod::ResourceNew)
1051 && matches!(abi_variant, AbiVariant::GuestExport)
1052 {
1053 "*"
1054 } else {
1055 ""
1056 };
1057 res.arguments.push((
1058 name.to_snake_case(),
1059 self.type_name(param, &res.namespace, Flavor::Argument(abi_variant)) + is_pointer,
1060 ));
1061 }
1062 let import = matches!(abi_variant, AbiVariant::GuestImport);
1064 if matches!(func.kind, FunctionKind::Method(_)) && import {
1065 res.const_member = true;
1066 }
1067 res
1068 }
1069
1070 fn print_signature(
1071 &mut self,
1072 func: &Function,
1073 variant: AbiVariant,
1074 import: bool,
1075 ) -> Vec<String> {
1076 let is_special = is_special_method(func);
1077 let from_namespace = self.gen.h_src.namespace.clone();
1078 let cpp_sig = self.high_level_signature(func, variant, &from_namespace);
1079 if cpp_sig.static_member {
1080 self.gen.h_src.src.push_str("static ");
1081 }
1082 self.gen.h_src.src.push_str(&cpp_sig.result);
1083 if !cpp_sig.result.is_empty() {
1084 self.gen.h_src.src.push_str(" ");
1085 }
1086 self.gen.h_src.src.push_str(&cpp_sig.name);
1087 self.gen.h_src.src.push_str("(");
1088 for (num, (arg, typ)) in cpp_sig.arguments.iter().enumerate() {
1089 if num > 0 {
1090 self.gen.h_src.src.push_str(", ");
1091 }
1092 self.gen.h_src.src.push_str(typ);
1093 self.gen.h_src.src.push_str(" ");
1094 self.gen.h_src.src.push_str(arg);
1095 }
1096 self.gen.h_src.src.push_str(")");
1097 if cpp_sig.const_member {
1098 self.gen.h_src.src.push_str(" const");
1099 }
1100 match (&is_special, false, &variant) {
1101 (SpecialMethod::Allocate, _, _) => {
1102 uwriteln!(
1103 self.gen.h_src.src,
1104 "{{\
1105 return {OWNED_CLASS_NAME}(new {}({}));\
1106 }}",
1107 cpp_sig.namespace.last().unwrap(), cpp_sig
1109 .arguments
1110 .iter()
1111 .map(|(arg, _)| format!("std::move({})", arg))
1112 .collect::<Vec<_>>()
1113 .join(", ")
1114 );
1115 return Vec::default();
1117 }
1118 (SpecialMethod::Dtor, _, _ )
1119 | (SpecialMethod::ResourceDrop, true, _) => {
1120 uwriteln!(
1121 self.gen.h_src.src,
1122 "{{\
1123 delete {};\
1124 }}",
1125 cpp_sig.arguments.first().unwrap().0
1126 );
1127 }
1128 _ => self.gen.h_src.src.push_str(";\n"),
1129 }
1130
1131 if !import
1133 && !matches!(
1134 &is_special,
1135 SpecialMethod::ResourceDrop
1136 | SpecialMethod::ResourceNew
1137 | SpecialMethod::ResourceRep
1138 )
1139 {
1140 self.print_export_signature(func, variant)
1141 } else {
1142 let c_namespace = self.gen.c_src.namespace.clone();
1144 let cpp_sig = self.high_level_signature(func, variant, &c_namespace);
1145 let mut params = Vec::new();
1146 self.gen.c_src.src.push_str(&cpp_sig.result);
1147 if !cpp_sig.result.is_empty() {
1148 self.gen.c_src.src.push_str(" ");
1149 }
1150 self.gen.c_src.qualify(&cpp_sig.namespace);
1151 self.gen.c_src.src.push_str(&cpp_sig.name);
1152 self.gen.c_src.src.push_str("(");
1153 if cpp_sig.implicit_self {
1154 params.push("(*this)".into());
1155 }
1156 for (num, (arg, typ)) in cpp_sig.arguments.iter().enumerate() {
1157 if num > 0 {
1158 self.gen.c_src.src.push_str(", ");
1159 }
1160 self.gen.c_src.src.push_str(typ);
1161 self.gen.c_src.src.push_str(" ");
1162 self.gen.c_src.src.push_str(arg);
1163 params.push(arg.clone());
1164 }
1165 self.gen.c_src.src.push_str(")");
1166 if cpp_sig.const_member {
1167 self.gen.c_src.src.push_str(" const");
1168 }
1169 self.gen.c_src.src.push_str("\n");
1170 params
1171 }
1172 }
1173
1174 fn generate_function(&mut self, func: &Function, owner: &TypeOwner, variant: AbiVariant) {
1175 fn class_namespace(
1176 cifg: &CppInterfaceGenerator,
1177 func: &Function,
1178 variant: AbiVariant,
1179 ) -> Vec<String> {
1180 let owner = &cifg.resolve.types[match &func.kind {
1181 FunctionKind::Static(id) => *id,
1182 _ => panic!("special func should be static"),
1183 }];
1184 let mut namespace = namespace(
1185 cifg.resolve,
1186 &owner.owner,
1187 matches!(variant, AbiVariant::GuestExport),
1188 &cifg.gen.opts,
1189 );
1190 namespace.push(owner.name.as_ref().unwrap().to_upper_camel_case());
1191 namespace
1192 }
1193
1194 let export = match variant {
1195 AbiVariant::GuestImport => false,
1196 AbiVariant::GuestExport => true,
1197 AbiVariant::GuestImportAsync => todo!(),
1198 AbiVariant::GuestExportAsync => todo!(),
1199 AbiVariant::GuestExportAsyncStackful => todo!(),
1200 };
1201 let params = self.print_signature(func, variant, !export);
1202 let special = is_special_method(func);
1203 if !matches!(special, SpecialMethod::Allocate) {
1204 self.gen.c_src.src.push_str("{\n");
1205 let needs_dealloc = if self.gen.opts.api_style == APIStyle::Symmetric
1206 && matches!(variant, AbiVariant::GuestExport)
1207 {
1208 self.gen
1209 .c_src
1210 .src
1211 .push_str("std::vector<void*> _deallocate;\n");
1212 self.gen.dependencies.needs_vector = true;
1213 true
1214 } else {
1215 false
1216 };
1217 let lift_lower = if export {
1218 LiftLower::LiftArgsLowerResults
1219 } else {
1220 LiftLower::LowerArgsLiftResults
1221 };
1222 match is_special_method(func) {
1223 SpecialMethod::ResourceDrop => match lift_lower {
1224 LiftLower::LiftArgsLowerResults => {
1225 let module_name =
1226 String::from("[export]") + &self.wasm_import_module.clone().unwrap();
1227 let wasm_sig =
1228 self.declare_import(&module_name, &func.name, &[WasmType::I32], &[]);
1229 uwriteln!(
1230 self.gen.c_src.src,
1231 "{wasm_sig}({});",
1232 func.params.first().unwrap().0
1233 );
1234 }
1235 LiftLower::LowerArgsLiftResults => {
1236 let module_name = self.wasm_import_module.clone().unwrap();
1237 let name =
1238 self.declare_import(&module_name, &func.name, &[WasmType::I32], &[]);
1239 uwriteln!(
1240 self.gen.c_src.src,
1241 " if (handle>=0) {{
1242 {name}(handle);
1243 }}"
1244 );
1245 }
1246 },
1247 SpecialMethod::Dtor => {
1248 let classname = class_namespace(self, func, variant).join("::");
1249 uwriteln!(self.gen.c_src.src, "(({classname}*)arg0)->handle=-1;");
1250 uwriteln!(self.gen.c_src.src, "{0}::Dtor(({0}*)arg0);", classname);
1251 }
1252 SpecialMethod::ResourceNew => {
1253 let module_name =
1254 String::from("[export]") + &self.wasm_import_module.clone().unwrap();
1255 let wasm_sig = self.declare_import(
1256 &module_name,
1257 &func.name,
1258 &[WasmType::Pointer],
1259 &[WasmType::I32],
1260 );
1261 uwriteln!(
1262 self.gen.c_src.src,
1263 "return {wasm_sig}(({}){});",
1264 self.gen.opts.ptr_type(),
1265 func.params.first().unwrap().0
1266 );
1267 }
1268 SpecialMethod::ResourceRep => {
1269 let module_name =
1270 String::from("[export]") + &self.wasm_import_module.clone().unwrap();
1271 let wasm_sig = self.declare_import(
1272 &module_name,
1273 &func.name,
1274 &[WasmType::I32],
1275 &[WasmType::Pointer],
1276 );
1277 let classname = class_namespace(self, func, variant).join("::");
1278 uwriteln!(
1279 self.gen.c_src.src,
1280 "return ({}*){wasm_sig}({});",
1281 classname,
1282 func.params.first().unwrap().0
1283 );
1284 }
1285 SpecialMethod::Allocate => unreachable!(),
1286 SpecialMethod::None => {
1287 let namespace = if matches!(func.kind, FunctionKind::Freestanding) {
1289 namespace(
1290 self.resolve,
1291 owner,
1292 matches!(variant, AbiVariant::GuestExport),
1293 &self.gen.opts,
1294 )
1295 } else {
1296 let owner = &self.resolve.types[match &func.kind {
1297 FunctionKind::Static(id) => *id,
1298 FunctionKind::Constructor(id) => *id,
1299 FunctionKind::Method(id) => *id,
1300 FunctionKind::Freestanding => unreachable!(),
1301 FunctionKind::AsyncFreestanding => todo!(),
1302 FunctionKind::AsyncMethod(_id) => todo!(),
1303 FunctionKind::AsyncStatic(_id) => todo!(),
1304 }]
1305 .clone();
1306 let mut namespace = namespace(
1307 self.resolve,
1308 &owner.owner,
1309 matches!(variant, AbiVariant::GuestExport),
1310 &self.gen.opts,
1311 );
1312 namespace.push(owner.name.as_ref().unwrap().to_upper_camel_case());
1313 namespace
1314 };
1315 let mut f = FunctionBindgen::new(self, params);
1316 if !export {
1317 f.namespace = namespace.clone();
1318 }
1319 f.variant = variant;
1320 f.needs_dealloc = needs_dealloc;
1321 f.cabi_post = None;
1322 abi::call(f.gen.resolve, variant, lift_lower, func, &mut f, false);
1323 let code = String::from(f.src);
1324 self.gen.c_src.src.push_str(&code);
1325 }
1326 }
1327 self.gen.c_src.src.push_str("}\n");
1328 if matches!(variant, AbiVariant::GuestExport)
1330 && abi::guest_export_needs_post_return(self.resolve, func)
1331 {
1332 let sig = self.resolve.wasm_signature(variant, func);
1333 let module_name = self.wasm_import_module.clone();
1334 let export_name = match module_name {
1335 Some(ref module_name) => {
1336 format!("{module_name}#{}", func.name)
1337 }
1338 None => make_external_component(&func.name),
1339 };
1340 let import_name = match module_name {
1341 Some(ref module_name) => {
1342 make_external_symbol(module_name, &func.name, AbiVariant::GuestExport)
1343 }
1344 None => make_external_component(&func.name),
1345 };
1346 uwriteln!(
1347 self.gen.c_src.src,
1348 "extern \"C\" __attribute__((__weak__, __export_name__(\"cabi_post_{export_name}\")))"
1349 );
1350 uwrite!(self.gen.c_src.src, "void cabi_post_{import_name}(");
1351
1352 let mut params = Vec::new();
1353 for (i, result) in sig.results.iter().enumerate() {
1354 let name = format!("arg{i}");
1355 uwrite!(
1356 self.gen.c_src.src,
1357 "{} {name}",
1358 wit_bindgen_c::wasm_type(*result)
1359 );
1360 params.push(name);
1361 }
1362 self.gen.c_src.src.push_str(") {\n");
1363
1364 let mut f = FunctionBindgen::new(self, params.clone());
1365 f.params = params;
1366 abi::post_return(f.gen.resolve, func, &mut f);
1367 let FunctionBindgen { src, .. } = f;
1368 self.gen.c_src.src.push_str(&src);
1369 self.gen.c_src.src.push_str("}\n");
1370 }
1371 }
1372 }
1373
1374 fn optional_type_name(
1376 &mut self,
1377 ty: Option<&Type>,
1378 from_namespace: &[String],
1379 flavor: Flavor,
1380 ) -> String {
1381 match ty {
1382 Some(ty) => self.type_name(ty, from_namespace, flavor),
1383 None => "void".into(),
1384 }
1385 }
1386
1387 fn scoped_record_name(
1388 &self,
1389 id: TypeId,
1390 from_namespace: &[String],
1391 guest_export: bool,
1392 flavor: Flavor,
1393 ) -> String {
1394 let name = self.scoped_type_name(id, from_namespace, guest_export);
1395
1396 if let Flavor::Argument(AbiVariant::GuestImport) = flavor {
1397 match self.gen.opts.ownership {
1398 Ownership::Owning => {
1399 format!("{}", name)
1400 }
1401 Ownership::CoarseBorrowing => {
1402 if self.gen.types.get(id).has_own_handle {
1403 format!("{}", name)
1404 } else {
1405 format!("{}Param", name)
1406 }
1407 }
1408 Ownership::FineBorrowing => {
1409 format!("{}Param", name)
1410 }
1411 }
1412 } else {
1413 name
1414 }
1415 }
1416
1417 fn scoped_type_name(
1418 &self,
1419 id: TypeId,
1420 from_namespace: &[String],
1421 guest_export: bool,
1422 ) -> String {
1423 let ty = &self.resolve.types[id];
1424 let namespc = namespace(self.resolve, &ty.owner, guest_export, &self.gen.opts);
1425 let mut relative = SourceWithState::default();
1426 relative.namespace = Vec::from(from_namespace);
1427 relative.qualify(&namespc);
1428 format!(
1429 "{}{}",
1430 relative.src.to_string(),
1431 ty.name.as_ref().unwrap().to_pascal_case()
1432 )
1433 }
1434
1435 fn type_name(&mut self, ty: &Type, from_namespace: &[String], flavor: Flavor) -> String {
1436 match ty {
1437 Type::Bool => "bool".into(),
1438 Type::Char => "uint32_t".into(),
1439 Type::U8 => "uint8_t".into(),
1440 Type::S8 => "int8_t".into(),
1441 Type::U16 => "uint16_t".into(),
1442 Type::S16 => "int16_t".into(),
1443 Type::U32 => "uint32_t".into(),
1444 Type::S32 => "int32_t".into(),
1445 Type::U64 => "uint64_t".into(),
1446 Type::S64 => "int64_t".into(),
1447 Type::F32 => "float".into(),
1448 Type::F64 => "double".into(),
1449 Type::String => match flavor {
1450 Flavor::BorrowedArgument => {
1451 self.gen.dependencies.needs_string_view = true;
1452 "std::string_view".into()
1453 }
1454 Flavor::Argument(var)
1455 if matches!(var, AbiVariant::GuestImport)
1456 || self.gen.opts.api_style == APIStyle::Symmetric =>
1457 {
1458 self.gen.dependencies.needs_string_view = true;
1459 "std::string_view".into()
1460 }
1461 Flavor::Argument(AbiVariant::GuestExport) => {
1462 self.gen.dependencies.needs_wit = true;
1463 "wit::string".into()
1464 }
1465 _ => {
1466 self.gen.dependencies.needs_wit = true;
1467 "wit::string".into()
1468 }
1469 },
1470 Type::Id(id) => match &self.resolve.types[*id].kind {
1471 TypeDefKind::Record(_) => {
1472 let guest_export = self.is_exported_type(&self.resolve.types[*id]);
1473 self.scoped_record_name(*id, from_namespace, guest_export, flavor)
1474 }
1475 TypeDefKind::Resource => {
1476 let guest_export = self.is_exported_type(&self.resolve.types[*id]);
1477 self.scoped_type_name(*id, from_namespace, guest_export)
1478 }
1479 TypeDefKind::Handle(Handle::Own(id)) => {
1480 let mut typename = self.type_name(&Type::Id(*id), from_namespace, flavor);
1481 match (false, flavor) {
1482 (false, Flavor::Argument(AbiVariant::GuestImport))
1483 | (true, Flavor::Argument(AbiVariant::GuestExport)) => {
1484 typename.push_str("&&")
1485 }
1486 (false, Flavor::Argument(AbiVariant::GuestExport))
1487 | (false, Flavor::Result(AbiVariant::GuestExport))
1488 | (true, Flavor::Argument(AbiVariant::GuestImport))
1489 | (true, Flavor::Result(AbiVariant::GuestImport)) => {
1490 typename.push_str(&format!("::{OWNED_CLASS_NAME}"))
1491 }
1492 (false, Flavor::Result(AbiVariant::GuestImport))
1493 | (true, Flavor::Result(AbiVariant::GuestExport)) => (),
1494 (_, Flavor::InStruct) => (),
1495 (false, Flavor::BorrowedArgument) => (),
1496 (_, _) => todo!(),
1497 }
1498 let ty = &self.resolve.types[*id];
1499 if matches!(flavor, Flavor::InStruct) && self.is_exported_type(ty) {
1500 typename.push_str(&format!("::{OWNED_CLASS_NAME}"))
1501 }
1502 typename
1503 }
1504 TypeDefKind::Handle(Handle::Borrow(id)) => {
1505 "std::reference_wrapper<const ".to_string()
1506 + &self.type_name(&Type::Id(*id), from_namespace, flavor)
1507 + ">"
1508 }
1509 TypeDefKind::Flags(_f) => {
1510 let ty = &self.resolve.types[*id];
1511 let guest_export = self.is_exported_type(ty);
1512 self.scoped_type_name(*id, from_namespace, guest_export)
1513 }
1514 TypeDefKind::Tuple(t) => {
1515 let types = t.types.iter().fold(String::new(), |mut a, b| {
1516 if !a.is_empty() {
1517 a += ", ";
1518 }
1519 a + &self.type_name(b, from_namespace, flavor)
1520 });
1521 self.gen.dependencies.needs_tuple = true;
1522 String::from("std::tuple<") + &types + ">"
1523 }
1524 TypeDefKind::Variant(_v) => {
1525 let ty = &self.resolve.types[*id];
1526 let guest_export = self.is_exported_type(ty);
1527 self.scoped_type_name(*id, from_namespace, guest_export)
1528 }
1529 TypeDefKind::Enum(_e) => {
1530 let ty = &self.resolve.types[*id];
1531 let guest_export = self.is_exported_type(ty);
1532 self.scoped_type_name(*id, from_namespace, guest_export)
1533 }
1534 TypeDefKind::Option(o) => {
1535 self.gen.dependencies.needs_optional = true;
1536 "std::optional<".to_string() + &self.type_name(o, from_namespace, flavor) + ">"
1537 }
1538 TypeDefKind::Result(r) => {
1539 let err_type = r.err.as_ref().map_or(String::from("wit::Void"), |ty| {
1540 self.type_name(ty, from_namespace, flavor)
1541 });
1542 self.gen.dependencies.needs_expected = true;
1543 "std::expected<".to_string()
1544 + &self.optional_type_name(r.ok.as_ref(), from_namespace, flavor)
1545 + ", "
1546 + &err_type
1547 + ">"
1548 }
1549 TypeDefKind::List(ty) => {
1550 let inner = self.type_name(ty, from_namespace, flavor);
1551 match flavor {
1552 Flavor::BorrowedArgument => {
1553 self.gen.dependencies.needs_span = true;
1554 format!("std::span<{inner} const>")
1555 }
1556 Flavor::Argument(var)
1557 if matches!(var, AbiVariant::GuestImport)
1558 || self.gen.opts.api_style == APIStyle::Symmetric =>
1559 {
1560 self.gen.dependencies.needs_span = true;
1561 let constness = if self.gen.types.get(*id).has_own_handle {
1563 ""
1564 } else {
1565 " const"
1566 };
1567 format!("std::span<{inner}{constness}>")
1568 }
1569 Flavor::Argument(AbiVariant::GuestExport) => {
1570 self.gen.dependencies.needs_wit = true;
1571 format!("wit::vector<{inner}>")
1572 }
1573 _ => {
1574 self.gen.dependencies.needs_wit = true;
1575 format!("wit::vector<{inner}>")
1576 }
1577 }
1578 }
1579 TypeDefKind::Future(_) => todo!(),
1580 TypeDefKind::Stream(_) => todo!(),
1581 TypeDefKind::Type(ty) => self.type_name(ty, from_namespace, flavor),
1582 TypeDefKind::FixedSizeList(_, _) => todo!(),
1583 TypeDefKind::Unknown => todo!(),
1584 },
1585 Type::ErrorContext => todo!(),
1586 }
1587 }
1588
1589 fn declare_import2(
1590 &self,
1591 module_name: &str,
1592 name: &str,
1593 args: &str,
1594 result: &str,
1595 variant: AbiVariant,
1596 ) -> (String, String) {
1597 let extern_name = make_external_symbol(module_name, name, variant);
1598 let import = format!("extern \"C\" __attribute__((import_module(\"{module_name}\")))\n __attribute__((import_name(\"{name}\")))\n {result} {extern_name}({args});\n")
1599 ;
1600 (extern_name, import)
1601 }
1602
1603 fn declare_import(
1604 &mut self,
1605 module_name: &str,
1606 name: &str,
1607 params: &[WasmType],
1608 results: &[WasmType],
1609 ) -> String {
1610 let mut args = String::default();
1611 for (n, param) in params.iter().enumerate() {
1612 args.push_str(wit_bindgen_c::wasm_type(*param));
1613 if n + 1 != params.len() {
1614 args.push_str(", ");
1615 }
1616 }
1617 let result = if results.is_empty() {
1618 "void"
1619 } else {
1620 wit_bindgen_c::wasm_type(results[0])
1621 };
1622 let variant = AbiVariant::GuestImport;
1623 let (name, code) = self.declare_import2(module_name, name, &args, result, variant);
1624 self.gen.extern_c_decls.push_str(&code);
1625 name
1626 }
1627
1628 fn docs(src: &mut Source, docs: &Docs) {
1629 if let Some(docs) = docs.contents.as_ref() {
1630 for line in docs.trim().lines() {
1631 src.push_str("/// ");
1632 src.push_str(line);
1633 src.push_str("\n");
1634 }
1635 }
1636 }
1637
1638 fn type_record_param(
1639 &mut self,
1640 id: TypeId,
1641 name: &str,
1642 record: &wit_bindgen_core::wit_parser::Record,
1643 namespc: &[String],
1644 ) {
1645 let (flavor, needs_param_type) = {
1646 match self.gen.opts.ownership {
1647 Ownership::Owning => (Flavor::InStruct, false),
1648 Ownership::CoarseBorrowing => {
1649 if self.gen.types.get(id).has_own_handle {
1650 (Flavor::InStruct, false)
1651 } else {
1652 (Flavor::BorrowedArgument, true)
1653 }
1654 }
1655 Ownership::FineBorrowing => (Flavor::BorrowedArgument, true),
1656 }
1657 };
1658
1659 if needs_param_type {
1660 let pascal = format!("{name}-param").to_pascal_case();
1661
1662 uwriteln!(self.gen.h_src.src, "struct {pascal} {{");
1663 for field in record.fields.iter() {
1664 let typename = self.type_name(&field.ty, namespc, flavor);
1665 let fname = field.name.to_snake_case();
1666 uwriteln!(self.gen.h_src.src, "{typename} {fname};");
1667 }
1668 uwriteln!(self.gen.h_src.src, "}};");
1669 }
1670 }
1671
1672 fn is_exported_type(&self, ty: &TypeDef) -> bool {
1673 if let TypeOwner::Interface(intf) = ty.owner {
1674 !self.gen.imported_interfaces.contains(&intf)
1675 } else {
1676 true
1677 }
1678 }
1679}
1680
1681impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for CppInterfaceGenerator<'a> {
1682 fn resolve(&self) -> &'a Resolve {
1683 self.resolve
1684 }
1685
1686 fn type_record(
1687 &mut self,
1688 id: TypeId,
1689 name: &str,
1690 record: &wit_bindgen_core::wit_parser::Record,
1691 docs: &wit_bindgen_core::wit_parser::Docs,
1692 ) {
1693 let ty = &self.resolve.types[id];
1694 let guest_export = self.is_exported_type(ty);
1695 let namespc = namespace(self.resolve, &ty.owner, guest_export, &self.gen.opts);
1696
1697 if self.gen.is_first_definition(&namespc, &name) {
1698 self.gen.h_src.change_namespace(&namespc);
1699 Self::docs(&mut self.gen.h_src.src, docs);
1700 let pascal = name.to_pascal_case();
1701
1702 uwriteln!(self.gen.h_src.src, "struct {pascal} {{");
1703 for field in record.fields.iter() {
1704 Self::docs(&mut self.gen.h_src.src, &field.docs);
1705 let typename = self.type_name(&field.ty, &namespc, Flavor::InStruct);
1706 let fname = field.name.to_snake_case();
1707 uwriteln!(self.gen.h_src.src, "{typename} {fname};");
1708 }
1709 uwriteln!(self.gen.h_src.src, "}};");
1710 self.type_record_param(id, name, record, namespc.as_slice());
1711 }
1712 }
1713
1714 fn type_resource(
1715 &mut self,
1716 id: TypeId,
1717 name: &str,
1718 _docs: &wit_bindgen_core::wit_parser::Docs,
1719 ) {
1720 let type_ = &self.resolve.types[id];
1721 if let TypeOwner::Interface(intf) = type_.owner {
1722 let guest_import = self.gen.imported_interfaces.contains(&intf);
1723 let definition = !(guest_import);
1724 let store = self.gen.start_new_file(Some(definition));
1725 let mut world_name = self.gen.world.to_snake_case();
1726 world_name.push_str("::");
1727 let namespc = namespace(self.resolve, &type_.owner, !guest_import, &self.gen.opts);
1728 let pascal = name.to_upper_camel_case();
1729 let mut user_filename = namespc.clone();
1730 user_filename.push(pascal.clone());
1731 if definition {
1732 uwriteln!(
1733 self.gen.h_src.src,
1734 r#"/* User class definition file, autogenerated once, then user modified
1735 * Updated versions of this file are generated into {pascal}.template.
1736 */"#
1737 );
1738 }
1739 self.gen.h_src.change_namespace(&namespc);
1740
1741 if !definition {
1742 self.gen.dependencies.needs_imported_resources = true;
1743 } else {
1744 self.gen.dependencies.needs_exported_resources = true;
1745 }
1746 self.gen.dependencies.needs_wit = true;
1747
1748 let base_type = match (definition, false) {
1749 (true, false) => format!("wit::{RESOURCE_EXPORT_BASE_CLASS_NAME}<{pascal}>"),
1750 (false, false) => {
1751 String::from_str("wit::").unwrap() + RESOURCE_IMPORT_BASE_CLASS_NAME
1752 }
1753 (false, true) => {
1754 String::from_str("wit::").unwrap() + RESOURCE_EXPORT_BASE_CLASS_NAME
1755 }
1756 (true, true) => format!("wit::{RESOURCE_IMPORT_BASE_CLASS_NAME}<{pascal}>"),
1757 };
1758 let derive = format!(" : public {base_type}");
1759 uwriteln!(self.gen.h_src.src, "class {pascal}{derive} {{\n");
1760 uwriteln!(self.gen.h_src.src, "public:\n");
1761 let variant = if guest_import {
1762 AbiVariant::GuestImport
1763 } else {
1764 AbiVariant::GuestExport
1765 };
1766 {
1767 let name = match variant {
1769 AbiVariant::GuestImport => "[resource-drop]",
1770 AbiVariant::GuestExport => "[dtor]",
1771 AbiVariant::GuestImportAsync => todo!(),
1772 AbiVariant::GuestExportAsync => todo!(),
1773 AbiVariant::GuestExportAsyncStackful => todo!(),
1774 }
1775 .to_string()
1776 + name;
1777 let func = Function {
1778 name,
1779 kind: FunctionKind::Static(id),
1780 params: vec![("self".into(), Type::Id(id))],
1781 result: None,
1782 docs: Docs::default(),
1783 stability: Stability::Unknown,
1784 };
1785 self.generate_function(&func, &TypeOwner::Interface(intf), variant);
1786 }
1787 let funcs = self.resolve.interfaces[intf].functions.values();
1788 for func in funcs {
1789 if match &func.kind {
1790 FunctionKind::Freestanding => false,
1791 FunctionKind::Method(mid) => *mid == id,
1792 FunctionKind::Static(mid) => *mid == id,
1793 FunctionKind::Constructor(mid) => *mid == id,
1794 FunctionKind::AsyncFreestanding => todo!(),
1795 FunctionKind::AsyncMethod(_id) => todo!(),
1796 FunctionKind::AsyncStatic(_id) => todo!(),
1797 } {
1798 self.generate_function(func, &TypeOwner::Interface(intf), variant);
1799 if matches!(func.kind, FunctionKind::Constructor(_))
1800 && matches!(variant, AbiVariant::GuestExport)
1801 {
1802 let func2 = Function {
1804 name: "$alloc".to_string(),
1805 kind: FunctionKind::Static(id),
1806 params: func.params.clone(),
1808 result: Some(Type::Id(id)),
1809 docs: Docs::default(),
1810 stability: Stability::Unknown,
1811 };
1812 self.generate_function(&func2, &TypeOwner::Interface(intf), variant);
1813 }
1814 }
1815 }
1816
1817 if !definition {
1818 uwriteln!(self.gen.h_src.src, "{pascal}({base_type} &&);",);
1820 uwriteln!(self.gen.h_src.src, "{pascal}({pascal}&&) = default;");
1821 uwriteln!(
1822 self.gen.h_src.src,
1823 "{pascal}& operator=({pascal}&&) = default;"
1824 );
1825 self.gen.c_src.qualify(&namespc);
1826 uwriteln!(
1827 self.gen.c_src.src,
1828 "{pascal}::{pascal}({base_type}&&b) : {base_type}(std::move(b)) {{}}"
1829 );
1830 }
1831 if matches!(variant, AbiVariant::GuestExport) {
1832 let id_type = Type::S32;
1833 let func = Function {
1834 name: "[resource-new]".to_string() + name,
1835 kind: FunctionKind::Static(id),
1836 params: vec![("self".into(), Type::Id(id))],
1837 result: Some(id_type),
1838 docs: Docs::default(),
1839 stability: Stability::Unknown,
1840 };
1841 self.generate_function(&func, &TypeOwner::Interface(intf), variant);
1842
1843 let func1 = Function {
1844 name: "[resource-rep]".to_string() + name,
1845 kind: FunctionKind::Static(id),
1846 params: vec![("id".into(), id_type)],
1847 result: Some(Type::Id(id)),
1848 docs: Docs::default(),
1849 stability: Stability::Unknown,
1850 };
1851 self.generate_function(&func1, &TypeOwner::Interface(intf), variant);
1852
1853 let func2 = Function {
1854 name: "[resource-drop]".to_string() + name,
1855 kind: FunctionKind::Static(id),
1856 params: vec![("id".into(), id_type)],
1857 result: None,
1858 docs: Docs::default(),
1859 stability: Stability::Unknown,
1860 };
1861 self.generate_function(&func2, &TypeOwner::Interface(intf), variant);
1862 }
1863 uwriteln!(self.gen.h_src.src, "}};\n");
1864 self.gen.finish_file(&user_filename, store);
1865 }
1866 }
1867
1868 fn type_flags(
1869 &mut self,
1870 id: TypeId,
1871 name: &str,
1872 flags: &wit_bindgen_core::wit_parser::Flags,
1873 docs: &wit_bindgen_core::wit_parser::Docs,
1874 ) {
1875 let ty = &self.resolve.types[id];
1876 let guest_export = self.is_exported_type(ty);
1877 let namespc = namespace(self.resolve, &ty.owner, guest_export, &self.gen.opts);
1878 if self.gen.is_first_definition(&namespc, name) {
1879 self.gen.h_src.change_namespace(&namespc);
1880 Self::docs(&mut self.gen.h_src.src, docs);
1881 let pascal = name.to_pascal_case();
1882 let int_repr = wit_bindgen_c::int_repr(wit_bindgen_c::flags_repr(flags));
1883 uwriteln!(self.gen.h_src.src, "enum class {pascal} : {int_repr} {{");
1884 uwriteln!(self.gen.h_src.src, "k_None = 0,");
1885 for (n, field) in flags.flags.iter().enumerate() {
1886 Self::docs(&mut self.gen.h_src.src, &field.docs);
1887 let fname = field.name.to_pascal_case();
1888 uwriteln!(self.gen.h_src.src, "k{fname} = (1ULL<<{n}),");
1889 }
1890 uwriteln!(self.gen.h_src.src, "}};");
1891 uwriteln!(
1892 self.gen.h_src.src,
1893 r#"static inline {pascal} operator|({pascal} a, {pascal} b) {{ return {pascal}({int_repr}(a)|{int_repr}(b)); }}
1894 static inline {pascal} operator&({pascal} a, {pascal} b) {{ return {pascal}({int_repr}(a)&{int_repr}(b)); }}"#
1895 );
1896 }
1897 }
1898
1899 fn type_tuple(
1900 &mut self,
1901 _id: TypeId,
1902 _name: &str,
1903 _flags: &wit_bindgen_core::wit_parser::Tuple,
1904 _docs: &wit_bindgen_core::wit_parser::Docs,
1905 ) {
1906 }
1908
1909 fn type_variant(
1910 &mut self,
1911 id: TypeId,
1912 name: &str,
1913 variant: &wit_bindgen_core::wit_parser::Variant,
1914 docs: &wit_bindgen_core::wit_parser::Docs,
1915 ) {
1916 let ty = &self.resolve.types[id];
1917 let guest_export = self.is_exported_type(ty);
1918 let namespc = namespace(self.resolve, &ty.owner, guest_export, &self.gen.opts);
1919 if self.gen.is_first_definition(&namespc, name) {
1920 self.gen.h_src.change_namespace(&namespc);
1921 Self::docs(&mut self.gen.h_src.src, docs);
1922 let pascal = name.to_pascal_case();
1923 uwriteln!(self.gen.h_src.src, "struct {pascal} {{");
1924 let mut inner_namespace = namespc.clone();
1925 inner_namespace.push(pascal.clone());
1926 let mut all_types = String::new();
1927 for case in variant.cases.iter() {
1928 Self::docs(&mut self.gen.h_src.src, &case.docs);
1929 let case_pascal = case.name.to_pascal_case();
1930 if !all_types.is_empty() {
1931 all_types += ", ";
1932 }
1933 all_types += &case_pascal;
1934 uwrite!(self.gen.h_src.src, "struct {case_pascal} {{");
1935 if let Some(ty) = case.ty.as_ref() {
1936 let typestr = self.type_name(ty, &inner_namespace, Flavor::InStruct);
1937 uwrite!(self.gen.h_src.src, " {typestr} value; ")
1938 }
1939 uwriteln!(self.gen.h_src.src, "}};");
1940 }
1941 uwriteln!(self.gen.h_src.src, " std::variant<{all_types}> variants;");
1942 uwriteln!(self.gen.h_src.src, "}};");
1943 self.gen.dependencies.needs_variant = true;
1944 }
1945 }
1946
1947 fn type_option(
1948 &mut self,
1949 _id: TypeId,
1950 _name: &str,
1951 _payload: &wit_bindgen_core::wit_parser::Type,
1952 _docs: &wit_bindgen_core::wit_parser::Docs,
1953 ) {
1954 }
1956
1957 fn type_result(
1958 &mut self,
1959 _id: TypeId,
1960 _name: &str,
1961 _result: &wit_bindgen_core::wit_parser::Result_,
1962 _docs: &wit_bindgen_core::wit_parser::Docs,
1963 ) {
1964 }
1966
1967 fn type_enum(
1968 &mut self,
1969 id: TypeId,
1970 name: &str,
1971 enum_: &wit_bindgen_core::wit_parser::Enum,
1972 docs: &wit_bindgen_core::wit_parser::Docs,
1973 ) {
1974 let ty = &self.resolve.types[id];
1975 let guest_export = self.is_exported_type(ty);
1976 let namespc = namespace(self.resolve, &ty.owner, guest_export, &self.gen.opts);
1977 if self.gen.is_first_definition(&namespc, name) {
1978 self.gen.h_src.change_namespace(&namespc);
1979 let pascal = name.to_pascal_case();
1980 Self::docs(&mut self.gen.h_src.src, docs);
1981 let int_t = wit_bindgen_c::int_repr(enum_.tag());
1982 uwriteln!(self.gen.h_src.src, "enum class {pascal} : {int_t} {{");
1983 for (i, case) in enum_.cases.iter().enumerate() {
1984 Self::docs(&mut self.gen.h_src.src, &case.docs);
1985 uwriteln!(
1986 self.gen.h_src.src,
1987 " k{} = {i},",
1988 case.name.to_pascal_case(),
1989 );
1990 }
1991 uwriteln!(self.gen.h_src.src, "}};\n");
1992 }
1993 }
1994
1995 fn type_alias(
1996 &mut self,
1997 id: TypeId,
1998 name: &str,
1999 alias_type: &wit_bindgen_core::wit_parser::Type,
2000 docs: &wit_bindgen_core::wit_parser::Docs,
2001 ) {
2002 let ty = &self.resolve.types[id];
2003 let guest_export = self.is_exported_type(ty);
2004 let namespc = namespace(self.resolve, &ty.owner, guest_export, &self.gen.opts);
2005 self.gen.h_src.change_namespace(&namespc);
2006 let pascal = name.to_pascal_case();
2007 Self::docs(&mut self.gen.h_src.src, docs);
2008 let typename = self.type_name(alias_type, &namespc, Flavor::InStruct);
2009 uwriteln!(self.gen.h_src.src, "using {pascal} = {typename};");
2010 }
2011
2012 fn type_list(
2013 &mut self,
2014 _id: TypeId,
2015 _name: &str,
2016 _ty: &wit_bindgen_core::wit_parser::Type,
2017 _docs: &wit_bindgen_core::wit_parser::Docs,
2018 ) {
2019 }
2021
2022 fn type_builtin(
2023 &mut self,
2024 _id: TypeId,
2025 _name: &str,
2026 _ty: &wit_bindgen_core::wit_parser::Type,
2027 _docs: &wit_bindgen_core::wit_parser::Docs,
2028 ) {
2029 todo!()
2030 }
2031
2032 fn type_future(&mut self, _id: TypeId, _name: &str, _ty: &Option<Type>, _docs: &Docs) {
2033 todo!()
2034 }
2035
2036 fn type_stream(&mut self, _id: TypeId, _name: &str, _ty: &Option<Type>, _docs: &Docs) {
2037 todo!()
2038 }
2039}
2040
2041struct CabiPostInformation {
2042 module: String,
2043 name: String,
2044 ret_type: String,
2045}
2046
2047struct FunctionBindgen<'a, 'b> {
2048 gen: &'b mut CppInterfaceGenerator<'a>,
2049 params: Vec<String>,
2050 tmp: usize,
2051 namespace: Vec<String>,
2052 src: Source,
2053 block_storage: Vec<wit_bindgen_core::Source>,
2054 blocks: Vec<(String, Vec<String>)>,
2056 payloads: Vec<String>,
2057 variant: AbiVariant,
2059 cabi_post: Option<CabiPostInformation>,
2060 needs_dealloc: bool,
2061 leak_on_insertion: Option<String>,
2062}
2063
2064impl<'a, 'b> FunctionBindgen<'a, 'b> {
2065 fn new(gen: &'b mut CppInterfaceGenerator<'a>, params: Vec<String>) -> Self {
2066 Self {
2067 gen,
2068 params,
2069 tmp: 0,
2070 namespace: Default::default(),
2071 src: Default::default(),
2072 block_storage: Default::default(),
2073 blocks: Default::default(),
2074 payloads: Default::default(),
2075 variant: AbiVariant::GuestImport,
2076 cabi_post: None,
2077 needs_dealloc: false,
2078 leak_on_insertion: None,
2079 }
2080 }
2081
2082 fn tmp(&mut self) -> usize {
2083 let ret = self.tmp;
2084 self.tmp += 1;
2085 ret
2086 }
2087
2088 fn tempname(&self, base: &str, idx: usize) -> String {
2089 format!("{base}{idx}")
2090 }
2091
2092 fn push_str(&mut self, s: &str) {
2093 self.src.push_str(s);
2094 }
2095
2096 fn let_results(&mut self, amt: usize, results: &mut Vec<String>) {
2097 if amt > 0 {
2098 let tmp = self.tmp();
2099 let res = format!("result{}", tmp);
2100 self.push_str("auto ");
2101 self.push_str(&res);
2102 self.push_str(" = ");
2103 if amt == 1 {
2104 results.push(res);
2105 } else {
2106 for i in 0..amt {
2107 results.push(format!("std::get<{i}>({res})"));
2108 }
2109 }
2110 }
2111 }
2112
2113 fn load(
2114 &mut self,
2115 ty: &str,
2116 offset: ArchitectureSize,
2117 operands: &[String],
2118 results: &mut Vec<String>,
2119 ) {
2120 results.push(format!(
2121 "*(({}*) ({} + {}))",
2122 ty,
2123 operands[0],
2124 offset.format(POINTER_SIZE_EXPRESSION)
2125 ));
2126 }
2127
2128 fn load_ext(
2129 &mut self,
2130 ty: &str,
2131 offset: ArchitectureSize,
2132 operands: &[String],
2133 results: &mut Vec<String>,
2134 ) {
2135 self.load(ty, offset, operands, results);
2136 let result = results.pop().unwrap();
2137 results.push(format!("(int32_t) ({})", result));
2138 }
2139
2140 fn store(&mut self, ty: &str, offset: ArchitectureSize, operands: &[String]) {
2141 uwriteln!(
2142 self.src,
2143 "*(({}*)({} + {})) = {};",
2144 ty,
2145 operands[1],
2146 offset.format(POINTER_SIZE_EXPRESSION),
2147 operands[0]
2148 );
2149 }
2150}
2151
2152fn move_if_necessary(arg: &str) -> String {
2153 if !arg.is_empty() && arg.chars().all(char::is_alphanumeric) {
2155 format!("std::move({arg})")
2156 } else {
2157 arg.into()
2158 }
2159}
2160
2161impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> {
2162 type Operand = String;
2163
2164 fn emit(
2165 &mut self,
2166 _resolve: &Resolve,
2167 inst: &wit_bindgen_core::abi::Instruction<'_>,
2168 operands: &mut Vec<Self::Operand>,
2169 results: &mut Vec<Self::Operand>,
2170 ) {
2171 let mut top_as = |cvt: &str| {
2172 results.push(format!("({cvt}({}))", operands.pop().unwrap()));
2173 };
2174
2175 match inst {
2176 abi::Instruction::GetArg { nth } => {
2177 if *nth == 0 && self.params[0].as_str() == "self" {
2178 if self.gen.in_guest_import {
2179 results.push("(*this)".to_string());
2180 } else {
2181 results.push("(*lookup_resource(self))".to_string());
2182 }
2183 } else {
2184 results.push(self.params[*nth].clone());
2185 }
2186 }
2187 abi::Instruction::I32Const { val } => results.push(format!("(int32_t({}))", val)),
2188 abi::Instruction::Bitcasts { casts } => {
2189 for (cast, op) in casts.iter().zip(operands) {
2190 results.push(self.gen.gen.perform_cast(op, cast));
2192 }
2193 }
2194 abi::Instruction::ConstZero { tys } => {
2195 for ty in tys.iter() {
2196 match ty {
2197 WasmType::I32 => results.push("int32_t(0)".to_string()),
2198 WasmType::I64 => results.push("int64_t(0)".to_string()),
2199 WasmType::F32 => results.push("0.0f".to_string()),
2200 WasmType::F64 => results.push("0.0".to_string()),
2201 WasmType::Length => results.push("size_t(0)".to_string()),
2202 WasmType::Pointer => results.push("nullptr".to_string()),
2203 WasmType::PointerOrI64 => results.push("int64_t(0)".to_string()),
2204 }
2205 }
2206 }
2207 abi::Instruction::I32Load { offset } => {
2208 let tmp = self.tmp();
2209 uwriteln!(
2210 self.src,
2211 "int32_t l{tmp} = *((int32_t const*)({} + {offset}));",
2212 operands[0],
2213 offset = offset.format(POINTER_SIZE_EXPRESSION)
2214 );
2215 results.push(format!("l{tmp}"));
2216 }
2217 abi::Instruction::I32Load8U { offset } => {
2218 self.load_ext("uint8_t", *offset, operands, results)
2219 }
2220 abi::Instruction::I32Load8S { offset } => {
2221 self.load_ext("int8_t", *offset, operands, results)
2222 }
2223 abi::Instruction::I32Load16U { offset } => {
2224 self.load_ext("uint16_t", *offset, operands, results)
2225 }
2226 abi::Instruction::I32Load16S { offset } => {
2227 self.load_ext("int16_t", *offset, operands, results)
2228 }
2229 abi::Instruction::I64Load { offset } => {
2230 self.load("int64_t", *offset, operands, results)
2231 }
2232 abi::Instruction::F32Load { offset } => self.load("float", *offset, operands, results),
2233 abi::Instruction::F64Load { offset } => self.load("double", *offset, operands, results),
2234 abi::Instruction::I32Store { offset } => self.store("int32_t", *offset, operands),
2235 abi::Instruction::I32Store8 { offset } => self.store("int8_t", *offset, operands),
2236 abi::Instruction::I32Store16 { offset } => self.store("int16_t", *offset, operands),
2237 abi::Instruction::I64Store { offset } => self.store("int64_t", *offset, operands),
2238 abi::Instruction::F32Store { offset } => self.store("float", *offset, operands),
2239 abi::Instruction::F64Store { offset } => self.store("double", *offset, operands),
2240 abi::Instruction::I32FromChar
2241 | abi::Instruction::I32FromBool
2242 | abi::Instruction::I32FromU8
2243 | abi::Instruction::I32FromS8
2244 | abi::Instruction::I32FromU16
2245 | abi::Instruction::I32FromS16
2246 | abi::Instruction::I32FromU32
2247 | abi::Instruction::I32FromS32 => top_as("int32_t"),
2248 abi::Instruction::I64FromU64 | abi::Instruction::I64FromS64 => top_as("int64_t"),
2249 abi::Instruction::F32FromCoreF32 => top_as("float"),
2250 abi::Instruction::F64FromCoreF64 => top_as("double"),
2251 abi::Instruction::S8FromI32 => top_as("int8_t"),
2252 abi::Instruction::U8FromI32 => top_as("uint8_t"),
2253 abi::Instruction::S16FromI32 => top_as("int16_t"),
2254 abi::Instruction::U16FromI32 => top_as("uint16_t"),
2255 abi::Instruction::S32FromI32 => top_as("int32_t"),
2256 abi::Instruction::U32FromI32 => top_as("uint32_t"),
2257 abi::Instruction::S64FromI64 => top_as("int64_t"),
2258 abi::Instruction::U64FromI64 => top_as("uint64_t"),
2259 abi::Instruction::CharFromI32 => top_as("uint32_t"),
2260 abi::Instruction::CoreF32FromF32 => top_as("float"),
2261 abi::Instruction::CoreF64FromF64 => top_as("double"),
2262 abi::Instruction::BoolFromI32 => top_as("bool"),
2263 abi::Instruction::ListCanonLower { realloc, .. } => {
2264 let tmp = self.tmp();
2265 let val = format!("vec{}", tmp);
2266 let ptr = format!("ptr{}", tmp);
2267 let len = format!("len{}", tmp);
2268 self.push_str(&format!("auto&& {} = {};\n", val, operands[0]));
2269 self.push_str(&format!(
2270 "auto {} = ({})({}.data());\n",
2271 ptr,
2272 self.gen.gen.opts.ptr_type(),
2273 val
2274 ));
2275 self.push_str(&format!("auto {} = (size_t)({}.size());\n", len, val));
2276 if realloc.is_none() {
2277 results.push(ptr);
2278 } else {
2279 uwriteln!(self.src, "{}.leak();\n", operands[0]);
2280 results.push(ptr);
2281 }
2282 results.push(len);
2283 }
2284 abi::Instruction::StringLower { realloc } => {
2285 let tmp = self.tmp();
2286 let val = format!("vec{}", tmp);
2287 let ptr = format!("ptr{}", tmp);
2288 let len = format!("len{}", tmp);
2289 self.push_str(&format!("auto&& {} = {};\n", val, operands[0]));
2290 self.push_str(&format!(
2291 "auto {} = ({})({}.data());\n",
2292 ptr,
2293 self.gen.gen.opts.ptr_type(),
2294 val
2295 ));
2296 self.push_str(&format!("auto {} = (size_t)({}.size());\n", len, val));
2297 if realloc.is_none() {
2298 results.push(ptr);
2299 } else {
2300 uwriteln!(self.src, "{}.leak();\n", operands[0]);
2301 results.push(ptr);
2302 }
2303 results.push(len);
2304 }
2305 abi::Instruction::ListLower { element, realloc } => {
2306 let tmp = self.tmp();
2307 let body = self.blocks.pop().unwrap();
2308 let val = format!("vec{}", tmp);
2309 let ptr = format!("ptr{}", tmp);
2310 let len = format!("len{}", tmp);
2311 let size = self.gen.sizes.size(element);
2312 self.push_str(&format!("auto&& {} = {};\n", val, operands[0]));
2313 self.push_str(&format!(
2314 "auto {} = ({})({}.data());\n",
2315 ptr,
2316 self.gen.gen.opts.ptr_type(),
2317 val
2318 ));
2319 self.push_str(&format!("auto {} = (size_t)({}.size());\n", len, val));
2320 self.push_str(&format!("for (size_t i = 0; i < {len}; ++i) {{\n"));
2321 self.push_str(&format!(
2322 "auto base = {ptr} + i * {size};\n",
2323 size = size.format(POINTER_SIZE_EXPRESSION)
2324 ));
2325 self.push_str(&format!("auto&& IterElem = {val}[i];\n"));
2326 self.push_str(&format!("{}\n", body.0));
2327 self.push_str("}\n");
2328 if realloc.is_none() {
2329 results.push(ptr);
2330 } else {
2331 uwriteln!(self.src, "{}.leak();\n", operands[0]);
2332 results.push(ptr);
2333 }
2334 results.push(len);
2335 }
2336 abi::Instruction::ListCanonLift { element, .. } => {
2337 let tmp = self.tmp();
2338 let len = format!("len{}", tmp);
2339 let inner = self
2340 .gen
2341 .type_name(element, &self.namespace, Flavor::InStruct);
2342 self.push_str(&format!("auto {} = {};\n", len, operands[1]));
2343 let result = if self.gen.gen.opts.api_style == APIStyle::Symmetric
2344 && matches!(self.variant, AbiVariant::GuestExport)
2345 {
2346 format!(
2347 "wit::vector<{inner} const>(({inner}*)({}), {len}).get_view()",
2348 operands[0]
2349 )
2350 } else {
2351 format!("wit::vector<{inner}>(({inner}*)({}), {len})", operands[0])
2352 };
2353 results.push(result);
2354 }
2355 abi::Instruction::StringLift => {
2356 let tmp = self.tmp();
2357 let len = format!("len{}", tmp);
2358 uwriteln!(self.src, "auto {} = {};\n", len, operands[1]);
2359 let result = if self.gen.gen.opts.api_style == APIStyle::Symmetric
2360 && matches!(self.variant, AbiVariant::GuestExport)
2361 {
2362 assert!(self.needs_dealloc);
2363 uwriteln!(
2364 self.src,
2365 "if ({len}>0) _deallocate.push_back({});\n",
2366 operands[0]
2367 );
2368 format!("std::string_view((char const*)({}), {len})", operands[0])
2369 } else {
2370 format!("wit::string((char const*)({}), {len})", operands[0])
2371 };
2372 results.push(result);
2373 }
2374 abi::Instruction::ListLift { element, .. } => {
2375 let body = self.blocks.pop().unwrap();
2376 let tmp = self.tmp();
2377 let size = self.gen.sizes.size(element);
2378 let _align = self.gen.sizes.align(element);
2379 let flavor = if self.gen.gen.opts.api_style == APIStyle::Symmetric
2380 && matches!(self.variant, AbiVariant::GuestExport)
2381 {
2382 Flavor::BorrowedArgument
2383 } else {
2384 Flavor::InStruct
2385 };
2386 let vtype = self.gen.type_name(element, &self.namespace, flavor);
2387 let len = format!("len{tmp}");
2388 let base = format!("base{tmp}");
2389 let result = format!("result{tmp}");
2390 self.push_str(&format!(
2391 "auto {base} = {operand0};\n",
2392 operand0 = operands[0]
2393 ));
2394 self.push_str(&format!(
2395 "auto {len} = {operand1};\n",
2396 operand1 = operands[1]
2397 ));
2398 self.push_str(&format!(
2399 r#"auto {result} = wit::vector<{vtype}>::allocate({len});
2400 "#,
2401 ));
2402
2403 if self.gen.gen.opts.api_style == APIStyle::Symmetric
2404 && matches!(self.variant, AbiVariant::GuestExport)
2405 {
2406 assert!(self.needs_dealloc);
2407 self.push_str(&format!("if ({len}>0) _deallocate.push_back({base});\n"));
2408 }
2409
2410 uwriteln!(self.src, "for (unsigned i=0; i<{len}; ++i) {{");
2411 uwriteln!(
2412 self.src,
2413 "auto base = {base} + i * {size};",
2414 size = size.format(POINTER_SIZE_EXPRESSION)
2415 );
2416 uwrite!(self.src, "{}", body.0);
2417 uwriteln!(self.src, "auto e{tmp} = {};", body.1[0]);
2418 if let Some(code) = self.leak_on_insertion.take() {
2419 assert!(self.needs_dealloc);
2420 uwriteln!(self.src, "{code}");
2421 }
2422 uwriteln!(self.src, "{result}.initialize(i, std::move(e{tmp}));");
2424 uwriteln!(self.src, "}}");
2425
2426 if self.gen.gen.opts.api_style == APIStyle::Symmetric
2427 && matches!(self.variant, AbiVariant::GuestExport)
2428 {
2429 results.push(format!("{result}.get_const_view()"));
2430 if self.gen.gen.opts.api_style == APIStyle::Symmetric
2431 && matches!(self.variant, AbiVariant::GuestExport)
2432 {
2433 self.leak_on_insertion.replace(format!(
2434 "if ({len}>0) _deallocate.push_back((void*){result}.leak());\n"
2435 ));
2436 }
2437 } else {
2438 results.push(move_if_necessary(&result));
2439 }
2440 }
2441 abi::Instruction::IterElem { .. } => results.push("IterElem".to_string()),
2442 abi::Instruction::IterBasePointer => results.push("base".to_string()),
2443 abi::Instruction::RecordLower { record, .. } => {
2444 let op = &operands[0];
2445 for f in record.fields.iter() {
2446 results.push(format!("({}).{}", op, to_c_ident(&f.name)));
2447 }
2448 }
2449 abi::Instruction::RecordLift { record, ty, .. } => {
2450 let mut result =
2451 self.gen
2452 .type_name(&Type::Id(*ty), &self.namespace, Flavor::InStruct);
2453 result.push('{');
2454 for (_field, val) in record.fields.iter().zip(operands) {
2455 result.push_str(&(move_if_necessary(val) + ", "));
2456 }
2457 result.push('}');
2458 results.push(result);
2459 }
2460 abi::Instruction::HandleLower {
2461 handle: Handle::Own(_ty),
2462 ..
2463 } => {
2464 let op = &operands[0];
2465 if matches!(self.variant, AbiVariant::GuestImport) {
2466 results.push(format!("{op}.into_handle()"));
2467 } else {
2468 results.push(format!("{op}.release()->handle"));
2469 }
2470 }
2471 abi::Instruction::HandleLower {
2472 handle: Handle::Borrow(_),
2473 ..
2474 } => {
2475 let op = &operands[0];
2476 if op == "(*this)" {
2477 results.push(format!("{op}.get_handle()"));
2479 } else {
2480 results.push(format!("{op}.get().get_handle()"));
2481 }
2482 }
2483 abi::Instruction::HandleLift { handle, .. } => {
2484 let op = &operands[0];
2485 match (handle, false) {
2486 (Handle::Own(ty), true) => match self.variant {
2487 AbiVariant::GuestExport => {
2488 results.push(format!("wit::{RESOURCE_EXPORT_BASE_CLASS_NAME}{{{op}}}"))
2489 }
2490 AbiVariant::GuestImport => {
2491 let tmp = self.tmp();
2492 let var = self.tempname("obj", tmp);
2493 let tname = self.gen.type_name(
2494 &Type::Id(*ty),
2495 &self.namespace,
2496 Flavor::Argument(self.variant),
2497 );
2498 uwriteln!(
2499 self.src,
2500 "auto {var} = {tname}::remove_resource({op});
2501 assert({var}.has_value());"
2502 );
2503 results.push(format!("{tname}::Owned(*{var})"));
2504 }
2505 AbiVariant::GuestImportAsync => todo!(),
2506 AbiVariant::GuestExportAsync => todo!(),
2507 AbiVariant::GuestExportAsyncStackful => todo!(),
2508 },
2509 (Handle::Own(ty), false) => match self.variant {
2510 AbiVariant::GuestImport => {
2511 results.push(format!("wit::{RESOURCE_IMPORT_BASE_CLASS_NAME}{{{op}}}"))
2512 }
2513 AbiVariant::GuestExport => {
2514 let tmp = self.tmp();
2515 let var = self.tempname("obj", tmp);
2516 let tname = self.gen.type_name(
2517 &Type::Id(*ty),
2518 &self.namespace,
2519 Flavor::Argument(self.variant),
2520 );
2521 uwriteln!(
2522 self.src,
2523 "auto {var} = {tname}::Owned({tname}::ResourceRep({op}));"
2524 );
2525
2526 results.push(format!("std::move({var})"))
2527 }
2528 AbiVariant::GuestImportAsync => todo!(),
2529 AbiVariant::GuestExportAsync => todo!(),
2530 AbiVariant::GuestExportAsyncStackful => todo!(),
2531 },
2532 (Handle::Borrow(ty), true) => {
2533 let tname = self.gen.type_name(
2534 &Type::Id(*ty),
2535 &self.namespace,
2536 Flavor::Argument(self.variant),
2537 );
2538 results.push(format!("**{tname}::lookup_resource({op})"));
2539 }
2540 (Handle::Borrow(ty), false) => match self.variant {
2541 AbiVariant::GuestImport => results.push(op.clone()),
2542 AbiVariant::GuestExport => {
2543 let tname = self.gen.type_name(
2544 &Type::Id(*ty),
2545 &self.namespace,
2546 Flavor::Argument(self.variant),
2547 );
2548 results.push(format!("std::ref(*({tname} *){op})"));
2549 }
2550 AbiVariant::GuestImportAsync => todo!(),
2551 AbiVariant::GuestExportAsync => todo!(),
2552 AbiVariant::GuestExportAsyncStackful => todo!(),
2553 },
2554 }
2555 }
2556 abi::Instruction::TupleLower { tuple, .. } => {
2557 let op = &operands[0];
2558 for n in 0..tuple.types.len() {
2559 results.push(format!("std::get<{n}>({op})"));
2560 }
2561 }
2562 abi::Instruction::TupleLift { tuple, .. } => {
2563 let name = format!("tuple{}", self.tmp());
2564 uwrite!(self.src, "auto {name} = std::tuple<");
2565 self.src.push_str(
2566 &(tuple
2567 .types
2568 .iter()
2569 .map(|t| self.gen.type_name(t, &self.namespace, Flavor::InStruct)))
2570 .collect::<Vec<_>>()
2571 .join(", "),
2572 );
2573 self.src.push_str(">(");
2574 self.src.push_str(&operands.join(", "));
2575 self.src.push_str(");\n");
2576 results.push(format!("std::move({name})"));
2577 }
2578 abi::Instruction::FlagsLower { flags, ty, .. } => {
2579 match wit_bindgen_c::flags_repr(flags) {
2580 Int::U8 | Int::U16 | Int::U32 => {
2581 results.push(format!("((int32_t){})", operands.pop().unwrap()));
2582 }
2583 Int::U64 => {
2584 let name =
2585 self.gen
2586 .type_name(&Type::Id(*ty), &self.namespace, Flavor::InStruct);
2587 let tmp = self.tmp();
2588 let tempname = self.tempname("flags", tmp);
2589 uwriteln!(self.src, "{name} {tempname} = {};", operands[0]);
2590 results.push(format!("(int32_t)(((uint64_t){tempname}) & 0xffffffff)"));
2591 results.push(format!(
2592 "(int32_t)((((uint64_t){tempname}) >> 32) & 0xffffffff)"
2593 ));
2594 }
2595 }
2596 }
2597 abi::Instruction::FlagsLift { flags, ty, .. } => {
2598 let typename =
2599 self.gen
2600 .type_name(&Type::Id(*ty), &self.namespace, Flavor::InStruct);
2601 match wit_bindgen_c::flags_repr(flags) {
2602 Int::U8 | Int::U16 | Int::U32 => {
2603 results.push(format!("(({typename}){})", operands.pop().unwrap()));
2604 }
2605 Int::U64 => {
2606 let op0 = &operands[0];
2607 let op1 = &operands[1];
2608 results.push(format!(
2609 "(({typename})(({op0}) | (((uint64_t)({op1})) << 32)))"
2610 ));
2611 }
2612 }
2613 }
2614 abi::Instruction::VariantPayloadName => {
2615 let name = format!("payload{}", self.tmp());
2616 results.push(name.clone());
2617 self.payloads.push(name);
2618 }
2619 abi::Instruction::VariantLower {
2620 variant,
2621 results: result_types,
2622 ty: var_ty,
2623 name: _var_name,
2624 ..
2625 } => {
2626 let blocks = self
2627 .blocks
2628 .drain(self.blocks.len() - variant.cases.len()..)
2629 .collect::<Vec<_>>();
2630 let payloads = self
2631 .payloads
2632 .drain(self.payloads.len() - variant.cases.len()..)
2633 .collect::<Vec<_>>();
2634
2635 let mut variant_results = Vec::with_capacity(result_types.len());
2636 for ty in result_types.iter() {
2637 let name = format!("variant{}", self.tmp());
2638 results.push(name.clone());
2639 self.src.push_str(wit_bindgen_c::wasm_type(*ty));
2640 self.src.push_str(" ");
2641 self.src.push_str(&name);
2642 self.src.push_str(";\n");
2643 variant_results.push(name);
2644 }
2645
2646 let expr_to_match = format!("({}).variants.index()", operands[0]);
2647 let elem_ns =
2648 self.gen
2649 .type_name(&Type::Id(*var_ty), &self.namespace, Flavor::InStruct);
2650
2651 uwriteln!(self.src, "switch ((int32_t) {}) {{", expr_to_match);
2652 for (i, ((case, (block, block_results)), payload)) in
2653 variant.cases.iter().zip(blocks).zip(payloads).enumerate()
2654 {
2655 uwriteln!(self.src, "case {}: {{", i);
2656 if let Some(ty) = case.ty.as_ref() {
2657 let ty = self.gen.type_name(ty, &self.namespace, Flavor::InStruct);
2658 let case = format!("{elem_ns}::{}", case.name.to_pascal_case());
2659 uwriteln!(
2660 self.src,
2661 "{} &{} = std::get<{case}>({}.variants).value;",
2662 ty,
2663 payload,
2664 operands[0],
2665 );
2666 }
2667
2668 self.src.push_str(&block);
2669
2670 for (name, result) in variant_results.iter().zip(&block_results) {
2671 uwriteln!(self.src, "{} = {};", name, result);
2672 }
2673 self.src.push_str("break;\n}\n");
2674 }
2675 self.src.push_str("}\n");
2676 }
2677 abi::Instruction::VariantLift { variant, ty, .. } => {
2678 let blocks = self
2679 .blocks
2680 .drain(self.blocks.len() - variant.cases.len()..)
2681 .collect::<Vec<_>>();
2682
2683 let ty = self
2684 .gen
2685 .type_name(&Type::Id(*ty), &self.namespace, Flavor::InStruct);
2686 let resultno = self.tmp();
2687 let result = format!("variant{resultno}");
2688
2689 uwriteln!(self.src, "{ty} {result};");
2690
2691 let op0 = &operands[0];
2692
2693 uwriteln!(self.src, "switch ({op0}) {{");
2694 for (i, (case, (block, block_results))) in
2695 variant.cases.iter().zip(blocks).enumerate()
2696 {
2697 let tp = case.name.clone().to_pascal_case();
2698 uwriteln!(self.src, "case {i}: {{ {block}");
2699 uwriteln!(
2700 self.src,
2701 "{result}.variants = {ty}::{tp}{{{}}};",
2702 move_if_necessary(&block_results.first().cloned().unwrap_or_default())
2703 );
2704 uwriteln!(self.src, "}} break;");
2705 }
2706 uwriteln!(self.src, "}}");
2707
2708 results.push(result);
2709 }
2710 abi::Instruction::EnumLower { .. } => results.push(format!("int32_t({})", operands[0])),
2711 abi::Instruction::EnumLift { ty, .. } => {
2712 let typename =
2713 self.gen
2714 .type_name(&Type::Id(*ty), &self.namespace, Flavor::InStruct);
2715 results.push(format!("({typename}){}", &operands[0]));
2716 }
2717 abi::Instruction::OptionLower {
2718 payload,
2719 results: result_types,
2720 ..
2721 } => {
2722 let (mut some, some_results) = self.blocks.pop().unwrap();
2723 let (mut none, none_results) = self.blocks.pop().unwrap();
2724 let some_payload = self.payloads.pop().unwrap();
2725 let _none_payload = self.payloads.pop().unwrap();
2726
2727 for (i, ty) in result_types.iter().enumerate() {
2728 let tmp = self.tmp();
2729 let name = self.tempname("option", tmp);
2730 results.push(name.clone());
2731 self.src.push_str(wit_bindgen_c::wasm_type(*ty));
2732 self.src.push_str(" ");
2733 self.src.push_str(&name);
2734 self.src.push_str(";\n");
2735 let some_result = &some_results[i];
2736 uwriteln!(some, "{name} = {some_result};");
2737 let none_result = &none_results[i];
2738 uwriteln!(none, "{name} = {none_result};");
2739 }
2740
2741 let op0 = &operands[0];
2742 let flavor = if matches!(self.variant, AbiVariant::GuestImport) {
2743 Flavor::BorrowedArgument
2744 } else {
2745 Flavor::InStruct
2746 };
2747 let ty = self.gen.type_name(payload, &self.namespace, flavor);
2748 let bind_some = format!("{ty} {some_payload} = (std::move({op0})).value();");
2749
2750 uwrite!(
2751 self.src,
2752 "\
2753 if (({op0}).has_value()) {{
2754 {bind_some}
2755 {some}}} else {{
2756 {none}}}
2757 "
2758 );
2759 }
2760 abi::Instruction::OptionLift { payload, .. } => {
2761 let (some, some_results) = self.blocks.pop().unwrap();
2762 let (_none, none_results) = self.blocks.pop().unwrap();
2763 assert!(none_results.is_empty());
2764 assert!(some_results.len() == 1);
2765 let flavor = if self.gen.gen.opts.api_style == APIStyle::Symmetric
2766 && matches!(self.variant, AbiVariant::GuestExport)
2767 {
2768 Flavor::BorrowedArgument
2769 } else {
2770 Flavor::InStruct
2771 };
2772 let type_name = self.gen.type_name(payload, &self.namespace, flavor);
2773 let full_type = format!("std::optional<{type_name}>");
2774 let op0 = &operands[0];
2775
2776 let tmp = self.tmp();
2777 let resultname = self.tempname("option", tmp);
2778 uwriteln!(
2779 self.src,
2780 "{full_type} {resultname};
2781 if ({op0}) {{
2782 {some}
2783 {resultname}.emplace({});
2784 }}",
2785 some_results[0]
2786 );
2787 results.push(format!("std::move({resultname})"));
2788 }
2789 abi::Instruction::ResultLower {
2790 results: result_types,
2791 result,
2792 ..
2793 } => {
2794 let (mut err, err_results) = self.blocks.pop().unwrap();
2795 let (mut ok, ok_results) = self.blocks.pop().unwrap();
2796 let err_payload = self.payloads.pop().unwrap();
2797 let ok_payload = self.payloads.pop().unwrap();
2798
2799 for (i, ty) in result_types.iter().enumerate() {
2800 let tmp = self.tmp();
2801 let name = self.tempname("result", tmp);
2802 results.push(name.clone());
2803 self.src.push_str(wit_bindgen_c::wasm_type(*ty));
2804 self.src.push_str(" ");
2805 self.src.push_str(&name);
2806 self.src.push_str(";\n");
2807 let ok_result = &ok_results[i];
2808 uwriteln!(ok, "{name} = {ok_result};");
2809 let err_result = &err_results[i];
2810 uwriteln!(err, "{name} = {err_result};");
2811 }
2812
2813 let op0 = &operands[0];
2814 let ok_ty = self.gen.optional_type_name(
2815 result.ok.as_ref(),
2816 &self.namespace,
2817 Flavor::InStruct,
2818 );
2819 let err_ty = self.gen.optional_type_name(
2820 result.err.as_ref(),
2821 &self.namespace,
2822 Flavor::InStruct,
2823 );
2824 let bind_ok = if let Some(_ok) = result.ok.as_ref() {
2825 format!("{ok_ty} {ok_payload} = std::move({op0}).value();")
2826 } else {
2827 String::new()
2828 };
2829 let bind_err = if let Some(_err) = result.err.as_ref() {
2830 format!("{err_ty} {err_payload} = std::move({op0}).error();")
2831 } else {
2832 String::new()
2833 };
2834
2835 uwrite!(
2836 self.src,
2837 "\
2838 if (({op0}).has_value()) {{
2839 {bind_ok}
2840 {ok}}} else {{
2841 {bind_err}
2842 {err}}}
2843 "
2844 );
2845 }
2846 abi::Instruction::ResultLift { result, .. } => {
2847 let (mut err, err_results) = self.blocks.pop().unwrap();
2848 let (mut ok, ok_results) = self.blocks.pop().unwrap();
2849 let mut ok_result = String::new();
2850 let err_result;
2851 if result.ok.is_none() {
2852 ok.clear();
2853 } else {
2854 ok_result = move_if_necessary(&ok_results[0]);
2855 }
2856 if result.err.is_none() {
2857 err.clear();
2858 self.gen.gen.dependencies.needs_wit = true;
2859 err_result = String::from("wit::Void{}");
2860 } else {
2861 err_result = move_if_necessary(&err_results[0]);
2862 }
2863 let ok_type = self.gen.optional_type_name(
2864 result.ok.as_ref(),
2865 &self.namespace,
2866 Flavor::InStruct,
2867 );
2868 let err_type = result.err.as_ref().map_or(String::from("wit::Void"), |ty| {
2869 self.gen.type_name(ty, &self.namespace, Flavor::InStruct)
2870 });
2871 let full_type = format!("std::expected<{ok_type}, {err_type}>",);
2872 let err_type = "std::unexpected";
2873 let operand = &operands[0];
2874
2875 let tmp = self.tmp();
2876 let resultname = self.tempname("result", tmp);
2877 let ok_assign = if result.ok.is_some() {
2878 format!("{resultname}.emplace({ok_result});")
2879 } else {
2880 String::new()
2881 };
2882 uwriteln!(
2883 self.src,
2884 "{full_type} {resultname};
2885 if ({operand}==0) {{
2886 {ok}
2887 {ok_assign}
2888 }} else {{
2889 {err}
2890 {resultname}={err_type}{{{err_result}}};
2891 }}"
2892 );
2893 results.push(resultname);
2894 }
2895 abi::Instruction::CallWasm { name, sig } => {
2896 let module_name = self
2897 .gen
2898 .wasm_import_module
2899 .as_ref()
2900 .map(|e| {
2901 self.gen
2902 .gen
2903 .import_prefix
2904 .as_ref()
2905 .cloned()
2906 .unwrap_or_default()
2907 + e
2908 })
2909 .unwrap();
2910
2911 let func = self
2912 .gen
2913 .declare_import(&module_name, name, &sig.params, &sig.results);
2914
2915 if !sig.results.is_empty() {
2917 self.src.push_str("auto ret = ");
2918 results.push("ret".to_string());
2919 }
2920 self.src.push_str(&func);
2921 self.src.push_str("(");
2922 self.src.push_str(&operands.join(", "));
2923 self.src.push_str(");\n");
2924 }
2925 abi::Instruction::CallInterface { func, .. } => {
2926 self.let_results(if func.result.is_some() { 1 } else { 0 }, results);
2928 let (namespace, func_name_h) = self.gen.func_namespace_name(func, true, true);
2929 if matches!(func.kind, FunctionKind::Method(_)) {
2930 let this = operands.remove(0);
2931 uwrite!(self.src, "({this}).get().");
2932 } else {
2933 let mut relative = SourceWithState::default();
2934 relative.qualify(&namespace);
2935 self.push_str(&relative.src);
2936 }
2937 self.src.push_str(&func_name_h);
2938 self.push_str("(");
2939 self.push_str(&operands.join(", "));
2940 self.push_str(");\n");
2941 if self.needs_dealloc {
2942 uwriteln!(
2943 self.src,
2944 "for (auto i: _deallocate) {{ free(i); }}\n
2945 _deallocate.clear();"
2946 );
2947 }
2948 }
2949 abi::Instruction::Return { amt, func } => {
2950 match amt {
2951 0 => {}
2952 _ => {
2953 assert!(*amt == operands.len());
2954 match &func.kind {
2955 FunctionKind::Constructor(_)
2956 if self.gen.gen.opts.is_only_handle(self.variant) =>
2957 {
2958 if matches!(self.variant, AbiVariant::GuestExport) {
2960 self.src.push_str("this->index = ");
2961 } else {
2962 self.src.push_str("this->handle = ");
2963 }
2964 }
2965 _ => self.src.push_str("return "),
2966 }
2967 if let Some(CabiPostInformation {
2968 module: _,
2969 name: _cabi_post_name,
2970 ret_type: cabi_post_type,
2971 }) = self.cabi_post.as_ref()
2972 {
2973 self.src.push_str("wit::guest_owned<");
2974 self.src.push_str(cabi_post_type);
2975 self.src.push_str(">(");
2976 }
2977 if *amt == 1 {
2978 if operands[0].starts_with("std::move(") {
2979 self.src.push_str(&operands[0][9..]);
2981 } else {
2982 self.src.push_str(&operands[0]);
2983 }
2984 } else {
2985 todo!();
2986 }
2987 if let Some(CabiPostInformation {
2988 module: func_module,
2989 name: func_name,
2990 ret_type: _cabi_post_type,
2991 }) = self.cabi_post.as_ref()
2992 {
2993 let cabi_post_name = self.gen.declare_import(
2994 &format!("cabi_post_{func_module}"),
2995 func_name,
2996 &[WasmType::Pointer],
2997 &[],
2998 );
2999 self.src.push_str(&format!(", ret, {})", cabi_post_name));
3000 }
3001 if matches!(func.kind, FunctionKind::Constructor(_))
3002 && self.gen.gen.opts.is_only_handle(self.variant)
3003 {
3004 self.src.push_str(".into_handle()");
3007 }
3008 self.src.push_str(";\n");
3009 }
3010 }
3011 }
3012 abi::Instruction::Malloc { .. } => todo!(),
3013 abi::Instruction::GuestDeallocate { .. } => {
3014 uwriteln!(self.src, "free((void*) ({}));", operands[0]);
3015 }
3016 abi::Instruction::GuestDeallocateString => {
3017 uwriteln!(self.src, "if (({}) > 0) {{", operands[1]);
3018 uwriteln!(
3019 self.src,
3020 "wit::string::drop_raw((void*) ({}));",
3021 operands[0]
3022 );
3023 uwriteln!(self.src, "}}");
3024 }
3025 abi::Instruction::GuestDeallocateList { element } => {
3026 let (body, results) = self.blocks.pop().unwrap();
3027 assert!(results.is_empty());
3028 let tmp = self.tmp();
3029 let ptr = self.tempname("ptr", tmp);
3030 let len = self.tempname("len", tmp);
3031 uwriteln!(self.src, "uint8_t* {ptr} = {};", operands[0]);
3032 uwriteln!(self.src, "size_t {len} = {};", operands[1]);
3033 let i = self.tempname("i", tmp);
3034 uwriteln!(self.src, "for (size_t {i} = 0; {i} < {len}; {i}++) {{");
3035 let size = self.gen.sizes.size(element);
3036 uwriteln!(
3037 self.src,
3038 "uint8_t* base = {ptr} + {i} * {size};",
3039 size = size.format(POINTER_SIZE_EXPRESSION)
3040 );
3041 uwriteln!(self.src, "(void) base;");
3042 uwrite!(self.src, "{body}");
3043 uwriteln!(self.src, "}}");
3044 uwriteln!(self.src, "if ({len} > 0) {{");
3045 uwriteln!(self.src, "free((void*) ({ptr}));");
3046 uwriteln!(self.src, "}}");
3047 }
3048 abi::Instruction::GuestDeallocateVariant { blocks } => {
3049 let blocks = self
3050 .blocks
3051 .drain(self.blocks.len() - blocks..)
3052 .collect::<Vec<_>>();
3053
3054 uwriteln!(self.src, "switch ((int32_t) {}) {{", operands[0]);
3055 for (i, (block, results)) in blocks.into_iter().enumerate() {
3056 assert!(results.is_empty());
3057 uwriteln!(self.src, "case {}: {{", i);
3058 self.src.push_str(&block);
3059 self.src.push_str("break;\n}\n");
3060 }
3061 self.src.push_str("}\n");
3062 }
3063 abi::Instruction::PointerLoad { offset } => {
3064 let ptr_type = self.gen.gen.opts.ptr_type();
3065 self.load(ptr_type, *offset, operands, results)
3066 }
3067 abi::Instruction::LengthLoad { offset } => {
3068 self.load("size_t", *offset, operands, results)
3069 }
3070 abi::Instruction::PointerStore { offset } => {
3071 let ptr_type = self.gen.gen.opts.ptr_type();
3072 self.store(ptr_type, *offset, operands)
3073 }
3074 abi::Instruction::LengthStore { offset } => self.store("size_t", *offset, operands),
3075 abi::Instruction::FutureLower { .. } => todo!(),
3076 abi::Instruction::FutureLift { .. } => todo!(),
3077 abi::Instruction::StreamLower { .. } => todo!(),
3078 abi::Instruction::StreamLift { .. } => todo!(),
3079 abi::Instruction::ErrorContextLower { .. } => todo!(),
3080 abi::Instruction::ErrorContextLift { .. } => todo!(),
3081 abi::Instruction::Flush { amt } => {
3082 for i in operands.iter().take(*amt) {
3083 let tmp = self.tmp();
3084 let result = format!("result{}", tmp);
3085 uwriteln!(self.src, "auto {result} = {};", move_if_necessary(i));
3086 results.push(result);
3087 }
3088 }
3089 abi::Instruction::AsyncTaskReturn { .. } => todo!(),
3090 abi::Instruction::DropHandle { .. } => todo!(),
3091 }
3092 }
3093
3094 fn return_pointer(&mut self, size: ArchitectureSize, align: Alignment) -> Self::Operand {
3095 let tmp = self.tmp();
3096 let size_string = size.format(POINTER_SIZE_EXPRESSION);
3097 let tp = match align {
3098 Alignment::Bytes(bytes) => match bytes.get() {
3099 1 => "uint8_t",
3100 2 => "uint16_t",
3101 4 => "uint32_t",
3102 8 => "uint64_t",
3103 _ => todo!(),
3104 },
3105 Alignment::Pointer => "uintptr_t",
3106 };
3107 let static_var = if self.gen.in_guest_import {
3108 ""
3109 } else {
3110 "static "
3111 };
3112 uwriteln!(
3113 self.src,
3114 "{static_var}{tp} ret_area[({size_string}+sizeof({tp})-1)/sizeof({tp})];"
3115 );
3116 uwriteln!(
3117 self.src,
3118 "{} ptr{tmp} = ({0})(&ret_area);",
3119 self.gen.gen.opts.ptr_type(),
3120 );
3121
3122 format!("ptr{}", tmp)
3123 }
3124
3125 fn push_block(&mut self) {
3126 let prev = core::mem::take(&mut self.src);
3127 self.block_storage.push(prev);
3128 }
3129
3130 fn finish_block(&mut self, operands: &mut Vec<Self::Operand>) {
3131 let to_restore = self.block_storage.pop().unwrap();
3132 let src = core::mem::replace(&mut self.src, to_restore);
3133 self.blocks.push((src.into(), core::mem::take(operands)));
3134 }
3135
3136 fn sizes(&self) -> &wit_bindgen_core::wit_parser::SizeAlign {
3137 &self.gen.sizes
3138 }
3139
3140 fn is_list_canonical(
3141 &self,
3142 resolve: &Resolve,
3143 ty: &wit_bindgen_core::wit_parser::Type,
3144 ) -> bool {
3145 if !resolve.all_bits_valid(ty) {
3146 return false;
3147 }
3148 match ty {
3149 Type::Id(id) => !self.gen.gen.types.get(*id).has_resource,
3150 _ => true,
3151 }
3152 }
3153}
3154
3155enum SpecialMethod {
3157 None,
3158 ResourceDrop, ResourceNew, ResourceRep, Dtor, Allocate, }
3164
3165fn is_special_method(func: &Function) -> SpecialMethod {
3166 if matches!(func.kind, FunctionKind::Static(_)) {
3167 if func.name.starts_with("[resource-drop]") {
3168 SpecialMethod::ResourceDrop
3169 } else if func.name.starts_with("[resource-new]") {
3170 SpecialMethod::ResourceNew
3171 } else if func.name.starts_with("[resource-rep]") {
3172 SpecialMethod::ResourceRep
3173 } else if func.name.starts_with("[dtor]") {
3174 SpecialMethod::Dtor
3175 } else if func.name == "$alloc" {
3176 SpecialMethod::Allocate
3177 } else {
3178 SpecialMethod::None
3179 }
3180 } else {
3181 SpecialMethod::None
3182 }
3183}