1use anyhow::Result;
2use heck::{ToLowerCamelCase as _, ToSnakeCase as _, ToUpperCamelCase as _};
3use std::borrow::Cow;
4use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, hash_map};
5use std::fmt;
6use std::fmt::Write as _;
7use std::io::{self, Write as _};
8use std::iter;
9use std::mem;
10use std::process::Command;
11use std::str::FromStr;
12use std::thread;
13use wit_bindgen_core::abi::{
14 self, AbiVariant, Bindgen, Bitcast, FlatTypes, Instruction, LiftLower, WasmType,
15};
16use wit_bindgen_core::wit_parser::{
17 Alignment, ArchitectureSize, Docs, Enum, Flags, FlagsRepr, Function, FunctionKind, Handle, Int,
18 InterfaceId, Package, PackageName, Param, Record, Resolve, Result_, SizeAlign, Tuple, Type,
19 TypeDefKind, TypeId, TypeOwner, Variant, WorldId, WorldKey,
20};
21use wit_bindgen_core::{
22 AsyncFilterSet, Direction, Files, InterfaceGenerator as _, Ns, WorldGenerator, uwriteln,
23};
24
25const MAX_FLAT_PARAMS: usize = 16;
26
27const POINTER_SIZE_EXPRESSION: &str = "4";
28const VARIANT_PAYLOAD_NAME: &str = "payload";
29const ITER_BASE_POINTER: &str = "base";
30const ITER_ELEMENT: &str = "element";
31const IMPORT_RETURN_AREA: &str = "returnArea";
32const EXPORT_RETURN_AREA: &str = "exportReturnArea";
33const SYNC_EXPORT_PINNER: &str = "syncExportPinner";
34const PINNER: &str = "pinner";
35
36fn remote_pkg(name: &str) -> String {
38 let prefix = match name {
39 "types" => "witTypes",
40 "async" => "witAsync",
41 "runtime" => "witRuntime",
42 _ => unimplemented!(),
43 };
44 format!(r#"{prefix} "go.bytecodealliance.org/pkg/wit/{name}""#)
45}
46
47const REMOTE_PKG_VERSION: &str = "v0.2.3";
49
50pub fn remote_pkg_version() -> String {
53 format!("go.bytecodealliance.org/pkg {REMOTE_PKG_VERSION}")
54}
55
56fn escape_go_keyword(name: String) -> String {
59 match name.as_str() {
60 "break" | "case" | "chan" | "const" | "continue" | "default" | "defer" | "else"
61 | "fallthrough" | "for" | "func" | "go" | "goto" | "if" | "import" | "interface"
62 | "map" | "package" | "range" | "return" | "select" | "struct" | "switch" | "type"
63 | "var" => format!("{name}_"),
64 _ => name,
65 }
66}
67
68#[derive(Default, Debug, Copy, Clone)]
69pub enum Format {
70 #[default]
71 True,
72 False,
73}
74
75impl fmt::Display for Format {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 write!(
78 f,
79 "{}",
80 match self {
81 Self::True => "true",
82 Self::False => "false",
83 }
84 )
85 }
86}
87
88impl FromStr for Format {
89 type Err = String;
90
91 fn from_str(s: &str) -> Result<Format, String> {
92 match s {
93 "true" => Ok(Format::True),
94 "false" => Ok(Format::False),
95 _ => Err(format!("expected `true` or `false`; got `{s}`")),
96 }
97 }
98}
99
100#[derive(Default, Debug, Clone)]
101#[cfg_attr(feature = "clap", derive(clap::Parser))]
102pub struct Opts {
103 #[cfg_attr(
106 feature = "clap",
107 arg(
108 long,
109 default_value = "true",
110 default_missing_value = "true",
111 num_args = 0..=1,
112 require_equals = true,
113 )
114 )]
115 pub format: Format,
116
117 #[cfg_attr(feature = "clap", clap(flatten))]
118 pub async_: AsyncFilterSet,
119
120 #[cfg_attr(feature = "clap", clap(long))]
123 pub generate_stubs: bool,
124
125 #[cfg_attr(feature = "clap", clap(long))]
129 pub pkg_name: Option<String>,
130
131 #[cfg_attr(feature = "clap", clap(long, requires = "pkg_name"))]
138 pub export_pkg_name: Option<String>,
139
140 #[cfg_attr(feature = "clap", clap(long))]
144 pub print_remote_pkg_version: bool,
145
146 #[cfg_attr(feature = "clap", clap(long))]
153 pub include_versions: bool,
154}
155
156impl Opts {
157 pub fn build(&self) -> Box<dyn WorldGenerator> {
158 Box::new(Go {
159 opts: self.clone(),
160 ..Go::default()
161 })
162 }
163}
164
165#[derive(Default)]
166struct InterfaceData {
167 code: String,
168 imports: BTreeSet<String>,
169 need_unsafe: bool,
170 need_runtime: bool,
171 need_math: bool,
172}
173
174impl InterfaceData {
175 fn extend(&mut self, data: InterfaceData) {
176 self.code.push_str(&data.code);
177 self.imports.extend(data.imports);
178 self.need_unsafe |= data.need_unsafe;
179 self.need_runtime |= data.need_runtime;
180 self.need_math |= data.need_math;
181 }
182
183 fn imports(&self) -> String {
184 self.imports
185 .iter()
186 .map(|s| s.to_string())
187 .chain(self.need_unsafe.then(|| r#""unsafe""#.into()))
188 .chain(self.need_runtime.then(|| r#""runtime""#.into()))
189 .chain(self.need_math.then(|| r#""math""#.into()))
190 .collect::<Vec<_>>()
191 .join("\n")
192 }
193
194 fn from_generator_and_code(generator: FunctionGenerator<'_>, code: String) -> Self {
195 Self {
196 code,
197 imports: generator.imports,
198 need_unsafe: generator.need_unsafe,
199 need_runtime: generator.need_pinner,
200 need_math: generator.need_math,
201 }
202 }
203}
204
205impl From<InterfaceGenerator<'_>> for InterfaceData {
206 fn from(generator: InterfaceGenerator<'_>) -> Self {
207 Self {
208 code: generator.src,
209 imports: generator.imports,
210 need_unsafe: generator.need_unsafe,
211 need_runtime: generator.need_runtime,
212 need_math: false,
213 }
214 }
215}
216
217#[derive(Default)]
218struct Go {
219 opts: Opts,
220 src: String,
221 sizes: SizeAlign,
222 return_area_size: ArchitectureSize,
223 return_area_align: Alignment,
224 imports: BTreeSet<String>,
225 tuples: BTreeSet<usize>,
226 need_option: bool,
227 need_result: bool,
228 need_math: bool,
229 need_unit: bool,
230 need_future: bool,
231 need_stream: bool,
232 need_unsafe: bool,
233 interface_names: HashMap<InterfaceId, WorldKey>,
234 interfaces: BTreeMap<String, InterfaceData>,
235 export_interfaces: BTreeMap<String, InterfaceData>,
236 types: HashSet<(String, TypeId)>,
238 resources: HashMap<TypeId, Direction>,
239 futures_and_streams: HashMap<(TypeId, bool), Option<WorldKey>>,
240 generated_futures_and_streams: HashSet<FutureStreamDedup>,
242}
243
244impl Go {
245 fn mod_pkg(&self, for_export: bool, name: &str) -> String {
247 let prefix = for_export
248 .then_some(())
249 .and(self.opts.export_pkg_name.as_deref())
250 .or(self.opts.pkg_name.as_deref())
251 .unwrap_or("wit_component");
252 format!(r#""{prefix}/{name}""#)
253 }
254
255 fn package_for_owner(
256 &mut self,
257 resolve: &Resolve,
258 owner: Option<&WorldKey>,
259 id: TypeId,
260 local: Option<&WorldKey>,
261 in_import: bool,
262 imports: &mut BTreeSet<String>,
263 ) -> String {
264 let exported = self.has_exported_resource(resolve, Type::Id(id));
265
266 if local == owner && (exported ^ in_import) {
267 String::new()
268 } else {
269 let package = self.go_package_name(resolve, owner);
270 let package = if exported {
271 format!("export_{package}")
272 } else {
273 package
274 };
275 let prefix = format!("{package}.");
276 imports.insert(self.mod_pkg(exported, &package));
277 prefix
278 }
279 }
280
281 fn package(
282 &mut self,
283 resolve: &Resolve,
284 id: TypeId,
285 local: Option<&WorldKey>,
286 in_import: bool,
287 imports: &mut BTreeSet<String>,
288 ) -> String {
289 let ty = &resolve.types[id];
290 let owner = match ty.owner {
291 TypeOwner::World(_) => None,
292 TypeOwner::Interface(id) => Some(
293 self.interface_names
294 .get(&id)
295 .cloned()
296 .unwrap_or(WorldKey::Interface(id)),
297 ),
298 TypeOwner::None => unreachable!(),
299 };
300
301 self.package_for_owner(resolve, owner.as_ref(), id, local, in_import, imports)
302 }
303
304 fn type_name(
305 &mut self,
306 resolve: &Resolve,
307 ty: Type,
308 local: Option<&WorldKey>,
309 in_import: bool,
310 imports: &mut BTreeSet<String>,
311 ) -> String {
312 match ty {
313 Type::Bool => "bool".into(),
314 Type::U8 => "uint8".into(),
315 Type::S8 => "int8".into(),
316 Type::U16 => "uint16".into(),
317 Type::S16 => "int16".into(),
318 Type::U32 => "uint32".into(),
319 Type::S32 => "int32".into(),
320 Type::U64 => "uint64".into(),
321 Type::S64 => "int64".into(),
322 Type::F32 => "float32".into(),
323 Type::F64 => "float64".into(),
324 Type::Char => "rune".into(),
325 Type::String => "string".into(),
326 Type::Id(id) => {
327 let ty = &resolve.types[id];
328 match &ty.kind {
329 TypeDefKind::Record(_)
330 | TypeDefKind::Flags(_)
331 | TypeDefKind::Variant(_)
332 | TypeDefKind::Enum(_)
333 | TypeDefKind::Resource => {
334 let package = self.package(resolve, id, local, in_import, imports);
335 let name = ty.name.as_ref().unwrap().to_upper_camel_case();
336 format!("{package}{name}")
337 }
338 TypeDefKind::Handle(Handle::Own(ty) | Handle::Borrow(ty)) => {
339 let name =
340 self.type_name(resolve, Type::Id(*ty), local, in_import, imports);
341 format!("*{name}")
342 }
343 TypeDefKind::Option(ty) => {
344 imports.insert(remote_pkg("types"));
345 let ty = self.type_name(resolve, *ty, local, in_import, imports);
346 format!("witTypes.Option[{ty}]")
347 }
348 TypeDefKind::List(ty) => {
349 let ty = self.type_name(resolve, *ty, local, in_import, imports);
350 format!("[]{ty}")
351 }
352 TypeDefKind::Result(result) => {
353 imports.insert(remote_pkg("types"));
354 let ok_type = result
355 .ok
356 .map(|ty| self.type_name(resolve, ty, local, in_import, imports))
357 .unwrap_or_else(|| {
358 self.need_unit = true;
359 "witTypes.Unit".into()
360 });
361 let err_type = result
362 .err
363 .map(|ty| self.type_name(resolve, ty, local, in_import, imports))
364 .unwrap_or_else(|| {
365 self.need_unit = true;
366 "witTypes.Unit".into()
367 });
368 format!("witTypes.Result[{ok_type}, {err_type}]")
369 }
370 TypeDefKind::Tuple(tuple) => {
371 imports.insert(remote_pkg("types"));
372 let count = tuple.types.len();
373 if count > 16 {
374 todo!(
375 "tuples can not have a capacity greater than 16: {:?}",
376 ty.kind
377 )
378 }
379 self.tuples.insert(count);
380 let types = tuple
381 .types
382 .iter()
383 .map(|ty| self.type_name(resolve, *ty, local, in_import, imports))
384 .collect::<Vec<_>>()
385 .join(", ");
386 format!("witTypes.Tuple{count}[{types}]")
387 }
388 TypeDefKind::Future(ty) => {
389 self.need_future = true;
390 imports.insert(remote_pkg("types"));
391 let ty = ty
392 .map(|ty| self.type_name(resolve, ty, local, in_import, imports))
393 .unwrap_or_else(|| {
394 self.need_unit = true;
395 "witTypes.Unit".into()
396 });
397 format!("*witTypes.FutureReader[{ty}]")
398 }
399 TypeDefKind::Stream(ty) => {
400 self.need_stream = true;
401 imports.insert(remote_pkg("types"));
402 let ty = ty
403 .map(|ty| self.type_name(resolve, ty, local, in_import, imports))
404 .unwrap_or_else(|| {
405 self.need_unit = true;
406 "witTypes.Unit".into()
407 });
408 format!("*witTypes.StreamReader[{ty}]")
409 }
410 TypeDefKind::Type(ty) => {
411 self.type_name(resolve, *ty, local, in_import, imports)
412 }
413 TypeDefKind::Map(key, value) => {
414 let key = self.type_name(resolve, *key, local, in_import, imports);
415 let value = self.type_name(resolve, *value, local, in_import, imports);
416 format!("map[{key}]{value}")
417 }
418 _ => todo!("{:?}", ty.kind),
419 }
420 }
421 _ => todo!("{ty:?}"),
422 }
423 }
424
425 #[expect(clippy::too_many_arguments, reason = "required context codegen")]
426 fn future_or_stream(
427 &mut self,
428 resolve: &Resolve,
429 ty: TypeId,
430 index: usize,
431 in_import: bool,
432 imported_type: bool,
433 interface: Option<&WorldKey>,
434 func_name: &str,
435 ) -> InterfaceData {
436 let prefix = if in_import { "" } else { "[export]" };
437
438 let module = format!(
439 "{prefix}{}",
440 interface
441 .as_ref()
442 .map(|name| resolve.name_world_key(name))
443 .unwrap_or_else(|| "$root".into())
444 );
445
446 let (payload_ty, kind, count) = match &resolve.types[ty].kind {
447 TypeDefKind::Future(ty) => (*ty, "future", ""),
448 TypeDefKind::Stream(ty) => (*ty, "stream", ", count uint32"),
449 _ => unreachable!(),
450 };
451
452 let upper_kind = kind.to_upper_camel_case();
453
454 let mut data = InterfaceData {
455 need_unsafe: true,
456 ..InterfaceData::default()
457 };
458 data.imports.insert(remote_pkg("types"));
459
460 let (payload, snake) = if let Some(ty) = payload_ty {
461 (
462 self.type_name(resolve, ty, interface, imported_type, &mut data.imports),
463 self.mangle_name(resolve, ty, interface),
464 )
465 } else {
466 self.need_unit = true;
467 ("witTypes.Unit".into(), "unit".into())
468 };
469 let camel = snake.to_upper_camel_case();
470
471 let abi = self.sizes.record(payload_ty.as_ref());
472 let size = abi.size.format(POINTER_SIZE_EXPRESSION);
473 let align = abi.align.format(POINTER_SIZE_EXPRESSION);
474
475 let (lift, lift_name, lower, lower_name) = match payload_ty {
478 None => (
479 format!(
480 "func wasm_{kind}_lift_{snake}(src unsafe.Pointer) {payload} {{
481 return witTypes.Unit{{}}
482}}
483"
484 ),
485 format!("wasm_{kind}_lift_{snake}"),
486 String::new(),
487 "nil".to_string(),
488 ),
489 Some(Type::U8 | Type::S8) => (
490 String::new(),
491 "nil".to_string(),
492 String::new(),
493 "nil".to_string(),
494 ),
495 Some(ty) => {
496 data.need_runtime = true;
497
498 let mut generator = FunctionGenerator::new(
499 self,
500 None,
501 None,
502 interface,
503 "INVALID",
504 Vec::new(),
505 false,
506 imported_type,
507 );
508 generator.collect_lifters = true;
509
510 let lift_result =
511 abi::lift_from_memory(resolve, &mut generator, "src".to_string(), &ty);
512 let lift = mem::take(&mut generator.src);
513
514 abi::lower_to_memory(
515 resolve,
516 &mut generator,
517 "dst".to_string(),
518 "value".to_string(),
519 &ty,
520 );
521
522 let lifter_count = generator.lifter_count;
523 let (prefix, suffix) = if lifter_count > 0 {
524 (
525 format!("lifters := make([]func(), 0, {lifter_count})\n"),
526 "\nreturn func() {
527 for _, lifter := range lifters {
528 lifter()
529 }
530}",
531 )
532 } else {
533 (String::new(), "\nreturn func() {}")
534 };
535
536 let lower = mem::take(&mut generator.src);
537 data.extend(InterfaceData::from_generator_and_code(
538 generator,
539 String::new(),
540 ));
541
542 (
543 format!(
544 "func wasm_{kind}_lift_{snake}(src unsafe.Pointer) {payload} {{
545 {lift}
546 return {lift_result}
547}}
548"
549 ),
550 format!("wasm_{kind}_lift_{snake}"),
551 format!(
552 "func wasm_{kind}_lower_{snake}(
553 pinner *runtime.Pinner,
554 value {payload},
555 dst unsafe.Pointer,
556) func() {{
557 {prefix}{lower}{suffix}
558}}
559"
560 ),
561 format!("wasm_{kind}_lower_{snake}"),
562 )
563 }
564 };
565
566 data.code = format!(
567 r#"
568//go:wasmimport {module} [{kind}-new-{index}]{func_name}
569func wasm_{kind}_new_{snake}() uint64
570
571//go:wasmimport {module} [async-lower][{kind}-read-{index}]{func_name}
572func wasm_{kind}_read_{snake}(handle int32, item unsafe.Pointer{count}) uint32
573
574//go:wasmimport {module} [async-lower][{kind}-write-{index}]{func_name}
575func wasm_{kind}_write_{snake}(handle int32, item unsafe.Pointer{count}) uint32
576
577//go:wasmimport {module} [{kind}-drop-readable-{index}]{func_name}
578func wasm_{kind}_drop_readable_{snake}(handle int32)
579
580//go:wasmimport {module} [{kind}-drop-writable-{index}]{func_name}
581func wasm_{kind}_drop_writable_{snake}(handle int32)
582
583{lift}
584
585{lower}
586
587var wasm_{kind}_vtable_{snake} = witTypes.{upper_kind}Vtable[{payload}]{{
588 Size: {size},
589 Align: {align},
590 Read: wasm_{kind}_read_{snake},
591 Write: wasm_{kind}_write_{snake},
592 CancelRead: nil,
593 CancelWrite: nil,
594 DropReadable: wasm_{kind}_drop_readable_{snake},
595 DropWritable: wasm_{kind}_drop_writable_{snake},
596 Lift: {lift_name},
597 Lower: {lower_name},
598}}
599
600func Make{upper_kind}{camel}() (*witTypes.{upper_kind}Writer[{payload}], *witTypes.{upper_kind}Reader[{payload}]) {{
601 pair := wasm_{kind}_new_{snake}()
602 return witTypes.Make{upper_kind}Writer[{payload}](&wasm_{kind}_vtable_{snake}, int32(pair >> 32)),
603 witTypes.Make{upper_kind}Reader[{payload}](&wasm_{kind}_vtable_{snake}, int32(pair & 0xFFFFFFFF))
604}}
605
606func Lift{upper_kind}{camel}(handle int32) *witTypes.{upper_kind}Reader[{payload}] {{
607 return witTypes.Make{upper_kind}Reader[{payload}](&wasm_{kind}_vtable_{snake}, handle)
608}}
609"#
610 );
611
612 data
613 }
614
615 fn mangle_name(&self, resolve: &Resolve, ty: Type, local: Option<&WorldKey>) -> String {
616 match ty {
620 Type::Bool => "bool".into(),
621 Type::U8 => "u8".into(),
622 Type::U16 => "u16".into(),
623 Type::U32 => "u32".into(),
624 Type::U64 => "u64".into(),
625 Type::S8 => "s8".into(),
626 Type::S16 => "s16".into(),
627 Type::S32 => "s32".into(),
628 Type::S64 => "s64".into(),
629 Type::ErrorContext => "error_context".into(),
630 Type::F32 => "f32".into(),
631 Type::F64 => "f64".into(),
632 Type::Char => "char".into(),
633 Type::String => "string".into(),
634 Type::Id(id) => {
635 let ty = &resolve.types[id];
636 match &ty.kind {
637 TypeDefKind::Record(_)
638 | TypeDefKind::Variant(_)
639 | TypeDefKind::Enum(_)
640 | TypeDefKind::Flags(_)
641 | TypeDefKind::Resource => {
642 let package = match ty.owner {
643 TypeOwner::Interface(interface) => {
644 let key = self
645 .interface_names
646 .get(&interface)
647 .cloned()
648 .unwrap_or(WorldKey::Interface(interface));
649
650 if local == Some(&key) {
651 String::new()
652 } else {
653 format!(
654 "{}_",
655 self.go_package_name(
656 resolve,
657 Some(
658 &self
659 .interface_names
660 .get(&interface)
661 .cloned()
662 .unwrap_or(WorldKey::Interface(interface))
663 )
664 )
665 )
666 }
667 }
668 _ => String::new(),
669 };
670
671 let name = ty.name.as_ref().unwrap().to_snake_case();
672
673 format!("{package}{name}")
674 }
675 TypeDefKind::Option(some) => {
676 format!("option_{}", self.mangle_name(resolve, *some, local))
677 }
678 TypeDefKind::Result(result) => format!(
679 "result_{}_{}",
680 result
681 .ok
682 .map(|ty| self.mangle_name(resolve, ty, local))
683 .unwrap_or_else(|| "unit".into()),
684 result
685 .err
686 .map(|ty| self.mangle_name(resolve, ty, local))
687 .unwrap_or_else(|| "unit".into())
688 ),
689 TypeDefKind::List(ty) => {
690 format!("list_{}", self.mangle_name(resolve, *ty, local))
691 }
692 TypeDefKind::Tuple(tuple) => {
693 let types = tuple
694 .types
695 .iter()
696 .map(|ty| self.mangle_name(resolve, *ty, local))
697 .collect::<Vec<_>>()
698 .join("_");
699 format!("tuple{}_{types}", tuple.types.len())
700 }
701 TypeDefKind::Handle(Handle::Own(ty) | Handle::Borrow(ty)) => {
702 self.mangle_name(resolve, Type::Id(*ty), local)
703 }
704 TypeDefKind::Type(ty) => self.mangle_name(resolve, *ty, local),
705 TypeDefKind::Stream(ty) => {
706 format!(
707 "stream_{}",
708 ty.map(|ty| self.mangle_name(resolve, ty, local))
709 .unwrap_or_else(|| "unit".into())
710 )
711 }
712 TypeDefKind::Future(ty) => {
713 format!(
714 "future_{}",
715 ty.map(|ty| self.mangle_name(resolve, ty, local))
716 .unwrap_or_else(|| "unit".into())
717 )
718 }
719 TypeDefKind::Map(key, value) => {
720 format!(
721 "map_{}_{}",
722 self.mangle_name(resolve, *key, local),
723 self.mangle_name(resolve, *value, local)
724 )
725 }
726 kind => todo!("{kind:?}"),
727 }
728 }
729 }
730 }
731}
732
733impl WorldGenerator for Go {
734 fn uses_nominal_type_ids(&self) -> bool {
739 false
740 }
741
742 fn preprocess(&mut self, resolve: &Resolve, world: WorldId) -> Result<()> {
743 _ = world;
744 self.sizes.fill(resolve);
745 self.imports.insert(remote_pkg("runtime"));
746 Ok(())
747 }
748
749 fn import_interface(
750 &mut self,
751 resolve: &Resolve,
752 name: &WorldKey,
753 id: InterfaceId,
754 _files: &mut Files,
755 ) -> Result<()> {
756 self.interface_names.insert(id, name.clone());
757
758 let go_package_name = self.go_package_name(resolve, Some(name));
759 let mut data = {
760 let mut generator = InterfaceGenerator::new(self, resolve, Some((id, name)), true);
761 for (name, ty) in resolve.interfaces[id].types.iter() {
762 if generator
763 .generator
764 .types
765 .insert((go_package_name.clone(), *ty))
766 {
767 generator.define_type(name, *ty);
768 }
769 }
770 InterfaceData::from(generator)
771 };
772
773 for (_, func) in &resolve.interfaces[id].functions {
774 data.extend(self.import(resolve, func, Some(name)));
775 }
776 self.interfaces
777 .entry(go_package_name)
778 .or_default()
779 .extend(data);
780
781 Ok(())
782 }
783
784 fn import_funcs(
785 &mut self,
786 resolve: &Resolve,
787 _world: WorldId,
788 funcs: &[(&str, &Function)],
789 _files: &mut Files,
790 ) {
791 let mut data = InterfaceData::default();
792 for (_, func) in funcs {
793 data.extend(self.import(resolve, func, None));
794 }
795 self.interfaces
796 .entry(self.go_package_name(resolve, None))
797 .or_default()
798 .extend(data);
799 }
800
801 fn export_interface(
802 &mut self,
803 resolve: &Resolve,
804 name: &WorldKey,
805 id: InterfaceId,
806 _files: &mut Files,
807 ) -> Result<()> {
808 self.interface_names.insert(id, name.clone());
809
810 let go_package_name = self.go_package_name(resolve, Some(name));
811 for (type_name, ty) in &resolve.interfaces[id].types {
812 let exported = matches!(resolve.types[*ty].kind, TypeDefKind::Resource)
813 || self.has_exported_resource(resolve, Type::Id(*ty));
814
815 let mut generator = InterfaceGenerator::new(self, resolve, Some((id, name)), false);
816
817 if generator
818 .generator
819 .types
820 .insert((go_package_name.clone(), *ty))
821 || exported
822 {
823 generator.define_type(type_name, *ty);
824 }
825
826 let data = generator.into();
827
828 if exported {
829 &mut self.export_interfaces
830 } else {
831 &mut self.interfaces
832 }
833 .entry(go_package_name.clone())
834 .or_default()
835 .extend(data);
836 }
837
838 for (_, func) in &resolve.interfaces[id].functions {
839 let code = self.export(resolve, func, Some(name));
840 self.src.push_str(&code);
841 }
842
843 Ok(())
844 }
845
846 fn export_funcs(
847 &mut self,
848 resolve: &Resolve,
849 _world: WorldId,
850 funcs: &[(&str, &Function)],
851 _files: &mut Files,
852 ) -> Result<()> {
853 for (_, func) in funcs {
854 let code = self.export(resolve, func, None);
855 self.src.push_str(&code);
856 }
857 Ok(())
858 }
859
860 fn import_types(
861 &mut self,
862 resolve: &Resolve,
863 _world: WorldId,
864 types: &[(&str, TypeId)],
865 _files: &mut Files,
866 ) {
867 let package = self.go_package_name(resolve, None);
868 let mut generator = InterfaceGenerator::new(self, resolve, None, true);
869 for (name, ty) in types {
870 if generator.generator.types.insert((package.clone(), *ty)) {
871 generator.define_type(name, *ty);
872 }
873 }
874 let data = generator.into();
875 self.interfaces.entry(package).or_default().extend(data);
876 }
877
878 fn finish(&mut self, resolve: &Resolve, id: WorldId, files: &mut Files) -> Result<()> {
879 _ = (resolve, id);
880
881 let version = env!("CARGO_PKG_VERSION");
882 let packages = resolve
883 .packages
884 .iter()
885 .map(
886 |(
887 _,
888 Package {
889 name:
890 PackageName {
891 namespace,
892 name,
893 version,
894 },
895 ..
896 },
897 )| {
898 let version = if let Some(version) = version {
899 format!("@{version}")
900 } else {
901 String::new()
902 };
903 format!("// {namespace}:{name}{version}")
904 },
905 )
906 .collect::<Vec<_>>()
907 .join("\n");
908 let header = &format!(
909 "// Generated by `wit-bindgen` {version}. DO NOT EDIT!
910//
911// This code was generated from the following packages:
912{packages}
913"
914 );
915
916 let src = mem::take(&mut self.src);
917 let align = self.return_area_align.format(POINTER_SIZE_EXPRESSION);
918 let size = self.return_area_size.format(POINTER_SIZE_EXPRESSION);
919 let imports = self
920 .imports
921 .iter()
922 .map(|s| s.as_str())
923 .chain(self.need_math.then_some(r#""math""#))
924 .chain(self.need_unsafe.then_some(r#""unsafe""#))
925 .collect::<Vec<_>>()
926 .join("\n");
927
928 let (exports_file_path, package_name, main_func) = if self.opts.pkg_name.is_some() {
929 if self.opts.print_remote_pkg_version {
930 println!("{}", remote_pkg_version());
931 }
932 ("wit_exports/wit_exports.go", "wit_exports", "")
934 } else {
935 files.push(
936 "go.mod",
937 format!(
938 r#"module wit_component
939
940go 1.25
941
942require (
943 go.bytecodealliance.org/pkg {REMOTE_PKG_VERSION}
944)
945"#,
946 )
947 .as_bytes(),
948 );
949
950 (
953 "wit_exports.go",
954 "main",
955 r#"// Unused, but present to make the compiler happy
956func main() {}
957"#,
958 )
959 };
960
961 files.push(
962 exports_file_path,
963 &maybe_gofmt(
964 self.opts.format,
965 format!(
966 r#"{header}
967package {package_name}
968
969import (
970 "runtime"
971 {imports}
972)
973
974var staticPinner = runtime.Pinner{{}}
975var {EXPORT_RETURN_AREA} = uintptr(witRuntime.Allocate(&staticPinner, {size}, {align}))
976var {SYNC_EXPORT_PINNER} = runtime.Pinner{{}}
977
978{src}
979
980{main_func}
981"#
982 )
983 .as_bytes(),
984 ),
985 );
986
987 for (prefix, interfaces) in [("export_", &self.export_interfaces), ("", &self.interfaces)] {
988 for (name, data) in interfaces {
989 let imports = data.imports();
990 let code = &data.code;
991
992 files.push(
993 &format!("{prefix}{name}/wit_bindings.go"),
994 &maybe_gofmt(
995 self.opts.format,
996 format!(
997 "{header}
998package {prefix}{name}
999
1000import (
1001 {imports}
1002)
1003
1004{code}"
1005 )
1006 .as_bytes(),
1007 ),
1008 );
1009
1010 files.push(
1011 &format!("{prefix}{name}/empty.s"),
1012 r#"// This file exists for testing this package without WebAssembly,
1013// allowing empty function bodies with a //go:wasmimport directive.
1014// See https://pkg.go.dev/cmd/compile for more information."#
1015 .as_bytes(),
1016 );
1017 }
1018 }
1019
1020 Ok(())
1021 }
1022}
1023
1024impl Go {
1025 fn import(
1026 &mut self,
1027 resolve: &Resolve,
1028 func: &Function,
1029 interface: Option<&WorldKey>,
1030 ) -> InterfaceData {
1031 self.visit_futures_and_streams(true, resolve, func, interface);
1032
1033 let async_ = self.opts.async_.is_async(resolve, interface, func, true);
1034
1035 let (variant, prefix) = if async_ {
1036 (AbiVariant::GuestImportAsync, "[async-lower]")
1037 } else {
1038 (AbiVariant::GuestImport, "")
1039 };
1040
1041 let sig = resolve.wasm_signature(variant, func);
1042 let import_name = &func.name;
1043 let name = func.name.to_snake_case().replace('.', "_");
1044 let (camel, has_self) = func_declaration(resolve, func);
1045
1046 let module = match interface {
1047 Some(name) => resolve.name_world_key(name),
1048 None => "$root".to_string(),
1049 };
1050
1051 let params = sig
1052 .params
1053 .iter()
1054 .enumerate()
1055 .map(|(i, param)| format!("arg{i} {}", wasm_type(*param)))
1056 .collect::<Vec<_>>()
1057 .join(", ");
1058
1059 let results = match &sig.results[..] {
1060 [] => "",
1061 [result] => wasm_type(*result),
1062 _ => unreachable!(),
1063 };
1064
1065 let mut imports = BTreeSet::new();
1066 let go_params =
1067 self.func_params(resolve, func, interface, true, &mut imports, has_self, "");
1068 let go_results = self.func_results(resolve, func, interface, true, &mut imports);
1069
1070 let raw_name = format!("wasm_import_{name}");
1071
1072 let go_param_names = has_self
1073 .then(|| "self".to_string())
1074 .into_iter()
1075 .chain(
1076 func.params
1077 .iter()
1078 .skip(if has_self { 1 } else { 0 })
1079 .map(|Param { name, .. }| escape_go_keyword(name.to_lower_camel_case())),
1080 )
1081 .collect::<Vec<_>>();
1082
1083 let mut generator = FunctionGenerator::new(
1084 self,
1085 None,
1086 interface,
1087 interface,
1088 &raw_name,
1089 go_param_names.clone(),
1090 false,
1091 true,
1092 );
1093 generator.imports = imports;
1094
1095 let code = if async_ {
1096 generator.imports.insert(remote_pkg("async"));
1097
1098 let (lower, wasm_params) = if sig.indirect_params {
1099 generator.imports.insert(remote_pkg("runtime"));
1100
1101 let params_pointer = generator.locals.tmp("params");
1102 let abi = generator
1103 .generator
1104 .sizes
1105 .record(func.params.iter().map(|Param { ty, .. }| ty));
1106 let size = abi.size.format(POINTER_SIZE_EXPRESSION);
1107 let align = abi.align.format(POINTER_SIZE_EXPRESSION);
1108 let offsets = generator
1109 .generator
1110 .sizes
1111 .field_offsets(func.params.iter().map(|Param { ty, .. }| ty));
1112
1113 for (name, (offset, ty)) in go_param_names.iter().zip(offsets) {
1114 let offset = offset.format(POINTER_SIZE_EXPRESSION);
1115 abi::lower_to_memory(
1116 resolve,
1117 &mut generator,
1118 format!("unsafe.Add(unsafe.Pointer({params_pointer}), {offset})"),
1119 name.clone(),
1120 ty,
1121 );
1122 }
1123
1124 let code = mem::take(&mut generator.src);
1125 generator.need_pinner = true;
1126 (
1127 format!(
1128 "{params_pointer} := witRuntime.Allocate({PINNER}, {size}, {align})\n{code}"
1129 ),
1130 vec![format!("uintptr({params_pointer})")],
1131 )
1132 } else {
1133 let wasm_params = go_param_names
1134 .iter()
1135 .zip(&func.params)
1136 .flat_map(|(name, Param { ty, .. })| {
1137 abi::lower_flat(resolve, &mut generator, name.clone(), ty)
1138 })
1139 .collect();
1140 (mem::take(&mut generator.src), wasm_params)
1141 };
1142
1143 let wasm_params = wasm_params
1144 .iter()
1145 .map(|v| v.as_str())
1146 .chain(func.result.map(|_| IMPORT_RETURN_AREA))
1147 .collect::<Vec<_>>()
1148 .join(", ");
1149
1150 let lift = if let Some(ty) = func.result {
1151 let result = abi::lift_from_memory(
1152 resolve,
1153 &mut generator,
1154 IMPORT_RETURN_AREA.to_string(),
1155 &ty,
1156 );
1157 let code = mem::take(&mut generator.src);
1158 if let Type::Id(ty) = ty
1159 && let TypeDefKind::Tuple(tuple) = &resolve.types[ty].kind
1160 {
1161 let count = tuple.types.len();
1162 let tuple = generator.locals.tmp("tuple");
1163
1164 let results = (0..count)
1165 .map(|index| format!("{tuple}.F{index}"))
1166 .collect::<Vec<_>>()
1167 .join(", ");
1168
1169 format!(
1170 "{code}
1171{tuple} := {result}
1172return {results}"
1173 )
1174 } else {
1175 format!("{code}\nreturn {result}")
1176 }
1177 } else {
1178 String::new()
1179 };
1180
1181 format!(
1182 "{lower}
1183witAsync.SubtaskWait(uint32({raw_name}({wasm_params})))
1184{lift}
1185"
1186 )
1187 } else {
1188 abi::call(
1189 resolve,
1190 variant,
1191 LiftLower::LowerArgsLiftResults,
1192 func,
1193 &mut generator,
1194 false,
1195 );
1196 mem::take(&mut generator.src)
1197 };
1198
1199 let return_area = |generator: &mut FunctionGenerator<'_>,
1200 size: ArchitectureSize,
1201 align: Alignment| {
1202 generator.imports.insert(remote_pkg("runtime"));
1203 generator.need_pinner = true;
1204 let size = size.format(POINTER_SIZE_EXPRESSION);
1205 let align = align.format(POINTER_SIZE_EXPRESSION);
1206 format!(
1207 "{IMPORT_RETURN_AREA} := uintptr(witRuntime.Allocate({PINNER}, {size}, {align}))"
1208 )
1209 };
1210
1211 let return_area = if async_ && func.result.is_some() {
1212 let abi = generator.generator.sizes.record(func.result.as_ref());
1213 return_area(&mut generator, abi.size, abi.align)
1214 } else if !(async_ || generator.return_area_size.is_empty()) {
1215 let size = generator.return_area_size;
1216 let align = generator.return_area_align;
1217 return_area(&mut generator, size, align)
1218 } else {
1219 String::new()
1220 };
1221
1222 let pinner = if generator.need_pinner {
1223 format!(
1224 "{PINNER} := &runtime.Pinner{{}}
1225defer {PINNER}.Unpin()
1226"
1227 )
1228 } else {
1229 String::new()
1230 };
1231
1232 InterfaceData::from_generator_and_code(
1233 generator,
1234 format!(
1235 "
1236//go:wasmimport {module} {prefix}{import_name}
1237func {raw_name}({params}) {results}
1238
1239func {camel}({go_params}) {go_results} {{
1240 {pinner}
1241 {return_area}
1242 {code}
1243}}
1244"
1245 ),
1246 )
1247 }
1248
1249 fn export(
1250 &mut self,
1251 resolve: &Resolve,
1252 func: &Function,
1253 interface: Option<&WorldKey>,
1254 ) -> String {
1255 self.visit_futures_and_streams(false, resolve, func, interface);
1256
1257 let async_ = self.opts.async_.is_async(resolve, interface, func, false);
1258
1259 let (variant, prefix) = if async_ {
1260 (AbiVariant::GuestExportAsync, "[async-lift]")
1261 } else {
1262 (AbiVariant::GuestExport, "")
1263 };
1264
1265 let sig = resolve.wasm_signature(variant, func);
1266 let core_module_name = interface.map(|v| resolve.name_world_key(v));
1267 let export_name = func.legacy_core_export_name(core_module_name.as_deref());
1268 let name = self.func_name(resolve, interface, func);
1269
1270 let params = sig
1271 .params
1272 .iter()
1273 .enumerate()
1274 .map(|(i, param)| format!("arg{i} {}", wasm_type(*param)))
1275 .collect::<Vec<_>>()
1276 .join(", ");
1277
1278 let results = match &sig.results[..] {
1279 [] => "",
1280 [result] => wasm_type(*result),
1281 _ => unreachable!(),
1282 };
1283
1284 let unpin_params =
1285 sig.indirect_params || abi::guest_export_params_have_allocations(resolve, func);
1286
1287 let param_names = (0..sig.params.len()).map(|i| format!("arg{i}")).collect();
1288 let mut generator = FunctionGenerator::new(
1289 self,
1290 Some(&name),
1291 interface,
1292 None,
1293 "INVALID",
1294 param_names,
1295 unpin_params,
1296 false,
1297 );
1298 abi::call(
1299 resolve,
1300 variant,
1301 LiftLower::LiftArgsLowerResults,
1302 func,
1303 &mut generator,
1304 async_,
1305 );
1306 let code = generator.src;
1307 let imports = generator.imports;
1308 let need_unsafe = generator.need_unsafe;
1309 self.need_math |= generator.need_math;
1310 self.need_unsafe |= need_unsafe;
1311 self.imports.extend(imports);
1312
1313 let (pinner, other, start, end) = if async_ {
1314 self.imports.insert(remote_pkg("async"));
1315
1316 let module = match interface {
1317 Some(name) => resolve.name_world_key(name),
1318 None => "$root".to_string(),
1319 };
1320
1321 let function = &func.name;
1322
1323 let task_return_params = func
1324 .result
1325 .map(|ty| {
1326 let mut storage = vec![WasmType::I32; MAX_FLAT_PARAMS];
1327 let mut flat = FlatTypes::new(&mut storage);
1328 if resolve.push_flat(&ty, &mut flat) {
1329 flat.to_vec()
1330 } else {
1331 vec![WasmType::I32]
1332 }
1333 })
1334 .unwrap_or_default()
1335 .into_iter()
1336 .enumerate()
1337 .map(|(i, ty)| {
1338 let ty = wasm_type(ty);
1339 format!("arg{i} {ty}")
1340 })
1341 .collect::<Vec<_>>()
1342 .join(", ");
1343
1344 (
1345 if abi::guest_export_needs_post_return(resolve, func) {
1346 format!(
1347 "{PINNER} := &runtime.Pinner{{}}
1348 defer {PINNER}.Unpin()"
1349 )
1350 } else {
1351 String::new()
1352 },
1353 format!(
1354 "
1355
1356//go:wasmexport [callback]{prefix}{export_name}
1357func wasm_export_callback_{name}(event0 uint32, event1 uint32, event2 uint32) uint32 {{
1358 return witAsync.Callback(event0, event1, event2)
1359}}
1360
1361//go:wasmimport [export]{module} [task-return]{function}
1362func wasm_export_task_return_{name}({task_return_params})
1363"
1364 ),
1365 "return int32(witAsync.Run(func() {",
1366 "}))",
1367 )
1368 } else if abi::guest_export_needs_post_return(resolve, func) {
1369 (
1370 format!("{PINNER} := &{SYNC_EXPORT_PINNER}"),
1371 format!(
1372 "
1373
1374//go:wasmexport cabi_post_{export_name}
1375func wasm_export_post_return_{name}(result {results}) {{
1376 syncExportPinner.Unpin()
1377}}
1378"
1379 ),
1380 "",
1381 "",
1382 )
1383 } else {
1384 (String::new(), String::new(), "", "")
1385 };
1386
1387 if self.opts.generate_stubs {
1388 let (camel, has_self) = func_declaration(resolve, func);
1389
1390 let mut imports = BTreeSet::new();
1391 let params =
1392 self.func_params(resolve, func, interface, false, &mut imports, has_self, "_");
1393 let results = self.func_results(resolve, func, interface, false, &mut imports);
1394
1395 self.export_interfaces
1396 .entry(self.go_package_name(resolve, interface))
1397 .or_default()
1398 .extend(InterfaceData {
1399 code: format!(
1400 r#"
1401func {camel}({params}) {results} {{
1402 panic("not implemented")
1403}}
1404"#
1405 ),
1406 imports,
1407 ..InterfaceData::default()
1408 });
1409 }
1410
1411 format!(
1412 "
1413//go:wasmexport {prefix}{export_name}
1414func wasm_export_{name}({params}) {results} {{
1415 {start}
1416 {pinner}
1417 {code}
1418 {end}
1419}}{other}
1420"
1421 )
1422 }
1423
1424 #[expect(clippy::too_many_arguments, reason = "required context for codegen")]
1425 fn func_params(
1426 &mut self,
1427 resolve: &Resolve,
1428 func: &Function,
1429 interface: Option<&WorldKey>,
1430 in_import: bool,
1431 imports: &mut BTreeSet<String>,
1432 has_self: bool,
1433 prefix: &str,
1434 ) -> String {
1435 func.params
1436 .iter()
1437 .skip(if has_self { 1 } else { 0 })
1438 .map(|Param { name, ty, .. }| {
1439 let name = escape_go_keyword(name.to_lower_camel_case());
1440 let ty = self.type_name(resolve, *ty, interface, in_import, imports);
1441 format!("{prefix}{name} {ty}")
1442 })
1443 .collect::<Vec<_>>()
1444 .join(", ")
1445 }
1446
1447 fn func_results(
1448 &mut self,
1449 resolve: &Resolve,
1450 func: &Function,
1451 interface: Option<&WorldKey>,
1452 in_import: bool,
1453 imports: &mut BTreeSet<String>,
1454 ) -> String {
1455 if let Some(ty) = &func.result {
1456 if let Type::Id(id) = ty
1457 && let TypeDefKind::Tuple(tuple) = &resolve.types[*id].kind
1458 {
1459 let types = tuple
1460 .types
1461 .iter()
1462 .map(|ty| self.type_name(resolve, *ty, interface, in_import, imports))
1463 .collect::<Vec<_>>()
1464 .join(", ");
1465 format!("({types})")
1466 } else {
1467 self.type_name(resolve, *ty, interface, in_import, imports)
1468 }
1469 } else {
1470 String::new()
1471 }
1472 }
1473
1474 fn visit_futures_and_streams(
1475 &mut self,
1476 in_import: bool,
1477 resolve: &Resolve,
1478 func: &Function,
1479 interface: Option<&WorldKey>,
1480 ) {
1481 for (index, ty) in func
1482 .find_futures_and_streams(resolve)
1483 .into_iter()
1484 .enumerate()
1485 {
1486 let payload_type = match &resolve.types[ty].kind {
1487 TypeDefKind::Future(ty) => {
1488 self.need_future = true;
1489 ty
1490 }
1491 TypeDefKind::Stream(ty) => {
1492 self.need_stream = true;
1493 ty
1494 }
1495 _ => unreachable!(),
1496 };
1497
1498 let exported = payload_type
1499 .map(|ty| self.has_exported_resource(resolve, ty))
1500 .unwrap_or(false);
1501
1502 if let hash_map::Entry::Vacant(e) = self.futures_and_streams.entry((ty, exported)) {
1503 e.insert(interface.cloned());
1504
1505 let name = self.go_package_name(resolve, interface);
1506
1507 let kind = match &resolve.types[ty].kind {
1515 TypeDefKind::Future(_) => "future",
1516 TypeDefKind::Stream(_) => "stream",
1517 _ => unreachable!(),
1518 };
1519 let snake = payload_type
1520 .map(|ty| self.mangle_name(resolve, ty, interface))
1521 .unwrap_or_else(|| "unit".into());
1522
1523 if !self
1524 .generated_futures_and_streams
1525 .insert(FutureStreamDedup {
1526 in_import,
1527 is_exported: exported,
1528 pkg_name: name.clone(),
1529 mangled_name: format!("{kind}_{snake}"),
1530 })
1531 {
1532 continue;
1533 }
1534
1535 let data = self.future_or_stream(
1536 resolve,
1537 ty,
1538 index,
1539 in_import,
1540 in_import || !exported,
1541 interface,
1542 &func.name,
1543 );
1544
1545 if in_import || !exported {
1546 &mut self.interfaces
1547 } else {
1548 &mut self.export_interfaces
1549 }
1550 .entry(name)
1551 .or_default()
1552 .extend(data);
1553 }
1554 }
1555 }
1556
1557 fn has_exported_resource(&self, resolve: &Resolve, ty: Type) -> bool {
1558 any(resolve, ty, &|ty| {
1559 if let Type::Id(id) = ty
1560 && let TypeDefKind::Resource = &resolve.types[id].kind
1561 && let Direction::Export = self.resources.get(&id).unwrap()
1562 {
1563 true
1564 } else {
1565 false
1566 }
1567 })
1568 }
1569
1570 fn go_package_name(&self, resolve: &Resolve, interface: Option<&WorldKey>) -> String {
1571 let name = match interface {
1572 Some(WorldKey::Name(name)) => name.to_snake_case(),
1573 Some(WorldKey::Interface(id)) => {
1574 let interface = &resolve.interfaces[*id];
1575 let package = &resolve.packages[interface.package.unwrap()];
1576 let package_has_multiple_versions = resolve.packages.iter().any(|(_, p)| {
1577 p.name.namespace == package.name.namespace
1578 && p.name.name == package.name.name
1579 && p.name.version != package.name.version
1580 });
1581 let version = if package_has_multiple_versions || self.opts.include_versions {
1582 if let Some(version) = &package.name.version {
1583 format!("{}_", version.to_string().replace(['.', '-', '+'], "_"))
1584 } else {
1585 String::new()
1586 }
1587 } else {
1588 String::new()
1589 };
1590 let namespace = package.name.namespace.to_snake_case();
1591 let package = package.name.name.to_snake_case();
1592 let interface = interface.name.as_ref().unwrap().to_snake_case();
1593 format!("{namespace}_{package}_{version}{interface}")
1594 }
1595 None => "wit_world".into(),
1596 };
1597
1598 escape_go_keyword(name)
1599 }
1600
1601 fn func_name(
1602 &self,
1603 resolve: &Resolve,
1604 interface: Option<&WorldKey>,
1605 func: &Function,
1606 ) -> String {
1607 let prefix = self.go_package_name(resolve, interface);
1608 let name = func.name.to_snake_case().replace('.', "_");
1609
1610 format!("{prefix}_{name}")
1611 }
1612}
1613
1614struct FunctionGenerator<'a> {
1615 generator: &'a mut Go,
1616 name: Option<&'a str>,
1617 interface: Option<&'a WorldKey>,
1618 interface_for_types: Option<&'a WorldKey>,
1619 function_to_call: &'a str,
1620 param_names: Vec<String>,
1621 unpin_params: bool,
1622 in_import: bool,
1623 locals: Ns,
1624 src: String,
1625 block_storage: Vec<String>,
1626 blocks: Vec<(String, Vec<String>)>,
1627 need_unsafe: bool,
1628 need_pinner: bool,
1629 need_math: bool,
1630 collect_lifters: bool,
1631 lifter_count: u32,
1632 return_area_size: ArchitectureSize,
1633 return_area_align: Alignment,
1634 imports: BTreeSet<String>,
1635}
1636
1637impl<'a> FunctionGenerator<'a> {
1638 #[expect(clippy::too_many_arguments, reason = "required context for codegen")]
1639 fn new(
1640 generator: &'a mut Go,
1641 name: Option<&'a str>,
1642 interface: Option<&'a WorldKey>,
1643 interface_for_types: Option<&'a WorldKey>,
1644 function_to_call: &'a str,
1645 param_names: Vec<String>,
1646 unpin_params: bool,
1647 in_import: bool,
1648 ) -> Self {
1649 let mut locals = Ns::default();
1650 for name in ¶m_names {
1651 locals.insert(name).unwrap();
1652 }
1653
1654 Self {
1655 generator,
1656 name,
1657 interface,
1658 interface_for_types,
1659 function_to_call,
1660 param_names,
1661 unpin_params,
1662 in_import,
1663 locals,
1664 src: String::new(),
1665 block_storage: Vec::new(),
1666 blocks: Vec::new(),
1667 need_unsafe: false,
1668 need_pinner: false,
1669 need_math: false,
1670 collect_lifters: false,
1671 lifter_count: 0,
1672 return_area_size: ArchitectureSize::default(),
1673 return_area_align: Alignment::default(),
1674 imports: BTreeSet::new(),
1675 }
1676 }
1677
1678 fn type_name(&mut self, resolve: &Resolve, ty: Type) -> String {
1679 self.generator.type_name(
1680 resolve,
1681 ty,
1682 self.interface_for_types,
1683 self.in_import,
1684 &mut self.imports,
1685 )
1686 }
1687
1688 fn package_for_owner(
1689 &mut self,
1690 resolve: &Resolve,
1691 owner: Option<&WorldKey>,
1692 ty: TypeId,
1693 ) -> String {
1694 self.generator.package_for_owner(
1695 resolve,
1696 owner,
1697 ty,
1698 self.interface_for_types,
1699 self.in_import,
1700 &mut self.imports,
1701 )
1702 }
1703}
1704
1705impl Bindgen for FunctionGenerator<'_> {
1706 type Operand = String;
1707
1708 fn sizes(&self) -> &SizeAlign {
1709 &self.generator.sizes
1710 }
1711
1712 fn push_block(&mut self) {
1713 let prev = mem::take(&mut self.src);
1714 self.block_storage.push(prev);
1715 }
1716
1717 fn finish_block(&mut self, operands: &mut Vec<String>) {
1718 let to_restore = self.block_storage.pop().unwrap();
1719 let src = mem::replace(&mut self.src, to_restore);
1720 self.blocks.push((src, mem::take(operands)));
1721 }
1722
1723 fn return_pointer(&mut self, size: ArchitectureSize, align: Alignment) -> String {
1724 if self.in_import {
1725 self.return_area_size = self.return_area_size.max(size);
1726 self.return_area_align = self.return_area_align.max(align);
1727
1728 if !self.return_area_size.is_empty() {
1729 self.need_pinner = true;
1730 self.imports.insert(remote_pkg("runtime"));
1731 }
1732
1733 IMPORT_RETURN_AREA.into()
1734 } else {
1735 self.generator.return_area_size = self.generator.return_area_size.max(size);
1736 self.generator.return_area_align = self.generator.return_area_align.max(align);
1737 EXPORT_RETURN_AREA.into()
1738 }
1739 }
1740
1741 fn is_list_canonical(&self, _: &Resolve, ty: &Type) -> bool {
1742 matches!(
1743 ty,
1744 Type::U8
1745 | Type::S8
1746 | Type::U16
1747 | Type::S16
1748 | Type::U32
1749 | Type::S32
1750 | Type::U64
1751 | Type::S64
1752 | Type::F32
1753 | Type::F64
1754 )
1755 }
1756
1757 fn emit(
1758 &mut self,
1759 resolve: &Resolve,
1760 instruction: &Instruction<'_>,
1761 operands: &mut Vec<String>,
1762 results: &mut Vec<String>,
1763 ) {
1764 let store = |me: &mut Self, src, pointer, offset: &ArchitectureSize, ty| {
1765 me.need_unsafe = true;
1766 let offset = offset.format(POINTER_SIZE_EXPRESSION);
1767 uwriteln!(
1768 me.src,
1769 "*(*{ty})(unsafe.Add(unsafe.Pointer({pointer}), {offset})) = {src}"
1770 );
1771 };
1772 let load = |me: &mut Self,
1773 results: &mut Vec<String>,
1774 pointer,
1775 offset: &ArchitectureSize,
1776 ty,
1777 cast: &dyn Fn(String) -> String| {
1778 me.need_unsafe = true;
1779 let offset = offset.format(POINTER_SIZE_EXPRESSION);
1780 results.push(cast(format!(
1781 "*(*{ty})(unsafe.Add(unsafe.Pointer({pointer}), {offset}))"
1782 )));
1783 };
1784
1785 match instruction {
1786 Instruction::GetArg { nth } => results.push(self.param_names[*nth].clone()),
1787 Instruction::StringLower { .. } => {
1788 self.need_pinner = true;
1789 self.need_unsafe = true;
1790 let string = &operands[0];
1791 let utf8 = self.locals.tmp("utf8");
1792 uwriteln!(
1793 self.src,
1794 "{utf8} := unsafe.Pointer(unsafe.StringData({string}))\n\
1795 {PINNER}.Pin({utf8})"
1796 );
1797 results.push(format!("uintptr({utf8})"));
1798 results.push(format!("uint32(len({string}))"));
1799 }
1800 Instruction::StringLift { .. } => {
1801 self.need_unsafe = true;
1802 let pointer = &operands[0];
1803 let length = &operands[1];
1804 let value = self.locals.tmp("value");
1805 uwriteln!(
1806 self.src,
1807 "{value} := unsafe.String((*uint8)(unsafe.Pointer({pointer})), {length})"
1808 );
1809 results.push(value)
1810 }
1811 Instruction::ListCanonLower { .. } => {
1812 self.need_pinner = true;
1813 self.need_unsafe = true;
1814 let slice = &operands[0];
1815 let data = self.locals.tmp("data");
1816 uwriteln!(
1817 self.src,
1818 "{data} := unsafe.Pointer(unsafe.SliceData({slice}))\n\
1819 {PINNER}.Pin({data})"
1820 );
1821 results.push(format!("uintptr({data})"));
1822 results.push(format!("uint32(len({slice}))"));
1823 }
1824 Instruction::ListCanonLift { element, .. } => {
1825 self.need_unsafe = true;
1826 let pointer = &operands[0];
1827 let length = &operands[1];
1828 let ty = self.type_name(resolve, **element);
1829 let value = self.locals.tmp("value");
1830 uwriteln!(
1831 self.src,
1832 "{value} := unsafe.Slice((*{ty})(unsafe.Pointer({pointer})), {length})"
1833 );
1834 results.push(value)
1835 }
1836 Instruction::ListLower { element, .. } => {
1837 self.need_unsafe = true;
1838 self.need_pinner = true;
1839 self.imports.insert(remote_pkg("runtime"));
1840 let (body, _) = self.blocks.pop().unwrap();
1841 let value = &operands[0];
1842 let slice = self.locals.tmp("slice");
1843 let result = self.locals.tmp("result");
1844 let length = self.locals.tmp("length");
1845 let size = self
1846 .generator
1847 .sizes
1848 .size(element)
1849 .format(POINTER_SIZE_EXPRESSION);
1850 let align = self
1851 .generator
1852 .sizes
1853 .align(element)
1854 .format(POINTER_SIZE_EXPRESSION);
1855 uwriteln!(
1856 self.src,
1857 "{slice} := {value}
1858{length} := uint32(len({slice}))
1859{result} := witRuntime.Allocate({PINNER}, uintptr({length} * {size}), {align})
1860for index, {ITER_ELEMENT} := range {slice} {{
1861 {ITER_BASE_POINTER} := unsafe.Add({result}, index * {size})
1862 {body}
1863}}
1864"
1865 );
1866 results.push(format!("uintptr({result})"));
1867 results.push(length);
1868 }
1869 Instruction::ListLift { element, .. } => {
1870 self.need_unsafe = true;
1871 let (body, body_results) = self.blocks.pop().unwrap();
1872 let value = &operands[0];
1873 let length = &operands[1];
1874 let result = self.locals.tmp("result");
1875 let size = self
1876 .generator
1877 .sizes
1878 .size(element)
1879 .format(POINTER_SIZE_EXPRESSION);
1880 let element_type = self.type_name(resolve, **element);
1881 let body_result = &body_results[0];
1882 uwriteln!(
1883 self.src,
1884 "{result} := make([]{element_type}, 0, {length})
1885for index := 0; index < int({length}); index++ {{
1886 {ITER_BASE_POINTER} := unsafe.Add(unsafe.Pointer({value}), index * {size})
1887 {body}
1888 {result} = append({result}, {body_result})
1889}}
1890"
1891 );
1892 results.push(result);
1893 }
1894 Instruction::CallInterface { func, .. } => {
1895 if self.unpin_params {
1896 self.imports.insert(remote_pkg("runtime"));
1897 uwriteln!(self.src, "witRuntime.Unpin()");
1898 }
1899
1900 let name = func.item_name().to_upper_camel_case();
1901 let package = format!(
1902 "export_{}",
1903 self.generator.go_package_name(resolve, self.interface)
1904 );
1905
1906 let call = match &func.kind {
1907 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {
1908 let args = operands.join(", ");
1909 let call = format!("{package}.{name}({args})");
1910 self.imports.insert(self.generator.mod_pkg(true, &package));
1911 call
1912 }
1913 FunctionKind::Constructor(ty) => {
1914 let args = operands.join(", ");
1915 let ty = resolve.types[*ty]
1916 .name
1917 .as_ref()
1918 .unwrap()
1919 .to_upper_camel_case();
1920 let call = format!("{package}.Make{ty}({args})");
1921 self.imports.insert(self.generator.mod_pkg(true, &package));
1922 call
1923 }
1924 FunctionKind::Method(_) | FunctionKind::AsyncMethod(_) => {
1925 let target = &operands[0];
1926 let args = operands[1..].join(", ");
1927 format!("({target}).{name}({args})")
1928 }
1929 FunctionKind::Static(ty) | FunctionKind::AsyncStatic(ty) => {
1930 let args = operands.join(", ");
1931 let ty = self.type_name(resolve, Type::Id(*ty));
1932 format!("{ty}{name}({args})")
1933 }
1934 };
1935
1936 if let Some(ty) = func.result {
1937 let result = self.locals.tmp("result");
1938 if let Type::Id(ty) = ty
1939 && let TypeDefKind::Tuple(tuple) = &resolve.types[ty].kind
1940 {
1941 let count = tuple.types.len();
1942 self.generator.tuples.insert(count);
1943 self.imports.insert(remote_pkg("types"));
1944
1945 let names = (0..count)
1946 .map(|_| self.locals.tmp("result"))
1947 .collect::<Vec<_>>();
1948 let bindings = names.join(", ");
1949 let fields = names
1950 .iter()
1951 .enumerate()
1952 .map(|(idx, name)| format!("F{idx}: {name}"))
1953 .collect::<Vec<_>>()
1954 .join(", ");
1955 let types = tuple
1956 .types
1957 .iter()
1958 .map(|&ty| self.type_name(resolve, ty))
1959 .collect::<Vec<_>>()
1960 .join(", ");
1961
1962 uwriteln!(
1963 self.src,
1964 "{bindings} := {call}
1965{result} := witTypes.Tuple{count}[{types}]{{{fields}}}"
1966 );
1967 } else {
1968 uwriteln!(self.src, "{result} := {call}");
1969 }
1970 results.push(result);
1971 } else {
1972 uwriteln!(self.src, "{call}");
1973 }
1974 }
1975 Instruction::Return { func, .. } => {
1976 if let Some(ty) = func.result {
1977 let result = &operands[0];
1978 if self.in_import
1979 && let Type::Id(ty) = ty
1980 && let TypeDefKind::Tuple(tuple) = &resolve.types[ty].kind
1981 {
1982 let count = tuple.types.len();
1983 let tuple = self.locals.tmp("tuple");
1984
1985 let results = (0..count)
1986 .map(|index| format!("{tuple}.F{index}"))
1987 .collect::<Vec<_>>()
1988 .join(", ");
1989
1990 uwriteln!(
1991 self.src,
1992 "{tuple} := {result}
1993return {results}"
1994 );
1995 } else {
1996 uwriteln!(self.src, "return {result}");
1997 }
1998 }
1999 }
2000 Instruction::AsyncTaskReturn { .. } => {
2001 let name = self.name.unwrap();
2002 let args = operands.join(", ");
2003 uwriteln!(self.src, "wasm_export_task_return_{name}({args})");
2004 }
2005 Instruction::LengthStore { offset } => store(
2006 self,
2007 &format!("uint32({})", operands[0]),
2008 &operands[1],
2009 offset,
2010 "uint32",
2011 ),
2012 Instruction::PointerStore { offset } => store(
2013 self,
2014 &format!("uint32(uintptr({}))", operands[0]),
2015 &operands[1],
2016 offset,
2017 "uint32",
2018 ),
2019 Instruction::I32Store8 { offset } => store(
2020 self,
2021 &format!("int8({})", operands[0]),
2022 &operands[1],
2023 offset,
2024 "int8",
2025 ),
2026 Instruction::I32Store16 { offset } => store(
2027 self,
2028 &format!("int16({})", operands[0]),
2029 &operands[1],
2030 offset,
2031 "int16",
2032 ),
2033 Instruction::I32Store { offset } => {
2034 store(self, &operands[0], &operands[1], offset, "int32")
2035 }
2036 Instruction::I64Store { offset } => {
2037 store(self, &operands[0], &operands[1], offset, "int64")
2038 }
2039 Instruction::F32Store { offset } => {
2040 store(self, &operands[0], &operands[1], offset, "float32")
2041 }
2042 Instruction::F64Store { offset } => {
2043 store(self, &operands[0], &operands[1], offset, "float64")
2044 }
2045 Instruction::LengthLoad { offset } => {
2046 load(self, results, &operands[0], offset, "uint32", &|v| v)
2047 }
2048 Instruction::PointerLoad { offset } => {
2049 load(self, results, &operands[0], offset, "uint32", &|v| {
2050 format!("uintptr({v})")
2051 })
2052 }
2053 Instruction::I32Load8U { offset } => {
2054 load(self, results, &operands[0], offset, "uint32", &|v| {
2055 format!("uint8({v})")
2056 })
2057 }
2058 Instruction::I32Load8S { offset } => {
2059 load(self, results, &operands[0], offset, "uint32", &|v| {
2060 format!("int8({v})")
2061 })
2062 }
2063 Instruction::I32Load16U { offset } => {
2064 load(self, results, &operands[0], offset, "uint32", &|v| {
2065 format!("uint16({v})")
2066 })
2067 }
2068 Instruction::I32Load16S { offset } => {
2069 load(self, results, &operands[0], offset, "uint32", &|v| {
2070 format!("int16({v})")
2071 })
2072 }
2073 Instruction::I32Load { offset } => {
2074 load(self, results, &operands[0], offset, "int32", &|v| v)
2075 }
2076 Instruction::I64Load { offset } => {
2077 load(self, results, &operands[0], offset, "int64", &|v| v)
2078 }
2079 Instruction::F32Load { offset } => {
2080 load(self, results, &operands[0], offset, "float32", &|v| v)
2081 }
2082 Instruction::F64Load { offset } => {
2083 load(self, results, &operands[0], offset, "float64", &|v| v)
2084 }
2085 Instruction::BoolFromI32 => results.push(format!("({} != 0)", operands[0])),
2086 Instruction::U8FromI32 => results.push(format!("uint8({})", operands[0])),
2087 Instruction::S8FromI32 => results.push(format!("int8({})", operands[0])),
2088 Instruction::U16FromI32 => results.push(format!("uint16({})", operands[0])),
2089 Instruction::S16FromI32 => results.push(format!("int16({})", operands[0])),
2090 Instruction::U32FromI32 => results.push(format!("uint32({})", operands[0])),
2091 Instruction::S32FromI32 | Instruction::S64FromI64 => {
2092 results.push(operands.pop().unwrap())
2093 }
2094 Instruction::U64FromI64 => results.push(format!("uint64({})", operands[0])),
2095 Instruction::I32FromBool => {
2096 let value = &operands[0];
2097 let result = self.locals.tmp("result");
2098 uwriteln!(
2099 self.src,
2100 "var {result} int32
2101if {value} {{
2102 {result} = 1
2103}} else {{
2104 {result} = 0
2105}}"
2106 );
2107 results.push(result);
2108 }
2109 Instruction::I32FromU8
2110 | Instruction::I32FromS8
2111 | Instruction::I32FromU16
2112 | Instruction::I32FromS16
2113 | Instruction::I32FromU32 => {
2114 results.push(format!("int32({})", operands[0]));
2115 }
2116 Instruction::I32FromS32 | Instruction::I64FromS64 => {
2117 results.push(operands.pop().unwrap())
2118 }
2119 Instruction::I64FromU64 => results.push(format!("int64({})", operands[0])),
2120 Instruction::CoreF32FromF32
2121 | Instruction::CoreF64FromF64
2122 | Instruction::F32FromCoreF32
2123 | Instruction::F64FromCoreF64 => results.push(operands.pop().unwrap()),
2124 Instruction::CharFromI32 => results.push(format!("rune({})", operands[0])),
2125 Instruction::I32FromChar => results.push(format!("int32({})", operands[0])),
2126 Instruction::TupleLower { tuple, .. } => {
2127 let op = &operands[0];
2128 for index in 0..tuple.types.len() {
2129 results.push(format!("({op}).F{index}"));
2130 }
2131 }
2132 Instruction::TupleLift { tuple, .. } => {
2133 let count = tuple.types.len();
2134 self.generator.tuples.insert(count);
2135 let types = tuple
2136 .types
2137 .iter()
2138 .map(|&ty| self.type_name(resolve, ty))
2139 .collect::<Vec<_>>()
2140 .join(", ");
2141 let fields = operands
2142 .iter()
2143 .enumerate()
2144 .map(|(idx, val)| format!("F{idx}: {val}"))
2145 .collect::<Vec<String>>()
2146 .join(", ");
2147 self.imports.insert(remote_pkg("types"));
2148 results.push(format!("witTypes.Tuple{count}[{types}]{{{fields}}}"));
2149 }
2150 Instruction::FlagsLower { .. } => {
2151 let value = operands.pop().unwrap();
2152 results.push(format!("int32({value})"))
2153 }
2154 Instruction::FlagsLift { flags, .. } => {
2155 let value = operands.pop().unwrap();
2156 let repr = flags_repr(flags);
2157 results.push(format!("{repr}({value})"))
2158 }
2159 Instruction::RecordLower { record, .. } => {
2160 let op = &operands[0];
2161 for field in &record.fields {
2162 let field = field.name.to_upper_camel_case();
2163 results.push(format!("({op}).{field}"));
2164 }
2165 }
2166 Instruction::RecordLift { record, ty, .. } => {
2167 let name = self.type_name(resolve, Type::Id(*ty));
2168 let fields = record
2169 .fields
2170 .iter()
2171 .zip(operands.iter())
2172 .map(|(field, op)| format!("{}: {op}", field.name.to_upper_camel_case()))
2173 .collect::<Vec<_>>()
2174 .join(", ");
2175 results.push(format!("{name}{{{fields}}}"));
2176 }
2177 Instruction::OptionLower {
2178 results: result_types,
2179 ..
2180 } => {
2181 self.generator.need_option = true;
2182 self.imports.insert(remote_pkg("types"));
2183 let (some, some_results) = self.blocks.pop().unwrap();
2184 let (none, none_results) = self.blocks.pop().unwrap();
2185 let value = &operands[0];
2186
2187 let result_names = (0..result_types.len())
2188 .map(|_| self.locals.tmp("option"))
2189 .collect::<Vec<_>>();
2190
2191 let declarations = result_types
2192 .iter()
2193 .zip(&result_names)
2194 .map(|(ty, name)| {
2195 let ty = wasm_type(*ty);
2196 format!("var {name} {ty}")
2197 })
2198 .collect::<Vec<_>>()
2199 .join("\n");
2200
2201 let some_result_assignments = some_results
2202 .iter()
2203 .zip(&result_names)
2204 .map(|(result, name)| format!("{name} = {result}"))
2205 .collect::<Vec<_>>()
2206 .join("\n");
2207
2208 let none_result_assignments = none_results
2209 .iter()
2210 .zip(&result_names)
2211 .map(|(result, name)| format!("{name} = {result}"))
2212 .collect::<Vec<_>>()
2213 .join("\n");
2214
2215 results.extend(result_names);
2216
2217 uwriteln!(
2218 self.src,
2219 r#"{declarations}
2220switch {value}.Tag() {{
2221case witTypes.OptionNone:
2222 {none}
2223 {none_result_assignments}
2224case witTypes.OptionSome:
2225 {VARIANT_PAYLOAD_NAME} := {value}.Some()
2226 {some}
2227 {some_result_assignments}
2228default:
2229 panic("unreachable")
2230}}"#
2231 );
2232 }
2233 Instruction::OptionLift { ty, payload } => {
2234 self.generator.need_option = true;
2235 self.imports.insert(remote_pkg("types"));
2236 let (some, some_results) = self.blocks.pop().unwrap();
2237 let (none, none_results) = self.blocks.pop().unwrap();
2238 assert!(none_results.is_empty());
2239 assert!(some_results.len() == 1);
2240 let some_result = &some_results[0];
2241 let ty = self.type_name(resolve, Type::Id(*ty));
2242 let some_type = self.type_name(resolve, **payload);
2243 let result = self.locals.tmp("option");
2244 let tag = &operands[0];
2245 uwriteln!(
2246 self.src,
2247 r#"var {result} {ty}
2248switch {tag} {{
2249case 0:
2250 {none}
2251 {result} = witTypes.None[{some_type}]()
2252case 1:
2253 {some}
2254 {result} = witTypes.Some[{some_type}]({some_result})
2255default:
2256 panic("unreachable")
2257}}"#
2258 );
2259 results.push(result);
2260 }
2261 Instruction::ResultLower {
2262 result,
2263 results: result_types,
2264 ..
2265 } => {
2266 self.generator.need_result = true;
2267 self.imports.insert(remote_pkg("types"));
2268 let (err, err_results) = self.blocks.pop().unwrap();
2269 let (ok, ok_results) = self.blocks.pop().unwrap();
2270 let value = &operands[0];
2271
2272 let result_names = (0..result_types.len())
2273 .map(|_| self.locals.tmp("option"))
2274 .collect::<Vec<_>>();
2275
2276 let declarations = result_types
2277 .iter()
2278 .zip(&result_names)
2279 .map(|(ty, name)| {
2280 let ty = wasm_type(*ty);
2281 format!("var {name} {ty}")
2282 })
2283 .collect::<Vec<_>>()
2284 .join("\n");
2285
2286 let ok_result_assignments = ok_results
2287 .iter()
2288 .zip(&result_names)
2289 .map(|(result, name)| format!("{name} = {result}"))
2290 .collect::<Vec<_>>()
2291 .join("\n");
2292
2293 let err_result_assignments = err_results
2294 .iter()
2295 .zip(&result_names)
2296 .map(|(result, name)| format!("{name} = {result}"))
2297 .collect::<Vec<_>>()
2298 .join("\n");
2299
2300 results.extend(result_names);
2301
2302 let ok_set_payload = if result.ok.is_some() {
2303 format!("{VARIANT_PAYLOAD_NAME} := {value}.Ok()")
2304 } else {
2305 self.generator.need_unit = true;
2306 String::new()
2307 };
2308
2309 let err_set_payload = if result.err.is_some() {
2310 format!("{VARIANT_PAYLOAD_NAME} := {value}.Err()")
2311 } else {
2312 self.generator.need_unit = true;
2313 String::new()
2314 };
2315
2316 uwriteln!(
2317 self.src,
2318 r#"{declarations}
2319switch {value}.Tag() {{
2320case witTypes.ResultOk:
2321 {ok_set_payload}
2322 {ok}
2323 {ok_result_assignments}
2324case witTypes.ResultErr:
2325 {err_set_payload}
2326 {err}
2327 {err_result_assignments}
2328default:
2329 panic("unreachable")
2330}}"#
2331 );
2332 }
2333 Instruction::ResultLift { ty, result, .. } => {
2334 self.generator.need_result = true;
2335 self.imports.insert(remote_pkg("types"));
2336 let (err, err_results) = self.blocks.pop().unwrap();
2337 let (ok, ok_results) = self.blocks.pop().unwrap();
2338 assert_eq!(ok_results.is_empty(), result.ok.is_none());
2339 assert_eq!(err_results.is_empty(), result.err.is_none());
2340 let ok_result = if result.ok.is_some() {
2341 &ok_results[0]
2342 } else {
2343 self.generator.need_unit = true;
2344 "witTypes.Unit{}"
2345 };
2346 let err_result = if result.err.is_some() {
2347 &err_results[0]
2348 } else {
2349 self.generator.need_unit = true;
2350 "witTypes.Unit{}"
2351 };
2352 let ty = self.type_name(resolve, Type::Id(*ty));
2353 let ok_type = result
2354 .ok
2355 .map(|ty| self.type_name(resolve, ty))
2356 .unwrap_or_else(|| {
2357 self.generator.need_unit = true;
2358 "witTypes.Unit".into()
2359 });
2360 let err_type = result
2361 .err
2362 .map(|ty| self.type_name(resolve, ty))
2363 .unwrap_or_else(|| {
2364 self.generator.need_unit = true;
2365 "witTypes.Unit".into()
2366 });
2367 let result = self.locals.tmp("result");
2368 let tag = &operands[0];
2369 uwriteln!(
2370 self.src,
2371 r#"var {result} {ty}
2372switch {tag} {{
2373case 0:
2374 {ok}
2375 {result} = witTypes.Ok[{ok_type}, {err_type}]({ok_result})
2376case 1:
2377 {err}
2378 {result} = witTypes.Err[{ok_type}, {err_type}]({err_result})
2379default:
2380 panic("unreachable")
2381}}"#
2382 );
2383 results.push(result);
2384 }
2385 Instruction::EnumLower { .. } => results.push(format!("int32({})", operands[0])),
2386 Instruction::EnumLift { enum_, .. } => {
2387 results.push(format!("{}({})", int_repr(enum_.tag()), operands[0]))
2388 }
2389 Instruction::VariantLower {
2390 ty,
2391 variant,
2392 results: result_types,
2393 ..
2394 } => {
2395 let blocks = self
2396 .blocks
2397 .drain(self.blocks.len() - variant.cases.len()..)
2398 .collect::<Vec<_>>();
2399
2400 let ty = self.type_name(resolve, Type::Id(*ty));
2401 let value = &operands[0];
2402
2403 let result_names = (0..result_types.len())
2404 .map(|_| self.locals.tmp("variant"))
2405 .collect::<Vec<_>>();
2406
2407 let declarations = result_types
2408 .iter()
2409 .zip(&result_names)
2410 .map(|(ty, name)| {
2411 let ty = wasm_type(*ty);
2412 format!("var {name} {ty}")
2413 })
2414 .collect::<Vec<_>>()
2415 .join("\n");
2416
2417 let cases = variant
2418 .cases
2419 .iter()
2420 .zip(blocks)
2421 .map(|(case, (block, block_results))| {
2422 let assignments = result_names
2423 .iter()
2424 .zip(&block_results)
2425 .map(|(name, result)| format!("{name} = {result}"))
2426 .collect::<Vec<_>>()
2427 .join("\n");
2428
2429 let name = case.name.to_upper_camel_case();
2430
2431 let set_payload = if case.ty.is_some() {
2432 format!("{VARIANT_PAYLOAD_NAME} := {value}.{name}()")
2433 } else {
2434 String::new()
2435 };
2436
2437 format!(
2438 "case {ty}{name}:
2439 {set_payload}
2440 {block}
2441 {assignments}
2442"
2443 )
2444 })
2445 .collect::<Vec<_>>()
2446 .join("\n");
2447
2448 results.extend(result_names);
2449
2450 uwriteln!(
2451 self.src,
2452 r#"{declarations}
2453switch {value}.Tag() {{
2454{cases}
2455default:
2456 panic("unreachable")
2457}}"#
2458 );
2459 }
2460 Instruction::VariantLift { ty, variant, .. } => {
2461 let blocks = self
2462 .blocks
2463 .drain(self.blocks.len() - variant.cases.len()..)
2464 .collect::<Vec<_>>();
2465
2466 let ty = self.type_name(resolve, Type::Id(*ty));
2467 let result = self.locals.tmp("variant");
2468 let tag = &operands[0];
2469
2470 let (package, name) = if let Some(index) = ty.find('.') {
2471 (&ty[..index + 1], &ty[index + 1..])
2472 } else {
2473 ("", ty.as_str())
2474 };
2475
2476 let cases = variant
2477 .cases
2478 .iter()
2479 .zip(blocks)
2480 .enumerate()
2481 .map(|(index, (case, (block, block_results)))| {
2482 assert_eq!(block_results.is_empty(), case.ty.is_none());
2483 let payload = if case.ty.is_some() {
2484 &block_results[0]
2485 } else {
2486 ""
2487 };
2488 let case = case.name.to_upper_camel_case();
2489 format!(
2490 "case {index}:
2491 {block}
2492 {result} = {package}Make{name}{case}({payload})
2493"
2494 )
2495 })
2496 .collect::<Vec<_>>()
2497 .join("\n");
2498
2499 uwriteln!(
2500 self.src,
2501 r#"var {result} {ty}
2502switch {tag} {{
2503{cases}
2504default:
2505 panic("unreachable")
2506}}"#
2507 );
2508 results.push(result);
2509 }
2510 Instruction::VariantPayloadName => results.push(VARIANT_PAYLOAD_NAME.into()),
2511 Instruction::IterElem { .. } => results.push(ITER_ELEMENT.into()),
2512 Instruction::IterBasePointer => results.push(ITER_BASE_POINTER.into()),
2513 Instruction::I32Const { val } => results.push(format!("int32({val})")),
2514 Instruction::ConstZero { tys } => {
2515 results.extend(iter::repeat_with(|| "0".into()).take(tys.len()));
2516 }
2517 Instruction::Bitcasts { casts } => {
2518 results.extend(
2519 casts
2520 .iter()
2521 .zip(operands)
2522 .map(|(which, op)| cast(op, which, &mut self.need_math)),
2523 );
2524 }
2525 Instruction::FutureLower { .. }
2526 | Instruction::StreamLower { .. }
2527 | Instruction::HandleLower {
2528 handle: Handle::Own(_),
2529 ..
2530 } => {
2531 let op = &operands[0];
2532 if self.collect_lifters {
2533 self.lifter_count += 1;
2534 let resource = self.locals.tmp("resource");
2535 let handle = self.locals.tmp("handle");
2536 uwriteln!(
2537 self.src,
2538 "{resource} := {op}
2539{handle} := {resource}.TakeHandle()
2540lifters = append(lifters, func() {{
2541 {resource}.SetHandle({handle})
2542}})"
2543 );
2544 results.push(handle)
2545 } else {
2546 results.push(format!("({op}).TakeHandle()"))
2547 }
2548 }
2549 Instruction::HandleLower {
2550 handle: Handle::Borrow(_),
2551 ..
2552 } => results.push(format!("({}).Handle()", operands[0])),
2553 Instruction::HandleLift { handle, .. } => {
2554 let (which, resource) = match handle {
2555 Handle::Borrow(resource) => ("Borrow", resource),
2556 Handle::Own(resource) => ("Own", resource),
2557 };
2558 let handle = &operands[0];
2559 let ty = self.type_name(resolve, Type::Id(*resource));
2560 results.push(format!("{ty}From{which}Handle(int32(uintptr({handle})))"))
2561 }
2562 Instruction::CallWasm { sig, .. } => {
2563 let assignment = match &sig.results[..] {
2564 [] => String::new(),
2565 [_] => {
2566 let result = self.locals.tmp("result");
2567 let assignment = format!("{result} := ");
2568 results.push(result);
2569 assignment
2570 }
2571 _ => unreachable!(),
2572 };
2573 let name = &self.function_to_call;
2574 let params = operands.join(", ");
2575 uwriteln!(self.src, "{assignment}{name}({params})")
2576 }
2577 Instruction::Flush { amt } => {
2578 for op in operands.iter().take(*amt) {
2579 let result = self.locals.tmp("result");
2580 uwriteln!(self.src, "{result} := {op};");
2581 results.push(result);
2582 }
2583 }
2584 Instruction::FutureLift { ty, .. } => {
2585 let exported = self.generator.has_exported_resource(resolve, Type::Id(*ty));
2586 let owner = self
2587 .generator
2588 .futures_and_streams
2589 .get(&(*ty, exported))
2590 .unwrap()
2591 .clone();
2592 let package = self.package_for_owner(resolve, owner.as_ref(), *ty);
2593 let TypeDefKind::Future(payload_ty) = &resolve.types[*ty].kind else {
2594 unreachable!()
2595 };
2596 let camel = if let Some(ty) = payload_ty {
2597 self.generator
2598 .mangle_name(resolve, *ty, owner.as_ref())
2599 .to_upper_camel_case()
2600 } else {
2601 "Unit".into()
2602 };
2603 let handle = &operands[0];
2604 results.push(format!("{package}LiftFuture{camel}({handle})"));
2605 }
2606 Instruction::StreamLift { ty, .. } => {
2607 let exported = self.generator.has_exported_resource(resolve, Type::Id(*ty));
2608 let owner = self
2609 .generator
2610 .futures_and_streams
2611 .get(&(*ty, exported))
2612 .unwrap()
2613 .clone();
2614 let package = self.package_for_owner(resolve, owner.as_ref(), *ty);
2615 let TypeDefKind::Stream(payload_ty) = &resolve.types[*ty].kind else {
2616 unreachable!()
2617 };
2618 let camel = if let Some(ty) = payload_ty {
2619 self.generator
2620 .mangle_name(resolve, *ty, owner.as_ref())
2621 .to_upper_camel_case()
2622 } else {
2623 "Unit".into()
2624 };
2625 let handle = &operands[0];
2626 results.push(format!("{package}LiftStream{camel}({handle})"));
2627 }
2628 Instruction::MapLower { key, value, .. } => {
2629 self.need_unsafe = true;
2630 self.need_pinner = true;
2631 self.imports.insert(remote_pkg("runtime"));
2632 let (body, _) = self.blocks.pop().unwrap();
2633 let value_op = &operands[0];
2634 let src_map = self.locals.tmp("srcMap");
2635 let result = self.locals.tmp("result");
2636 let length = self.locals.tmp("length");
2637 let idx = self.locals.tmp("idx");
2638 let entry = self.generator.sizes.record([*key, *value]);
2639 let size = entry.size.format(POINTER_SIZE_EXPRESSION);
2640 let align = entry.align.format(POINTER_SIZE_EXPRESSION);
2641 uwriteln!(
2642 self.src,
2643 "{src_map} := {value_op}
2644{length} := uint32(len({src_map}))
2645{result} := witRuntime.Allocate({PINNER}, uintptr({length} * {size}), {align})
2646var {idx} int
2647for map_key, map_value := range {src_map} {{
2648 {ITER_BASE_POINTER} := unsafe.Add({result}, {idx} * {size})
2649 {body}
2650 {idx}++
2651}}
2652"
2653 );
2654 results.push(format!("uintptr({result})"));
2655 results.push(length);
2656 }
2657 Instruction::MapLift { key, value, .. } => {
2658 self.need_unsafe = true;
2659 let (body, body_results) = self.blocks.pop().unwrap();
2660 let pointer = &operands[0];
2661 let length = &operands[1];
2662 let result = self.locals.tmp("result");
2663 let entry = self.generator.sizes.record([*key, *value]);
2664 let size = entry.size.format(POINTER_SIZE_EXPRESSION);
2665 let key_type = self.type_name(resolve, **key);
2666 let value_type = self.type_name(resolve, **value);
2667 let body_key = &body_results[0];
2668 let body_value = &body_results[1];
2669 uwriteln!(
2670 self.src,
2671 "{result} := make(map[{key_type}]{value_type}, {length})
2672for index := 0; index < int({length}); index++ {{
2673 {ITER_BASE_POINTER} := unsafe.Add(unsafe.Pointer({pointer}), index * {size})
2674 {body}
2675 {result}[{body_key}] = {body_value}
2676}}
2677"
2678 );
2679 results.push(result);
2680 }
2681 Instruction::IterMapKey { .. } => results.push("map_key".into()),
2682 Instruction::IterMapValue { .. } => results.push("map_value".into()),
2683 Instruction::GuestDeallocateMap { .. } | Instruction::GuestDeallocate { .. } => {
2684 }
2686 _ => unimplemented!("{instruction:?}"),
2687 }
2688 }
2689}
2690
2691struct InterfaceGenerator<'a> {
2692 generator: &'a mut Go,
2693 resolve: &'a Resolve,
2694 interface: Option<(InterfaceId, &'a WorldKey)>,
2695 in_import: bool,
2696 src: String,
2697 imports: BTreeSet<String>,
2698 need_unsafe: bool,
2699 need_runtime: bool,
2700}
2701
2702impl<'a> InterfaceGenerator<'a> {
2703 fn new(
2704 generator: &'a mut Go,
2705 resolve: &'a Resolve,
2706 interface: Option<(InterfaceId, &'a WorldKey)>,
2707 in_import: bool,
2708 ) -> Self {
2709 Self {
2710 generator,
2711 resolve,
2712 interface,
2713 in_import,
2714 src: String::new(),
2715 imports: BTreeSet::new(),
2716 need_unsafe: false,
2717 need_runtime: false,
2718 }
2719 }
2720
2721 fn type_name(&mut self, resolve: &Resolve, ty: Type) -> String {
2722 self.generator.type_name(
2723 resolve,
2724 ty,
2725 self.interface.map(|(_, key)| key),
2726 self.in_import || !self.generator.has_exported_resource(resolve, ty),
2727 &mut self.imports,
2728 )
2729 }
2730}
2731
2732impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
2733 fn resolve(&self) -> &'a Resolve {
2734 self.resolve
2735 }
2736
2737 fn type_record(&mut self, _: TypeId, name: &str, record: &Record, docs: &Docs) {
2738 let name = name.to_upper_camel_case();
2739
2740 let fields = record
2741 .fields
2742 .iter()
2743 .map(|field| {
2744 let ty = self.type_name(self.resolve, field.ty);
2745 let docs = format_docs(&field.docs);
2746 let field = field.name.to_upper_camel_case();
2747 format!("{docs}{field} {ty}")
2748 })
2749 .collect::<Vec<_>>()
2750 .join("\n");
2751
2752 let docs = format_docs(docs);
2753
2754 uwriteln!(
2755 self.src,
2756 "
2757{docs}type {name} struct {{
2758 {fields}
2759}}"
2760 )
2761 }
2762
2763 fn type_resource(&mut self, id: TypeId, name: &str, docs: &Docs) {
2764 self.generator.resources.insert(
2765 id,
2766 if self.in_import {
2767 Direction::Import
2768 } else {
2769 Direction::Export
2770 },
2771 );
2772
2773 let camel = name.to_upper_camel_case();
2774 let module = self
2775 .interface
2776 .map(|(_, key)| self.resolve.name_world_key(key))
2777 .unwrap_or_else(|| "$root".into());
2778
2779 if self.in_import {
2780 self.imports.insert(remote_pkg("runtime"));
2781 self.need_runtime = true;
2782 let docs = format_docs(docs);
2783 uwriteln!(
2784 self.src,
2785 r#"
2786//go:wasmimport {module} [resource-drop]{name}
2787func resourceDrop{camel}(handle int32)
2788
2789{docs}type {camel} struct {{
2790 handle *witRuntime.Handle
2791}}
2792
2793func (self *{camel}) TakeHandle() int32 {{
2794 return self.handle.Take()
2795}}
2796
2797func (self *{camel}) SetHandle(handle int32) {{
2798 self.handle.Set(handle)
2799}}
2800
2801func (self *{camel}) Handle() int32 {{
2802 return self.handle.Use()
2803}}
2804
2805func (self *{camel}) Drop() {{
2806 handle := self.handle.TakeOrNil()
2807 if handle != 0 {{
2808 resourceDrop{camel}(handle)
2809 }}
2810}}
2811
2812func {camel}FromOwnHandle(handleValue int32) *{camel} {{
2813 handle := witRuntime.MakeHandle(handleValue)
2814 value := &{camel}{{handle}}
2815 runtime.AddCleanup(value, func(_ int) {{
2816 handleValue := handle.TakeOrNil()
2817 if handleValue != 0 {{
2818 resourceDrop{camel}(handleValue)
2819 }}
2820 }}, 0)
2821 return value
2822}}
2823
2824func {camel}FromBorrowHandle(handleValue int32) *{camel} {{
2825 handle := witRuntime.MakeHandle(handleValue)
2826 return &{camel}{{handle}}
2827}}
2828"#
2829 );
2830 } else {
2831 self.need_unsafe = true;
2832 uwriteln!(
2833 self.src,
2834 r#"
2835//go:wasmimport [export]{module} [resource-new]{name}
2836func resourceNew{camel}(pointer unsafe.Pointer) int32
2837
2838//go:wasmimport [export]{module} [resource-rep]{name}
2839func resourceRep{camel}(handle int32) unsafe.Pointer
2840
2841//go:wasmimport [export]{module} [resource-drop]{name}
2842func resourceDrop{camel}(handle int32)
2843
2844//go:wasmexport {module}#[dtor]{name}
2845func resourceDtor{camel}(rep int32) {{
2846 val := (*{camel})(unsafe.Pointer(uintptr(rep)))
2847 val.handle = 0
2848 val.pinner.Unpin()
2849 val.OnDrop()
2850}}
2851
2852func (self *{camel}) TakeHandle() int32 {{
2853 self.pinner.Pin(self)
2854 self.handle = resourceNew{camel}(unsafe.Pointer(self))
2855 return self.handle
2856}}
2857
2858func (self *{camel}) SetHandle(handle int32) {{
2859 if self.handle != handle {{
2860 panic("invalid handle")
2861 }}
2862}}
2863
2864func (self *{camel}) Drop() {{
2865 handle := self.handle
2866 if self.handle != 0 {{
2867 self.handle = 0
2868 resourceDrop{camel}(handle)
2869 self.pinner.Unpin()
2870 self.OnDrop()
2871 }}
2872}}
2873
2874func {camel}FromOwnHandle(handle int32) *{camel} {{
2875 return (*{camel})(unsafe.Pointer(resourceRep{camel}(handle)))
2876}}
2877
2878func {camel}FromBorrowHandle(rep int32) *{camel} {{
2879 return (*{camel})(unsafe.Pointer(uintptr(rep)))
2880}}
2881"#
2882 );
2883
2884 if self.generator.opts.generate_stubs {
2885 self.need_runtime = true;
2886 uwriteln!(
2887 self.src,
2888 r#"
2889type {camel} struct {{
2890 pinner runtime.Pinner
2891 handle int32
2892}}
2893
2894func (self *{camel}) OnDrop() {{}}
2895"#
2896 );
2897 }
2898 }
2899 }
2900
2901 fn type_flags(&mut self, _: TypeId, name: &str, flags: &Flags, docs: &Docs) {
2902 let repr = flags_repr(flags);
2903
2904 let name = name.to_upper_camel_case();
2905
2906 let constants = flags
2907 .flags
2908 .iter()
2909 .enumerate()
2910 .map(|(i, flag)| {
2911 let docs = format_docs(&flag.docs);
2912 let flag = flag.name.to_upper_camel_case();
2913 format!("{docs}{name}{flag} {repr} = 1 << {i}")
2914 })
2915 .collect::<Vec<_>>()
2916 .join("\n");
2917
2918 let docs = format_docs(docs);
2919
2920 uwriteln!(
2921 self.src,
2922 "
2923const (
2924{constants}
2925)
2926
2927{docs}type {name} = {repr}"
2928 )
2929 }
2930
2931 fn type_tuple(&mut self, _: TypeId, name: &str, tuple: &Tuple, docs: &Docs) {
2932 self.imports.insert(remote_pkg("types"));
2933 let count = tuple.types.len();
2934 self.generator.tuples.insert(count);
2935 let name = name.to_upper_camel_case();
2936 let docs = format_docs(docs);
2937 let types = tuple
2938 .types
2939 .iter()
2940 .map(|ty| self.type_name(self.resolve, *ty))
2941 .collect::<Vec<_>>()
2942 .join(", ");
2943
2944 uwriteln!(
2945 self.src,
2946 "{docs}type {name} = witTypes.Tuple{count}[{types}]"
2947 );
2948 }
2949
2950 fn type_variant(&mut self, _: TypeId, name: &str, variant: &Variant, docs: &Docs) {
2951 let repr = int_repr(variant.tag());
2952
2953 let name = name.to_upper_camel_case();
2954
2955 let constants = variant
2956 .cases
2957 .iter()
2958 .enumerate()
2959 .map(|(i, case)| {
2960 let docs = format_docs(&case.docs);
2961 let case = case.name.to_upper_camel_case();
2962 format!("{docs}{name}{case} {repr} = {i}")
2963 })
2964 .collect::<Vec<_>>()
2965 .join("\n");
2966
2967 let getters = variant
2968 .cases
2969 .iter()
2970 .filter_map(|case| {
2971 case.ty.map(|ty| {
2972 let case = case.name.to_upper_camel_case();
2973 let ty = self.type_name(self.resolve, ty);
2974 format!(
2975 r#"func (self {name}) {case}() {ty} {{
2976 if self.tag != {name}{case} {{
2977 panic("tag mismatch")
2978 }}
2979 return self.value.({ty})
2980}}
2981"#
2982 )
2983 })
2984 })
2985 .collect::<Vec<_>>()
2986 .concat();
2987
2988 let constructors = variant
2989 .cases
2990 .iter()
2991 .map(|case| {
2992 let (param, value) = if let Some(ty) = case.ty {
2993 let ty = self.type_name(self.resolve, ty);
2994 (format!("value {ty}"), "value")
2995 } else {
2996 (String::new(), "nil")
2997 };
2998 let case = case.name.to_upper_camel_case();
2999 format!(
3000 r#"func Make{name}{case}({param}) {name} {{
3001 return {name}{{{name}{case}, {value}}}
3002}}
3003"#
3004 )
3005 })
3006 .collect::<Vec<_>>()
3007 .concat();
3008
3009 let docs = format_docs(docs);
3010
3011 uwriteln!(
3012 self.src,
3013 "
3014const (
3015{constants}
3016)
3017
3018{docs}type {name} struct {{
3019 tag {repr}
3020 value any
3021}}
3022
3023func (self {name}) Tag() {repr} {{
3024 return self.tag
3025}}
3026
3027{getters}
3028{constructors}
3029"
3030 )
3031 }
3032
3033 fn type_option(&mut self, _: TypeId, name: &str, payload: &Type, docs: &Docs) {
3034 self.generator.need_option = true;
3035 self.imports.insert(remote_pkg("types"));
3036 let name = name.to_upper_camel_case();
3037 let ty = self.type_name(self.resolve, *payload);
3038 let docs = format_docs(docs);
3039 uwriteln!(self.src, "{docs}type {name} = witTypes.Option[{ty}]");
3040 }
3041
3042 fn type_result(&mut self, _: TypeId, name: &str, result: &Result_, docs: &Docs) {
3043 self.generator.need_result = true;
3044 self.imports.insert(remote_pkg("types"));
3045 let name = name.to_upper_camel_case();
3046 let ok_type = result
3047 .ok
3048 .map(|ty| self.type_name(self.resolve, ty))
3049 .unwrap_or_else(|| {
3050 self.generator.need_unit = true;
3051 "witTypes.Unit".into()
3052 });
3053 let err_type = result
3054 .err
3055 .map(|ty| self.type_name(self.resolve, ty))
3056 .unwrap_or_else(|| {
3057 self.generator.need_unit = true;
3058 "witTypes.Unit".into()
3059 });
3060 let docs = format_docs(docs);
3061 uwriteln!(
3062 self.src,
3063 "{docs}type {name} = witTypes.Result[{ok_type}, {err_type}]"
3064 );
3065 }
3066
3067 fn type_enum(&mut self, _: TypeId, name: &str, enum_: &Enum, docs: &Docs) {
3068 let repr = int_repr(enum_.tag());
3069
3070 let name = name.to_upper_camel_case();
3071
3072 let constants = enum_
3073 .cases
3074 .iter()
3075 .enumerate()
3076 .map(|(i, case)| {
3077 let docs = format_docs(&case.docs);
3078 let case = case.name.to_upper_camel_case();
3079 format!("{docs}{name}{case} {repr} = {i}")
3080 })
3081 .collect::<Vec<_>>()
3082 .join("\n");
3083
3084 let docs = format_docs(docs);
3085
3086 uwriteln!(
3087 self.src,
3088 "
3089const (
3090 {constants}
3091)
3092{docs}type {name} = {repr}"
3093 )
3094 }
3095
3096 fn type_alias(&mut self, _: TypeId, name: &str, ty: &Type, docs: &Docs) {
3097 let name = name.to_upper_camel_case();
3098 let ty = self.type_name(self.resolve, *ty);
3099 let docs = format_docs(docs);
3100 uwriteln!(self.src, "{docs}type {name} = {ty}");
3101 }
3102
3103 fn type_list(&mut self, _: TypeId, name: &str, ty: &Type, docs: &Docs) {
3104 let name = name.to_upper_camel_case();
3105 let ty = self.type_name(self.resolve, *ty);
3106 let docs = format_docs(docs);
3107 uwriteln!(self.src, "{docs}type {name} = []{ty}");
3108 }
3109
3110 fn type_fixed_length_list(&mut self, _: TypeId, name: &str, ty: &Type, size: u32, docs: &Docs) {
3111 let name = name.to_upper_camel_case();
3112 let ty = self.type_name(self.resolve, *ty);
3113 let docs = format_docs(docs);
3114 uwriteln!(self.src, "{docs}type {name} = [{size}]{ty}");
3115 }
3116
3117 fn type_map(&mut self, _id: TypeId, name: &str, key: &Type, value: &Type, docs: &Docs) {
3118 let name = name.to_upper_camel_case();
3119 let key = self.type_name(self.resolve, *key);
3120 let value = self.type_name(self.resolve, *value);
3121 let docs = format_docs(docs);
3122 uwriteln!(self.src, "{docs}type {name} = map[{key}]{value}");
3123 }
3124
3125 fn type_builtin(&mut self, id: TypeId, name: &str, ty: &Type, docs: &Docs) {
3126 _ = (id, name, ty, docs);
3127 todo!()
3128 }
3129
3130 fn type_future(&mut self, id: TypeId, name: &str, _: &Option<Type>, docs: &Docs) {
3131 let name = name.to_upper_camel_case();
3132 let ty = self.type_name(self.resolve, Type::Id(id));
3133 let docs = format_docs(docs);
3134 uwriteln!(self.src, "{docs}type {name} = {ty}");
3135 }
3136
3137 fn type_stream(&mut self, id: TypeId, name: &str, _: &Option<Type>, docs: &Docs) {
3138 let name = name.to_upper_camel_case();
3139 let ty = self.type_name(self.resolve, Type::Id(id));
3140 let docs = format_docs(docs);
3141 uwriteln!(self.src, "{docs}type {name} = {ty}");
3142 }
3143}
3144
3145fn wasm_type(ty: WasmType) -> &'static str {
3146 match ty {
3147 WasmType::I32 => "int32",
3148 WasmType::I64 => "int64",
3149 WasmType::F32 => "float32",
3150 WasmType::F64 => "float64",
3151 WasmType::Pointer => "uintptr",
3152 WasmType::PointerOrI64 => "int64",
3153 WasmType::Length => "uint32",
3154 }
3155}
3156
3157fn format_docs(docs: &Docs) -> String {
3158 docs.contents
3159 .as_ref()
3160 .map(|v| {
3161 v.trim()
3162 .lines()
3163 .map(|line| format!("// {line}\n"))
3164 .collect::<Vec<_>>()
3165 .concat()
3166 })
3167 .unwrap_or_default()
3168}
3169
3170fn flags_repr(flags: &Flags) -> &'static str {
3171 match flags.repr() {
3172 FlagsRepr::U8 => "uint8",
3173 FlagsRepr::U16 => "uint16",
3174 FlagsRepr::U32(1) => "uint32",
3175 _ => unreachable!(),
3176 }
3177}
3178
3179fn int_repr(int: Int) -> &'static str {
3180 match int {
3181 Int::U8 => "uint8",
3182 Int::U16 => "uint16",
3183 Int::U32 => "uint32",
3184 Int::U64 => unreachable!(),
3185 }
3186}
3187
3188fn cast(op: &str, which: &Bitcast, need_math: &mut bool) -> String {
3189 match which {
3190 Bitcast::I32ToF32 | Bitcast::I64ToF32 => {
3191 *need_math = true;
3192 format!("math.Float32frombits(uint32({op}))")
3193 }
3194 Bitcast::F32ToI32 => {
3195 *need_math = true;
3196 format!("int32(math.Float32bits({op}))")
3197 }
3198 Bitcast::F32ToI64 => {
3199 *need_math = true;
3200 format!("int64(math.Float32bits({op}))")
3201 }
3202 Bitcast::I64ToF64 => {
3203 *need_math = true;
3204 format!("math.Float64frombits(uint64({op}))")
3205 }
3206 Bitcast::F64ToI64 => {
3207 *need_math = true;
3208 format!("int64(math.Float64bits({op}))")
3209 }
3210 Bitcast::I32ToI64 | Bitcast::LToI64 => {
3211 format!("int64({op})")
3212 }
3213 Bitcast::PToP64 => {
3214 format!("int64({op})")
3215 }
3216 Bitcast::I64ToI32 | Bitcast::I64ToL | Bitcast::PToI32 => {
3217 format!("int32({op})")
3218 }
3219 Bitcast::I64ToP64 | Bitcast::P64ToI64 => op.into(),
3220 Bitcast::P64ToP | Bitcast::LToP | Bitcast::I32ToP => {
3221 format!("uintptr({op})")
3222 }
3223 Bitcast::PToL => {
3224 format!("uint32({op})")
3225 }
3226 Bitcast::I32ToL => {
3227 format!("uint32({op})")
3228 }
3229 Bitcast::LToI32 => {
3230 format!("uint32({op})")
3231 }
3232 Bitcast::None => op.to_string(),
3233 Bitcast::Sequence(sequence) => {
3234 let [first, second] = &**sequence;
3235 let inner = cast(op, first, need_math);
3236 cast(&inner, second, need_math)
3237 }
3238 }
3239}
3240
3241fn any(resolve: &Resolve, ty: Type, fun: &dyn Fn(Type) -> bool) -> bool {
3242 if fun(ty) {
3243 return true;
3244 }
3245
3246 match ty {
3247 Type::Bool
3248 | Type::U8
3249 | Type::S8
3250 | Type::U16
3251 | Type::S16
3252 | Type::U32
3253 | Type::S32
3254 | Type::U64
3255 | Type::S64
3256 | Type::F32
3257 | Type::F64
3258 | Type::Char
3259 | Type::String => false,
3260 Type::Id(id) => {
3261 let ty = &resolve.types[id];
3262 match &ty.kind {
3263 TypeDefKind::Flags(_) | TypeDefKind::Enum(_) | TypeDefKind::Resource => false,
3264 TypeDefKind::Handle(Handle::Own(resource) | Handle::Borrow(resource)) => {
3265 any(resolve, Type::Id(*resource), fun)
3266 }
3267 TypeDefKind::Record(record) => record
3268 .fields
3269 .iter()
3270 .any(|field| any(resolve, field.ty, fun)),
3271 TypeDefKind::Variant(variant) => variant
3272 .cases
3273 .iter()
3274 .any(|case| case.ty.map(|ty| any(resolve, ty, fun)).unwrap_or(false)),
3275 TypeDefKind::Option(ty) | TypeDefKind::List(ty) | TypeDefKind::Type(ty) => {
3276 any(resolve, *ty, fun)
3277 }
3278 TypeDefKind::Result(result) => result
3279 .ok
3280 .map(|ty| any(resolve, ty, fun))
3281 .or_else(|| result.err.map(|ty| any(resolve, ty, fun)))
3282 .unwrap_or(false),
3283 TypeDefKind::Tuple(tuple) => tuple.types.iter().any(|ty| any(resolve, *ty, fun)),
3284 TypeDefKind::Future(ty) | TypeDefKind::Stream(ty) => {
3285 ty.map(|ty| any(resolve, ty, fun)).unwrap_or(false)
3286 }
3287 TypeDefKind::Map(key, value) => {
3288 any(resolve, *key, fun) || any(resolve, *value, fun)
3289 }
3290 _ => todo!("{:?}", ty.kind),
3291 }
3292 }
3293 _ => todo!("{ty:?}"),
3294 }
3295}
3296
3297fn func_declaration(resolve: &Resolve, func: &Function) -> (String, bool) {
3298 match &func.kind {
3299 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {
3300 (func.item_name().to_upper_camel_case(), false)
3301 }
3302 FunctionKind::Constructor(ty) => {
3303 let ty = resolve.types[*ty]
3304 .name
3305 .as_ref()
3306 .unwrap()
3307 .to_upper_camel_case();
3308 (format!("Make{ty}"), false)
3309 }
3310 FunctionKind::Method(ty) | FunctionKind::AsyncMethod(ty) => {
3311 let ty = resolve.types[*ty]
3312 .name
3313 .as_ref()
3314 .unwrap()
3315 .to_upper_camel_case();
3316 let camel = func.item_name().to_upper_camel_case();
3317 (format!("(self *{ty}) {camel}"), true)
3318 }
3319 FunctionKind::Static(ty) | FunctionKind::AsyncStatic(ty) => {
3320 let ty = resolve.types[*ty]
3321 .name
3322 .as_ref()
3323 .unwrap()
3324 .to_upper_camel_case();
3325 let camel = func.item_name().to_upper_camel_case();
3326 (format!("{ty}{camel}"), false)
3327 }
3328 }
3329}
3330
3331fn maybe_gofmt<'a>(format: Format, code: &'a [u8]) -> Cow<'a, [u8]> {
3332 thread::scope(|s| {
3333 if let Format::True = format
3334 && let Ok((reader, mut writer)) = io::pipe()
3335 {
3336 s.spawn(move || {
3337 _ = writer.write_all(code);
3338 });
3339
3340 if let Ok(output) = Command::new("gofmt").stdin(reader).output()
3341 && output.status.success()
3342 {
3343 return Cow::Owned(output.stdout);
3344 }
3345 }
3346
3347 Cow::Borrowed(code)
3348 })
3349}
3350
3351#[derive(Eq, PartialEq, Hash)]
3352struct FutureStreamDedup {
3353 in_import: bool,
3354 is_exported: bool,
3355 pkg_name: String,
3356 mangled_name: String,
3357}