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