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