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