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