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