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