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