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