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