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