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!("{PINNER} := &runtime.Pinner{{}}")
1330 } else {
1331 String::new()
1332 },
1333 format!(
1334 "
1335
1336//go:wasmexport [callback]{prefix}{export_name}
1337func wasm_export_callback_{name}(event0 uint32, event1 uint32, event2 uint32) uint32 {{
1338 return witAsync.Callback(event0, event1, event2)
1339}}
1340
1341//go:wasmimport [export]{module} [task-return]{function}
1342func wasm_export_task_return_{name}({task_return_params})
1343"
1344 ),
1345 "return int32(witAsync.Run(func() {",
1346 "}))",
1347 )
1348 } else if abi::guest_export_needs_post_return(resolve, func) {
1349 (
1350 format!("{PINNER} := &{SYNC_EXPORT_PINNER}"),
1351 format!(
1352 "
1353
1354//go:wasmexport cabi_post_{export_name}
1355func wasm_export_post_return_{name}(result {results}) {{
1356 syncExportPinner.Unpin()
1357}}
1358"
1359 ),
1360 "",
1361 "",
1362 )
1363 } else {
1364 (String::new(), String::new(), "", "")
1365 };
1366
1367 if self.opts.generate_stubs {
1368 let (camel, has_self) = func_declaration(resolve, func);
1369
1370 let mut imports = BTreeSet::new();
1371 let params =
1372 self.func_params(resolve, func, interface, false, &mut imports, has_self, "_");
1373 let results = self.func_results(resolve, func, interface, false, &mut imports);
1374
1375 self.export_interfaces
1376 .entry(self.interface_name(resolve, interface))
1377 .or_default()
1378 .extend(InterfaceData {
1379 code: format!(
1380 r#"
1381func {camel}({params}) {results} {{
1382 panic("not implemented")
1383}}
1384"#
1385 ),
1386 imports,
1387 ..InterfaceData::default()
1388 });
1389 }
1390
1391 format!(
1392 "
1393//go:wasmexport {prefix}{export_name}
1394func wasm_export_{name}({params}) {results} {{
1395 {start}
1396 {pinner}
1397 {code}
1398 {end}
1399}}{other}
1400"
1401 )
1402 }
1403
1404 #[expect(clippy::too_many_arguments, reason = "required context for codegen")]
1405 fn func_params(
1406 &mut self,
1407 resolve: &Resolve,
1408 func: &Function,
1409 interface: Option<&WorldKey>,
1410 in_import: bool,
1411 imports: &mut BTreeSet<String>,
1412 has_self: bool,
1413 prefix: &str,
1414 ) -> String {
1415 func.params
1416 .iter()
1417 .skip(if has_self { 1 } else { 0 })
1418 .map(|Param { name, ty, .. }| {
1419 let name = name.to_lower_camel_case();
1420 let ty = self.type_name(resolve, *ty, interface, in_import, imports);
1421 format!("{prefix}{name} {ty}")
1422 })
1423 .collect::<Vec<_>>()
1424 .join(", ")
1425 }
1426
1427 fn func_results(
1428 &mut self,
1429 resolve: &Resolve,
1430 func: &Function,
1431 interface: Option<&WorldKey>,
1432 in_import: bool,
1433 imports: &mut BTreeSet<String>,
1434 ) -> String {
1435 if let Some(ty) = &func.result {
1436 if let Type::Id(id) = ty
1437 && let TypeDefKind::Tuple(tuple) = &resolve.types[*id].kind
1438 {
1439 let types = tuple
1440 .types
1441 .iter()
1442 .map(|ty| self.type_name(resolve, *ty, interface, in_import, imports))
1443 .collect::<Vec<_>>()
1444 .join(", ");
1445 format!("({types})")
1446 } else {
1447 self.type_name(resolve, *ty, interface, in_import, imports)
1448 }
1449 } else {
1450 String::new()
1451 }
1452 }
1453
1454 fn visit_futures_and_streams(
1455 &mut self,
1456 in_import: bool,
1457 resolve: &Resolve,
1458 func: &Function,
1459 interface: Option<&WorldKey>,
1460 ) {
1461 for (index, ty) in func
1462 .find_futures_and_streams(resolve)
1463 .into_iter()
1464 .enumerate()
1465 {
1466 let payload_type = match &resolve.types[ty].kind {
1467 TypeDefKind::Future(ty) => {
1468 self.need_future = true;
1469 ty
1470 }
1471 TypeDefKind::Stream(ty) => {
1472 self.need_stream = true;
1473 ty
1474 }
1475 _ => unreachable!(),
1476 };
1477
1478 let exported = payload_type
1479 .map(|ty| self.has_exported_resource(resolve, ty))
1480 .unwrap_or(false);
1481
1482 if let hash_map::Entry::Vacant(e) = self.futures_and_streams.entry((ty, exported)) {
1483 e.insert(interface.cloned());
1484
1485 let data = self.future_or_stream(
1486 resolve,
1487 ty,
1488 index,
1489 in_import,
1490 in_import || !exported,
1491 interface,
1492 &func.name,
1493 );
1494
1495 let name = self.interface_name(resolve, interface);
1496 if in_import || !exported {
1497 &mut self.interfaces
1498 } else {
1499 &mut self.export_interfaces
1500 }
1501 .entry(name)
1502 .or_default()
1503 .extend(data);
1504 }
1505 }
1506 }
1507
1508 fn has_exported_resource(&self, resolve: &Resolve, ty: Type) -> bool {
1509 any(resolve, ty, &|ty| {
1510 if let Type::Id(id) = ty
1511 && let TypeDefKind::Resource = &resolve.types[id].kind
1512 && let Direction::Export = self.resources.get(&id).unwrap()
1513 {
1514 true
1515 } else {
1516 false
1517 }
1518 })
1519 }
1520
1521 fn interface_name(&self, resolve: &Resolve, interface: Option<&WorldKey>) -> String {
1522 match interface {
1523 Some(WorldKey::Name(name)) => name.to_snake_case(),
1524 Some(WorldKey::Interface(id)) => {
1525 let interface = &resolve.interfaces[*id];
1526 let package = &resolve.packages[interface.package.unwrap()];
1527 let package_has_multiple_versions = resolve.packages.iter().any(|(_, p)| {
1528 p.name.namespace == package.name.namespace
1529 && p.name.name == package.name.name
1530 && p.name.version != package.name.version
1531 });
1532 let version = if package_has_multiple_versions || self.opts.include_versions {
1533 if let Some(version) = &package.name.version {
1534 format!("{}_", version.to_string().replace(['.', '-', '+'], "_"))
1535 } else {
1536 String::new()
1537 }
1538 } else {
1539 String::new()
1540 };
1541 let namespace = package.name.namespace.to_snake_case();
1542 let package = package.name.name.to_snake_case();
1543 let interface = interface.name.as_ref().unwrap().to_snake_case();
1544 format!("{namespace}_{package}_{version}{interface}")
1545 }
1546 None => "wit_world".into(),
1547 }
1548 }
1549
1550 fn func_name(
1551 &self,
1552 resolve: &Resolve,
1553 interface: Option<&WorldKey>,
1554 func: &Function,
1555 ) -> String {
1556 let prefix = self.interface_name(resolve, interface);
1557 let name = func.name.to_snake_case().replace('.', "_");
1558
1559 format!("{prefix}_{name}")
1560 }
1561}
1562
1563struct FunctionGenerator<'a> {
1564 generator: &'a mut Go,
1565 name: Option<&'a str>,
1566 interface: Option<&'a WorldKey>,
1567 interface_for_types: Option<&'a WorldKey>,
1568 function_to_call: &'a str,
1569 param_names: Vec<String>,
1570 unpin_params: bool,
1571 in_import: bool,
1572 locals: Ns,
1573 src: String,
1574 block_storage: Vec<String>,
1575 blocks: Vec<(String, Vec<String>)>,
1576 need_unsafe: bool,
1577 need_pinner: bool,
1578 need_math: bool,
1579 collect_lifters: bool,
1580 lifter_count: u32,
1581 return_area_size: ArchitectureSize,
1582 return_area_align: Alignment,
1583 imports: BTreeSet<String>,
1584}
1585
1586impl<'a> FunctionGenerator<'a> {
1587 #[expect(clippy::too_many_arguments, reason = "required context for codegen")]
1588 fn new(
1589 generator: &'a mut Go,
1590 name: Option<&'a str>,
1591 interface: Option<&'a WorldKey>,
1592 interface_for_types: Option<&'a WorldKey>,
1593 function_to_call: &'a str,
1594 param_names: Vec<String>,
1595 unpin_params: bool,
1596 in_import: bool,
1597 ) -> Self {
1598 let mut locals = Ns::default();
1599 for name in ¶m_names {
1600 locals.insert(name).unwrap();
1601 }
1602
1603 Self {
1604 generator,
1605 name,
1606 interface,
1607 interface_for_types,
1608 function_to_call,
1609 param_names,
1610 unpin_params,
1611 in_import,
1612 locals,
1613 src: String::new(),
1614 block_storage: Vec::new(),
1615 blocks: Vec::new(),
1616 need_unsafe: false,
1617 need_pinner: false,
1618 need_math: false,
1619 collect_lifters: false,
1620 lifter_count: 0,
1621 return_area_size: ArchitectureSize::default(),
1622 return_area_align: Alignment::default(),
1623 imports: BTreeSet::new(),
1624 }
1625 }
1626
1627 fn type_name(&mut self, resolve: &Resolve, ty: Type) -> String {
1628 self.generator.type_name(
1629 resolve,
1630 ty,
1631 self.interface_for_types,
1632 self.in_import,
1633 &mut self.imports,
1634 )
1635 }
1636
1637 fn package_for_owner(
1638 &mut self,
1639 resolve: &Resolve,
1640 owner: Option<&WorldKey>,
1641 ty: TypeId,
1642 ) -> String {
1643 self.generator.package_for_owner(
1644 resolve,
1645 owner,
1646 ty,
1647 self.interface_for_types,
1648 self.in_import,
1649 &mut self.imports,
1650 )
1651 }
1652}
1653
1654impl Bindgen for FunctionGenerator<'_> {
1655 type Operand = String;
1656
1657 fn sizes(&self) -> &SizeAlign {
1658 &self.generator.sizes
1659 }
1660
1661 fn push_block(&mut self) {
1662 let prev = mem::take(&mut self.src);
1663 self.block_storage.push(prev);
1664 }
1665
1666 fn finish_block(&mut self, operands: &mut Vec<String>) {
1667 let to_restore = self.block_storage.pop().unwrap();
1668 let src = mem::replace(&mut self.src, to_restore);
1669 self.blocks.push((src, mem::take(operands)));
1670 }
1671
1672 fn return_pointer(&mut self, size: ArchitectureSize, align: Alignment) -> String {
1673 if self.in_import {
1674 self.return_area_size = self.return_area_size.max(size);
1675 self.return_area_align = self.return_area_align.max(align);
1676
1677 if !self.return_area_size.is_empty() {
1678 self.need_pinner = true;
1679 self.imports.insert(remote_pkg("runtime"));
1680 }
1681
1682 IMPORT_RETURN_AREA.into()
1683 } else {
1684 self.generator.return_area_size = self.generator.return_area_size.max(size);
1685 self.generator.return_area_align = self.generator.return_area_align.max(align);
1686 EXPORT_RETURN_AREA.into()
1687 }
1688 }
1689
1690 fn is_list_canonical(&self, _: &Resolve, ty: &Type) -> bool {
1691 matches!(
1692 ty,
1693 Type::U8
1694 | Type::S8
1695 | Type::U16
1696 | Type::S16
1697 | Type::U32
1698 | Type::S32
1699 | Type::U64
1700 | Type::S64
1701 | Type::F32
1702 | Type::F64
1703 )
1704 }
1705
1706 fn emit(
1707 &mut self,
1708 resolve: &Resolve,
1709 instruction: &Instruction<'_>,
1710 operands: &mut Vec<String>,
1711 results: &mut Vec<String>,
1712 ) {
1713 let store = |me: &mut Self, src, pointer, offset: &ArchitectureSize, ty| {
1714 me.need_unsafe = true;
1715 let offset = offset.format(POINTER_SIZE_EXPRESSION);
1716 uwriteln!(
1717 me.src,
1718 "*(*{ty})(unsafe.Add(unsafe.Pointer({pointer}), {offset})) = {src}"
1719 );
1720 };
1721 let load = |me: &mut Self,
1722 results: &mut Vec<String>,
1723 pointer,
1724 offset: &ArchitectureSize,
1725 ty,
1726 cast: &dyn Fn(String) -> String| {
1727 me.need_unsafe = true;
1728 let offset = offset.format(POINTER_SIZE_EXPRESSION);
1729 results.push(cast(format!(
1730 "*(*{ty})(unsafe.Add(unsafe.Pointer({pointer}), {offset}))"
1731 )));
1732 };
1733
1734 match instruction {
1735 Instruction::GetArg { nth } => results.push(self.param_names[*nth].clone()),
1736 Instruction::StringLower { .. } => {
1737 self.need_pinner = true;
1738 self.need_unsafe = true;
1739 let string = &operands[0];
1740 let utf8 = self.locals.tmp("utf8");
1741 uwriteln!(
1742 self.src,
1743 "{utf8} := unsafe.Pointer(unsafe.StringData({string}))\n\
1744 {PINNER}.Pin({utf8})"
1745 );
1746 results.push(format!("uintptr({utf8})"));
1747 results.push(format!("uint32(len({string}))"));
1748 }
1749 Instruction::StringLift { .. } => {
1750 self.need_unsafe = true;
1751 let pointer = &operands[0];
1752 let length = &operands[1];
1753 let value = self.locals.tmp("value");
1754 uwriteln!(
1755 self.src,
1756 "{value} := unsafe.String((*uint8)(unsafe.Pointer({pointer})), {length})"
1757 );
1758 results.push(value)
1759 }
1760 Instruction::ListCanonLower { .. } => {
1761 self.need_pinner = true;
1762 self.need_unsafe = true;
1763 let slice = &operands[0];
1764 let data = self.locals.tmp("data");
1765 uwriteln!(
1766 self.src,
1767 "{data} := unsafe.Pointer(unsafe.SliceData({slice}))\n\
1768 {PINNER}.Pin({data})"
1769 );
1770 results.push(format!("uintptr({data})"));
1771 results.push(format!("uint32(len({slice}))"));
1772 }
1773 Instruction::ListCanonLift { element, .. } => {
1774 self.need_unsafe = true;
1775 let pointer = &operands[0];
1776 let length = &operands[1];
1777 let ty = self.type_name(resolve, **element);
1778 let value = self.locals.tmp("value");
1779 uwriteln!(
1780 self.src,
1781 "{value} := unsafe.Slice((*{ty})(unsafe.Pointer({pointer})), {length})"
1782 );
1783 results.push(value)
1784 }
1785 Instruction::ListLower { element, .. } => {
1786 self.need_unsafe = true;
1787 self.need_pinner = true;
1788 self.imports.insert(remote_pkg("runtime"));
1789 let (body, _) = self.blocks.pop().unwrap();
1790 let value = &operands[0];
1791 let slice = self.locals.tmp("slice");
1792 let result = self.locals.tmp("result");
1793 let length = self.locals.tmp("length");
1794 let size = self
1795 .generator
1796 .sizes
1797 .size(element)
1798 .format(POINTER_SIZE_EXPRESSION);
1799 let align = self
1800 .generator
1801 .sizes
1802 .align(element)
1803 .format(POINTER_SIZE_EXPRESSION);
1804 uwriteln!(
1805 self.src,
1806 "{slice} := {value}
1807{length} := uint32(len({slice}))
1808{result} := witRuntime.Allocate({PINNER}, uintptr({length} * {size}), {align})
1809for index, {ITER_ELEMENT} := range {slice} {{
1810 {ITER_BASE_POINTER} := unsafe.Add({result}, index * {size})
1811 {body}
1812}}
1813"
1814 );
1815 results.push(format!("uintptr({result})"));
1816 results.push(length);
1817 }
1818 Instruction::ListLift { element, .. } => {
1819 self.need_unsafe = true;
1820 let (body, body_results) = self.blocks.pop().unwrap();
1821 let value = &operands[0];
1822 let length = &operands[1];
1823 let result = self.locals.tmp("result");
1824 let size = self
1825 .generator
1826 .sizes
1827 .size(element)
1828 .format(POINTER_SIZE_EXPRESSION);
1829 let element_type = self.type_name(resolve, **element);
1830 let body_result = &body_results[0];
1831 uwriteln!(
1832 self.src,
1833 "{result} := make([]{element_type}, 0, {length})
1834for index := 0; index < int({length}); index++ {{
1835 {ITER_BASE_POINTER} := unsafe.Add(unsafe.Pointer({value}), index * {size})
1836 {body}
1837 {result} = append({result}, {body_result})
1838}}
1839"
1840 );
1841 results.push(result);
1842 }
1843 Instruction::CallInterface { func, .. } => {
1844 if self.unpin_params {
1845 self.imports.insert(remote_pkg("runtime"));
1846 uwriteln!(self.src, "witRuntime.Unpin()");
1847 }
1848
1849 let name = func.item_name().to_upper_camel_case();
1850 let package = format!(
1851 "export_{}",
1852 self.generator.interface_name(resolve, self.interface)
1853 );
1854
1855 let call = match &func.kind {
1856 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {
1857 let args = operands.join(", ");
1858 let call = format!("{package}.{name}({args})");
1859 self.imports.insert(self.generator.mod_pkg(true, &package));
1860 call
1861 }
1862 FunctionKind::Constructor(ty) => {
1863 let args = operands.join(", ");
1864 let ty = resolve.types[*ty]
1865 .name
1866 .as_ref()
1867 .unwrap()
1868 .to_upper_camel_case();
1869 let call = format!("{package}.Make{ty}({args})");
1870 self.imports.insert(self.generator.mod_pkg(true, &package));
1871 call
1872 }
1873 FunctionKind::Method(_) | FunctionKind::AsyncMethod(_) => {
1874 let target = &operands[0];
1875 let args = operands[1..].join(", ");
1876 format!("({target}).{name}({args})")
1877 }
1878 FunctionKind::Static(ty) | FunctionKind::AsyncStatic(ty) => {
1879 let args = operands.join(", ");
1880 let ty = self.type_name(resolve, Type::Id(*ty));
1881 format!("{ty}{name}({args})")
1882 }
1883 };
1884
1885 if let Some(ty) = func.result {
1886 let result = self.locals.tmp("result");
1887 if let Type::Id(ty) = ty
1888 && let TypeDefKind::Tuple(tuple) = &resolve.types[ty].kind
1889 {
1890 let count = tuple.types.len();
1891 self.generator.tuples.insert(count);
1892 self.imports.insert(remote_pkg("types"));
1893
1894 let results = (0..count)
1895 .map(|_| self.locals.tmp("result"))
1896 .collect::<Vec<_>>()
1897 .join(", ");
1898
1899 let types = tuple
1900 .types
1901 .iter()
1902 .map(|&ty| self.type_name(resolve, ty))
1903 .collect::<Vec<_>>()
1904 .join(", ");
1905
1906 uwriteln!(
1907 self.src,
1908 "{results} := {call}
1909{result} := witTypes.Tuple{count}[{types}]{{{results}}}"
1910 );
1911 } else {
1912 uwriteln!(self.src, "{result} := {call}");
1913 }
1914 results.push(result);
1915 } else {
1916 uwriteln!(self.src, "{call}");
1917 }
1918 }
1919 Instruction::Return { func, .. } => {
1920 if let Some(ty) = func.result {
1921 let result = &operands[0];
1922 if self.in_import
1923 && let Type::Id(ty) = ty
1924 && let TypeDefKind::Tuple(tuple) = &resolve.types[ty].kind
1925 {
1926 let count = tuple.types.len();
1927 let tuple = self.locals.tmp("tuple");
1928
1929 let results = (0..count)
1930 .map(|index| format!("{tuple}.F{index}"))
1931 .collect::<Vec<_>>()
1932 .join(", ");
1933
1934 uwriteln!(
1935 self.src,
1936 "{tuple} := {result}
1937return {results}"
1938 );
1939 } else {
1940 uwriteln!(self.src, "return {result}");
1941 }
1942 }
1943 }
1944 Instruction::AsyncTaskReturn { .. } => {
1945 let name = self.name.unwrap();
1946 let args = operands.join(", ");
1947 uwriteln!(self.src, "wasm_export_task_return_{name}({args})");
1948 }
1949 Instruction::LengthStore { offset } => store(
1950 self,
1951 &format!("uint32({})", operands[0]),
1952 &operands[1],
1953 offset,
1954 "uint32",
1955 ),
1956 Instruction::PointerStore { offset } => store(
1957 self,
1958 &format!("uint32(uintptr({}))", operands[0]),
1959 &operands[1],
1960 offset,
1961 "uint32",
1962 ),
1963 Instruction::I32Store8 { offset } => store(
1964 self,
1965 &format!("int8({})", operands[0]),
1966 &operands[1],
1967 offset,
1968 "int8",
1969 ),
1970 Instruction::I32Store16 { offset } => store(
1971 self,
1972 &format!("int16({})", operands[0]),
1973 &operands[1],
1974 offset,
1975 "int16",
1976 ),
1977 Instruction::I32Store { offset } => {
1978 store(self, &operands[0], &operands[1], offset, "int32")
1979 }
1980 Instruction::I64Store { offset } => {
1981 store(self, &operands[0], &operands[1], offset, "int64")
1982 }
1983 Instruction::F32Store { offset } => {
1984 store(self, &operands[0], &operands[1], offset, "float32")
1985 }
1986 Instruction::F64Store { offset } => {
1987 store(self, &operands[0], &operands[1], offset, "float64")
1988 }
1989 Instruction::LengthLoad { offset } => {
1990 load(self, results, &operands[0], offset, "uint32", &|v| v)
1991 }
1992 Instruction::PointerLoad { offset } => {
1993 load(self, results, &operands[0], offset, "uint32", &|v| {
1994 format!("uintptr({v})")
1995 })
1996 }
1997 Instruction::I32Load8U { offset } => {
1998 load(self, results, &operands[0], offset, "uint32", &|v| {
1999 format!("uint8({v})")
2000 })
2001 }
2002 Instruction::I32Load8S { offset } => {
2003 load(self, results, &operands[0], offset, "uint32", &|v| {
2004 format!("int8({v})")
2005 })
2006 }
2007 Instruction::I32Load16U { offset } => {
2008 load(self, results, &operands[0], offset, "uint32", &|v| {
2009 format!("uint16({v})")
2010 })
2011 }
2012 Instruction::I32Load16S { offset } => {
2013 load(self, results, &operands[0], offset, "uint32", &|v| {
2014 format!("int16({v})")
2015 })
2016 }
2017 Instruction::I32Load { offset } => {
2018 load(self, results, &operands[0], offset, "int32", &|v| v)
2019 }
2020 Instruction::I64Load { offset } => {
2021 load(self, results, &operands[0], offset, "int64", &|v| v)
2022 }
2023 Instruction::F32Load { offset } => {
2024 load(self, results, &operands[0], offset, "float32", &|v| v)
2025 }
2026 Instruction::F64Load { offset } => {
2027 load(self, results, &operands[0], offset, "float64", &|v| v)
2028 }
2029 Instruction::BoolFromI32 => results.push(format!("({} != 0)", operands[0])),
2030 Instruction::U8FromI32 => results.push(format!("uint8({})", operands[0])),
2031 Instruction::S8FromI32 => results.push(format!("int8({})", operands[0])),
2032 Instruction::U16FromI32 => results.push(format!("uint16({})", operands[0])),
2033 Instruction::S16FromI32 => results.push(format!("int16({})", operands[0])),
2034 Instruction::U32FromI32 => results.push(format!("uint32({})", operands[0])),
2035 Instruction::S32FromI32 | Instruction::S64FromI64 => {
2036 results.push(operands.pop().unwrap())
2037 }
2038 Instruction::U64FromI64 => results.push(format!("uint64({})", operands[0])),
2039 Instruction::I32FromBool => {
2040 let value = &operands[0];
2041 let result = self.locals.tmp("result");
2042 uwriteln!(
2043 self.src,
2044 "var {result} int32
2045if {value} {{
2046 {result} = 1
2047}} else {{
2048 {result} = 0
2049}}"
2050 );
2051 results.push(result);
2052 }
2053 Instruction::I32FromU8
2054 | Instruction::I32FromS8
2055 | Instruction::I32FromU16
2056 | Instruction::I32FromS16
2057 | Instruction::I32FromU32 => {
2058 results.push(format!("int32({})", operands[0]));
2059 }
2060 Instruction::I32FromS32 | Instruction::I64FromS64 => {
2061 results.push(operands.pop().unwrap())
2062 }
2063 Instruction::I64FromU64 => results.push(format!("int64({})", operands[0])),
2064 Instruction::CoreF32FromF32
2065 | Instruction::CoreF64FromF64
2066 | Instruction::F32FromCoreF32
2067 | Instruction::F64FromCoreF64 => results.push(operands.pop().unwrap()),
2068 Instruction::CharFromI32 => results.push(format!("rune({})", operands[0])),
2069 Instruction::I32FromChar => results.push(format!("int32({})", operands[0])),
2070 Instruction::TupleLower { tuple, .. } => {
2071 let op = &operands[0];
2072 for index in 0..tuple.types.len() {
2073 results.push(format!("({op}).F{index}"));
2074 }
2075 }
2076 Instruction::TupleLift { tuple, .. } => {
2077 let count = tuple.types.len();
2078 self.generator.tuples.insert(count);
2079 let types = tuple
2080 .types
2081 .iter()
2082 .map(|&ty| self.type_name(resolve, ty))
2083 .collect::<Vec<_>>()
2084 .join(", ");
2085 let fields = operands.join(", ");
2086 self.imports.insert(remote_pkg("types"));
2087 results.push(format!("witTypes.Tuple{count}[{types}]{{{fields}}}"));
2088 }
2089 Instruction::FlagsLower { .. } => {
2090 let value = operands.pop().unwrap();
2091 results.push(format!("int32({value})"))
2092 }
2093 Instruction::FlagsLift { flags, .. } => {
2094 let value = operands.pop().unwrap();
2095 let repr = flags_repr(flags);
2096 results.push(format!("{repr}({value})"))
2097 }
2098 Instruction::RecordLower { record, .. } => {
2099 let op = &operands[0];
2100 for field in &record.fields {
2101 let field = field.name.to_upper_camel_case();
2102 results.push(format!("({op}).{field}"));
2103 }
2104 }
2105 Instruction::RecordLift { ty, .. } => {
2106 let name = self.type_name(resolve, Type::Id(*ty));
2107 let fields = operands.join(", ");
2108 results.push(format!("{name}{{{fields}}}"));
2109 }
2110 Instruction::OptionLower {
2111 results: result_types,
2112 ..
2113 } => {
2114 self.generator.need_option = true;
2115 self.imports.insert(remote_pkg("types"));
2116 let (some, some_results) = self.blocks.pop().unwrap();
2117 let (none, none_results) = self.blocks.pop().unwrap();
2118 let value = &operands[0];
2119
2120 let result_names = (0..result_types.len())
2121 .map(|_| self.locals.tmp("option"))
2122 .collect::<Vec<_>>();
2123
2124 let declarations = result_types
2125 .iter()
2126 .zip(&result_names)
2127 .map(|(ty, name)| {
2128 let ty = wasm_type(*ty);
2129 format!("var {name} {ty}")
2130 })
2131 .collect::<Vec<_>>()
2132 .join("\n");
2133
2134 let some_result_assignments = some_results
2135 .iter()
2136 .zip(&result_names)
2137 .map(|(result, name)| format!("{name} = {result}"))
2138 .collect::<Vec<_>>()
2139 .join("\n");
2140
2141 let none_result_assignments = none_results
2142 .iter()
2143 .zip(&result_names)
2144 .map(|(result, name)| format!("{name} = {result}"))
2145 .collect::<Vec<_>>()
2146 .join("\n");
2147
2148 results.extend(result_names);
2149
2150 uwriteln!(
2151 self.src,
2152 r#"{declarations}
2153switch {value}.Tag() {{
2154case witTypes.OptionNone:
2155 {none}
2156 {none_result_assignments}
2157case witTypes.OptionSome:
2158 {VARIANT_PAYLOAD_NAME} := {value}.Some()
2159 {some}
2160 {some_result_assignments}
2161default:
2162 panic("unreachable")
2163}}"#
2164 );
2165 }
2166 Instruction::OptionLift { ty, payload } => {
2167 self.generator.need_option = true;
2168 self.imports.insert(remote_pkg("types"));
2169 let (some, some_results) = self.blocks.pop().unwrap();
2170 let (none, none_results) = self.blocks.pop().unwrap();
2171 assert!(none_results.is_empty());
2172 assert!(some_results.len() == 1);
2173 let some_result = &some_results[0];
2174 let ty = self.type_name(resolve, Type::Id(*ty));
2175 let some_type = self.type_name(resolve, **payload);
2176 let result = self.locals.tmp("option");
2177 let tag = &operands[0];
2178 uwriteln!(
2179 self.src,
2180 r#"var {result} {ty}
2181switch {tag} {{
2182case 0:
2183 {none}
2184 {result} = witTypes.None[{some_type}]()
2185case 1:
2186 {some}
2187 {result} = witTypes.Some[{some_type}]({some_result})
2188default:
2189 panic("unreachable")
2190}}"#
2191 );
2192 results.push(result);
2193 }
2194 Instruction::ResultLower {
2195 result,
2196 results: result_types,
2197 ..
2198 } => {
2199 self.generator.need_result = true;
2200 self.imports.insert(remote_pkg("types"));
2201 let (err, err_results) = self.blocks.pop().unwrap();
2202 let (ok, ok_results) = self.blocks.pop().unwrap();
2203 let value = &operands[0];
2204
2205 let result_names = (0..result_types.len())
2206 .map(|_| self.locals.tmp("option"))
2207 .collect::<Vec<_>>();
2208
2209 let declarations = result_types
2210 .iter()
2211 .zip(&result_names)
2212 .map(|(ty, name)| {
2213 let ty = wasm_type(*ty);
2214 format!("var {name} {ty}")
2215 })
2216 .collect::<Vec<_>>()
2217 .join("\n");
2218
2219 let ok_result_assignments = ok_results
2220 .iter()
2221 .zip(&result_names)
2222 .map(|(result, name)| format!("{name} = {result}"))
2223 .collect::<Vec<_>>()
2224 .join("\n");
2225
2226 let err_result_assignments = err_results
2227 .iter()
2228 .zip(&result_names)
2229 .map(|(result, name)| format!("{name} = {result}"))
2230 .collect::<Vec<_>>()
2231 .join("\n");
2232
2233 results.extend(result_names);
2234
2235 let ok_set_payload = if result.ok.is_some() {
2236 format!("{VARIANT_PAYLOAD_NAME} := {value}.Ok()")
2237 } else {
2238 self.generator.need_unit = true;
2239 String::new()
2240 };
2241
2242 let err_set_payload = if result.err.is_some() {
2243 format!("{VARIANT_PAYLOAD_NAME} := {value}.Err()")
2244 } else {
2245 self.generator.need_unit = true;
2246 String::new()
2247 };
2248
2249 uwriteln!(
2250 self.src,
2251 r#"{declarations}
2252switch {value}.Tag() {{
2253case witTypes.ResultOk:
2254 {ok_set_payload}
2255 {ok}
2256 {ok_result_assignments}
2257case witTypes.ResultErr:
2258 {err_set_payload}
2259 {err}
2260 {err_result_assignments}
2261default:
2262 panic("unreachable")
2263}}"#
2264 );
2265 }
2266 Instruction::ResultLift { ty, result, .. } => {
2267 self.generator.need_result = true;
2268 self.imports.insert(remote_pkg("types"));
2269 let (err, err_results) = self.blocks.pop().unwrap();
2270 let (ok, ok_results) = self.blocks.pop().unwrap();
2271 assert_eq!(ok_results.is_empty(), result.ok.is_none());
2272 assert_eq!(err_results.is_empty(), result.err.is_none());
2273 let ok_result = if result.ok.is_some() {
2274 &ok_results[0]
2275 } else {
2276 self.generator.need_unit = true;
2277 "witTypes.Unit{}"
2278 };
2279 let err_result = if result.err.is_some() {
2280 &err_results[0]
2281 } else {
2282 self.generator.need_unit = true;
2283 "witTypes.Unit{}"
2284 };
2285 let ty = self.type_name(resolve, Type::Id(*ty));
2286 let ok_type = result
2287 .ok
2288 .map(|ty| self.type_name(resolve, ty))
2289 .unwrap_or_else(|| {
2290 self.generator.need_unit = true;
2291 "witTypes.Unit".into()
2292 });
2293 let err_type = result
2294 .err
2295 .map(|ty| self.type_name(resolve, ty))
2296 .unwrap_or_else(|| {
2297 self.generator.need_unit = true;
2298 "witTypes.Unit".into()
2299 });
2300 let result = self.locals.tmp("result");
2301 let tag = &operands[0];
2302 uwriteln!(
2303 self.src,
2304 r#"var {result} {ty}
2305switch {tag} {{
2306case 0:
2307 {ok}
2308 {result} = witTypes.Ok[{ok_type}, {err_type}]({ok_result})
2309case 1:
2310 {err}
2311 {result} = witTypes.Err[{ok_type}, {err_type}]({err_result})
2312default:
2313 panic("unreachable")
2314}}"#
2315 );
2316 results.push(result);
2317 }
2318 Instruction::EnumLower { .. } => results.push(format!("int32({})", operands[0])),
2319 Instruction::EnumLift { enum_, .. } => {
2320 results.push(format!("{}({})", int_repr(enum_.tag()), operands[0]))
2321 }
2322 Instruction::VariantLower {
2323 ty,
2324 variant,
2325 results: result_types,
2326 ..
2327 } => {
2328 let blocks = self
2329 .blocks
2330 .drain(self.blocks.len() - variant.cases.len()..)
2331 .collect::<Vec<_>>();
2332
2333 let ty = self.type_name(resolve, Type::Id(*ty));
2334 let value = &operands[0];
2335
2336 let result_names = (0..result_types.len())
2337 .map(|_| self.locals.tmp("variant"))
2338 .collect::<Vec<_>>();
2339
2340 let declarations = result_types
2341 .iter()
2342 .zip(&result_names)
2343 .map(|(ty, name)| {
2344 let ty = wasm_type(*ty);
2345 format!("var {name} {ty}")
2346 })
2347 .collect::<Vec<_>>()
2348 .join("\n");
2349
2350 let cases = variant
2351 .cases
2352 .iter()
2353 .zip(blocks)
2354 .map(|(case, (block, block_results))| {
2355 let assignments = result_names
2356 .iter()
2357 .zip(&block_results)
2358 .map(|(name, result)| format!("{name} = {result}"))
2359 .collect::<Vec<_>>()
2360 .join("\n");
2361
2362 let name = case.name.to_upper_camel_case();
2363
2364 let set_payload = if case.ty.is_some() {
2365 format!("{VARIANT_PAYLOAD_NAME} := {value}.{name}()")
2366 } else {
2367 String::new()
2368 };
2369
2370 format!(
2371 "case {ty}{name}:
2372 {set_payload}
2373 {block}
2374 {assignments}
2375"
2376 )
2377 })
2378 .collect::<Vec<_>>()
2379 .join("\n");
2380
2381 results.extend(result_names);
2382
2383 uwriteln!(
2384 self.src,
2385 r#"{declarations}
2386switch {value}.Tag() {{
2387{cases}
2388default:
2389 panic("unreachable")
2390}}"#
2391 );
2392 }
2393 Instruction::VariantLift { ty, variant, .. } => {
2394 let blocks = self
2395 .blocks
2396 .drain(self.blocks.len() - variant.cases.len()..)
2397 .collect::<Vec<_>>();
2398
2399 let ty = self.type_name(resolve, Type::Id(*ty));
2400 let result = self.locals.tmp("variant");
2401 let tag = &operands[0];
2402
2403 let (package, name) = if let Some(index) = ty.find('.') {
2404 (&ty[..index + 1], &ty[index + 1..])
2405 } else {
2406 ("", ty.as_str())
2407 };
2408
2409 let cases = variant
2410 .cases
2411 .iter()
2412 .zip(blocks)
2413 .enumerate()
2414 .map(|(index, (case, (block, block_results)))| {
2415 assert_eq!(block_results.is_empty(), case.ty.is_none());
2416 let payload = if case.ty.is_some() {
2417 &block_results[0]
2418 } else {
2419 ""
2420 };
2421 let case = case.name.to_upper_camel_case();
2422 format!(
2423 "case {index}:
2424 {block}
2425 {result} = {package}Make{name}{case}({payload})
2426"
2427 )
2428 })
2429 .collect::<Vec<_>>()
2430 .join("\n");
2431
2432 uwriteln!(
2433 self.src,
2434 r#"var {result} {ty}
2435switch {tag} {{
2436{cases}
2437default:
2438 panic("unreachable")
2439}}"#
2440 );
2441 results.push(result);
2442 }
2443 Instruction::VariantPayloadName => results.push(VARIANT_PAYLOAD_NAME.into()),
2444 Instruction::IterElem { .. } => results.push(ITER_ELEMENT.into()),
2445 Instruction::IterBasePointer => results.push(ITER_BASE_POINTER.into()),
2446 Instruction::I32Const { val } => results.push(format!("int32({val})")),
2447 Instruction::ConstZero { tys } => {
2448 results.extend(iter::repeat_with(|| "0".into()).take(tys.len()));
2449 }
2450 Instruction::Bitcasts { casts } => {
2451 results.extend(
2452 casts
2453 .iter()
2454 .zip(operands)
2455 .map(|(which, op)| cast(op, which, &mut self.need_math)),
2456 );
2457 }
2458 Instruction::FutureLower { .. }
2459 | Instruction::StreamLower { .. }
2460 | Instruction::HandleLower {
2461 handle: Handle::Own(_),
2462 ..
2463 } => {
2464 let op = &operands[0];
2465 if self.collect_lifters {
2466 self.lifter_count += 1;
2467 let resource = self.locals.tmp("resource");
2468 let handle = self.locals.tmp("handle");
2469 uwriteln!(
2470 self.src,
2471 "{resource} := {op}
2472{handle} := {resource}.TakeHandle()
2473lifters = append(lifters, func() {{
2474 {resource}.SetHandle({handle})
2475}})"
2476 );
2477 results.push(handle)
2478 } else {
2479 results.push(format!("({op}).TakeHandle()"))
2480 }
2481 }
2482 Instruction::HandleLower {
2483 handle: Handle::Borrow(_),
2484 ..
2485 } => results.push(format!("({}).Handle()", operands[0])),
2486 Instruction::HandleLift { handle, .. } => {
2487 let (which, resource) = match handle {
2488 Handle::Borrow(resource) => ("Borrow", resource),
2489 Handle::Own(resource) => ("Own", resource),
2490 };
2491 let handle = &operands[0];
2492 let ty = self.type_name(resolve, Type::Id(*resource));
2493 results.push(format!("{ty}From{which}Handle(int32(uintptr({handle})))"))
2494 }
2495 Instruction::CallWasm { sig, .. } => {
2496 let assignment = match &sig.results[..] {
2497 [] => String::new(),
2498 [_] => {
2499 let result = self.locals.tmp("result");
2500 let assignment = format!("{result} := ");
2501 results.push(result);
2502 assignment
2503 }
2504 _ => unreachable!(),
2505 };
2506 let name = &self.function_to_call;
2507 let params = operands.join(", ");
2508 uwriteln!(self.src, "{assignment}{name}({params})")
2509 }
2510 Instruction::Flush { amt } => {
2511 for op in operands.iter().take(*amt) {
2512 let result = self.locals.tmp("result");
2513 uwriteln!(self.src, "{result} := {op};");
2514 results.push(result);
2515 }
2516 }
2517 Instruction::FutureLift { ty, .. } => {
2518 let exported = self.generator.has_exported_resource(resolve, Type::Id(*ty));
2519 let owner = self
2520 .generator
2521 .futures_and_streams
2522 .get(&(*ty, exported))
2523 .unwrap()
2524 .clone();
2525 let package = self.package_for_owner(resolve, owner.as_ref(), *ty);
2526 let TypeDefKind::Future(payload_ty) = &resolve.types[*ty].kind else {
2527 unreachable!()
2528 };
2529 let camel = if let Some(ty) = payload_ty {
2530 self.generator
2531 .mangle_name(resolve, *ty, owner.as_ref())
2532 .to_upper_camel_case()
2533 } else {
2534 "Unit".into()
2535 };
2536 let handle = &operands[0];
2537 results.push(format!("{package}LiftFuture{camel}({handle})"));
2538 }
2539 Instruction::StreamLift { ty, .. } => {
2540 let exported = self.generator.has_exported_resource(resolve, Type::Id(*ty));
2541 let owner = self
2542 .generator
2543 .futures_and_streams
2544 .get(&(*ty, exported))
2545 .unwrap()
2546 .clone();
2547 let package = self.package_for_owner(resolve, owner.as_ref(), *ty);
2548 let TypeDefKind::Stream(payload_ty) = &resolve.types[*ty].kind else {
2549 unreachable!()
2550 };
2551 let camel = if let Some(ty) = payload_ty {
2552 self.generator
2553 .mangle_name(resolve, *ty, owner.as_ref())
2554 .to_upper_camel_case()
2555 } else {
2556 "Unit".into()
2557 };
2558 let handle = &operands[0];
2559 results.push(format!("{package}LiftStream{camel}({handle})"));
2560 }
2561 Instruction::MapLower { key, value, .. } => {
2562 self.need_unsafe = true;
2563 self.need_pinner = true;
2564 self.imports.insert(remote_pkg("runtime"));
2565 let (body, _) = self.blocks.pop().unwrap();
2566 let value_op = &operands[0];
2567 let src_map = self.locals.tmp("srcMap");
2568 let result = self.locals.tmp("result");
2569 let length = self.locals.tmp("length");
2570 let idx = self.locals.tmp("idx");
2571 let entry = self.generator.sizes.record([*key, *value]);
2572 let size = entry.size.format(POINTER_SIZE_EXPRESSION);
2573 let align = entry.align.format(POINTER_SIZE_EXPRESSION);
2574 uwriteln!(
2575 self.src,
2576 "{src_map} := {value_op}
2577{length} := uint32(len({src_map}))
2578{result} := witRuntime.Allocate({PINNER}, uintptr({length} * {size}), {align})
2579var {idx} int
2580for map_key, map_value := range {src_map} {{
2581 {ITER_BASE_POINTER} := unsafe.Add({result}, {idx} * {size})
2582 {body}
2583 {idx}++
2584}}
2585"
2586 );
2587 results.push(format!("uintptr({result})"));
2588 results.push(length);
2589 }
2590 Instruction::MapLift { key, value, .. } => {
2591 self.need_unsafe = true;
2592 let (body, body_results) = self.blocks.pop().unwrap();
2593 let pointer = &operands[0];
2594 let length = &operands[1];
2595 let result = self.locals.tmp("result");
2596 let entry = self.generator.sizes.record([*key, *value]);
2597 let size = entry.size.format(POINTER_SIZE_EXPRESSION);
2598 let key_type = self.type_name(resolve, **key);
2599 let value_type = self.type_name(resolve, **value);
2600 let body_key = &body_results[0];
2601 let body_value = &body_results[1];
2602 uwriteln!(
2603 self.src,
2604 "{result} := make(map[{key_type}]{value_type}, {length})
2605for index := 0; index < int({length}); index++ {{
2606 {ITER_BASE_POINTER} := unsafe.Add(unsafe.Pointer({pointer}), index * {size})
2607 {body}
2608 {result}[{body_key}] = {body_value}
2609}}
2610"
2611 );
2612 results.push(result);
2613 }
2614 Instruction::IterMapKey { .. } => results.push("map_key".into()),
2615 Instruction::IterMapValue { .. } => results.push("map_value".into()),
2616 Instruction::GuestDeallocateMap { .. } | Instruction::GuestDeallocate { .. } => {
2617 }
2619 _ => unimplemented!("{instruction:?}"),
2620 }
2621 }
2622}
2623
2624struct InterfaceGenerator<'a> {
2625 generator: &'a mut Go,
2626 resolve: &'a Resolve,
2627 interface: Option<(InterfaceId, &'a WorldKey)>,
2628 in_import: bool,
2629 src: String,
2630 imports: BTreeSet<String>,
2631 need_unsafe: bool,
2632 need_runtime: bool,
2633}
2634
2635impl<'a> InterfaceGenerator<'a> {
2636 fn new(
2637 generator: &'a mut Go,
2638 resolve: &'a Resolve,
2639 interface: Option<(InterfaceId, &'a WorldKey)>,
2640 in_import: bool,
2641 ) -> Self {
2642 Self {
2643 generator,
2644 resolve,
2645 interface,
2646 in_import,
2647 src: String::new(),
2648 imports: BTreeSet::new(),
2649 need_unsafe: false,
2650 need_runtime: false,
2651 }
2652 }
2653
2654 fn type_name(&mut self, resolve: &Resolve, ty: Type) -> String {
2655 self.generator.type_name(
2656 resolve,
2657 ty,
2658 self.interface.map(|(_, key)| key),
2659 self.in_import || !self.generator.has_exported_resource(resolve, ty),
2660 &mut self.imports,
2661 )
2662 }
2663}
2664
2665impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
2666 fn resolve(&self) -> &'a Resolve {
2667 self.resolve
2668 }
2669
2670 fn type_record(&mut self, _: TypeId, name: &str, record: &Record, docs: &Docs) {
2671 let name = name.to_upper_camel_case();
2672
2673 let fields = record
2674 .fields
2675 .iter()
2676 .map(|field| {
2677 let ty = self.type_name(self.resolve, field.ty);
2678 let docs = format_docs(&field.docs);
2679 let field = field.name.to_upper_camel_case();
2680 format!("{docs}{field} {ty}")
2681 })
2682 .collect::<Vec<_>>()
2683 .join("\n");
2684
2685 let docs = format_docs(docs);
2686
2687 uwriteln!(
2688 self.src,
2689 "
2690{docs}type {name} struct {{
2691 {fields}
2692}}"
2693 )
2694 }
2695
2696 fn type_resource(&mut self, id: TypeId, name: &str, docs: &Docs) {
2697 self.generator.resources.insert(
2698 id,
2699 if self.in_import {
2700 Direction::Import
2701 } else {
2702 Direction::Export
2703 },
2704 );
2705
2706 let camel = name.to_upper_camel_case();
2707 let module = self
2708 .interface
2709 .map(|(_, key)| self.resolve.name_world_key(key))
2710 .unwrap_or_else(|| "$root".into());
2711
2712 if self.in_import {
2713 self.imports.insert(remote_pkg("runtime"));
2714 self.need_runtime = true;
2715 let docs = format_docs(docs);
2716 uwriteln!(
2717 self.src,
2718 r#"
2719//go:wasmimport {module} [resource-drop]{name}
2720func resourceDrop{camel}(handle int32)
2721
2722{docs}type {camel} struct {{
2723 handle *witRuntime.Handle
2724}}
2725
2726func (self *{camel}) TakeHandle() int32 {{
2727 return self.handle.Take()
2728}}
2729
2730func (self *{camel}) SetHandle(handle int32) {{
2731 self.handle.Set(handle)
2732}}
2733
2734func (self *{camel}) Handle() int32 {{
2735 return self.handle.Use()
2736}}
2737
2738func (self *{camel}) Drop() {{
2739 handle := self.handle.TakeOrNil()
2740 if handle != 0 {{
2741 resourceDrop{camel}(handle)
2742 }}
2743}}
2744
2745func {camel}FromOwnHandle(handleValue int32) *{camel} {{
2746 handle := witRuntime.MakeHandle(handleValue)
2747 value := &{camel}{{handle}}
2748 runtime.AddCleanup(value, func(_ int) {{
2749 handleValue := handle.TakeOrNil()
2750 if handleValue != 0 {{
2751 resourceDrop{camel}(handleValue)
2752 }}
2753 }}, 0)
2754 return value
2755}}
2756
2757func {camel}FromBorrowHandle(handleValue int32) *{camel} {{
2758 handle := witRuntime.MakeHandle(handleValue)
2759 return &{camel}{{handle}}
2760}}
2761"#
2762 );
2763 } else {
2764 self.need_unsafe = true;
2765 uwriteln!(
2766 self.src,
2767 r#"
2768//go:wasmimport [export]{module} [resource-new]{name}
2769func resourceNew{camel}(pointer unsafe.Pointer) int32
2770
2771//go:wasmimport [export]{module} [resource-rep]{name}
2772func resourceRep{camel}(handle int32) unsafe.Pointer
2773
2774//go:wasmimport [export]{module} [resource-drop]{name}
2775func resourceDrop{camel}(handle int32)
2776
2777//go:wasmexport {module}#[dtor]{name}
2778func resourceDtor{camel}(rep int32) {{
2779 val := (*{camel})(unsafe.Pointer(uintptr(rep)))
2780 val.handle = 0
2781 val.pinner.Unpin()
2782 val.OnDrop()
2783}}
2784
2785func (self *{camel}) TakeHandle() int32 {{
2786 self.pinner.Pin(self)
2787 self.handle = resourceNew{camel}(unsafe.Pointer(self))
2788 return self.handle
2789}}
2790
2791func (self *{camel}) SetHandle(handle int32) {{
2792 if self.handle != handle {{
2793 panic("invalid handle")
2794 }}
2795}}
2796
2797func (self *{camel}) Drop() {{
2798 handle := self.handle
2799 if self.handle != 0 {{
2800 self.handle = 0
2801 resourceDrop{camel}(handle)
2802 self.pinner.Unpin()
2803 self.OnDrop()
2804 }}
2805}}
2806
2807func {camel}FromOwnHandle(handle int32) *{camel} {{
2808 return (*{camel})(unsafe.Pointer(resourceRep{camel}(handle)))
2809}}
2810
2811func {camel}FromBorrowHandle(rep int32) *{camel} {{
2812 return (*{camel})(unsafe.Pointer(uintptr(rep)))
2813}}
2814"#
2815 );
2816
2817 if self.generator.opts.generate_stubs {
2818 self.need_runtime = true;
2819 uwriteln!(
2820 self.src,
2821 r#"
2822type {camel} struct {{
2823 pinner runtime.Pinner
2824 handle int32
2825}}
2826
2827func (self *{camel}) OnDrop() {{}}
2828"#
2829 );
2830 }
2831 }
2832 }
2833
2834 fn type_flags(&mut self, _: TypeId, name: &str, flags: &Flags, docs: &Docs) {
2835 let repr = flags_repr(flags);
2836
2837 let name = name.to_upper_camel_case();
2838
2839 let constants = flags
2840 .flags
2841 .iter()
2842 .enumerate()
2843 .map(|(i, flag)| {
2844 let docs = format_docs(&flag.docs);
2845 let flag = flag.name.to_upper_camel_case();
2846 format!("{docs}{name}{flag} {repr} = 1 << {i}")
2847 })
2848 .collect::<Vec<_>>()
2849 .join("\n");
2850
2851 let docs = format_docs(docs);
2852
2853 uwriteln!(
2854 self.src,
2855 "
2856const (
2857{constants}
2858)
2859
2860{docs}type {name} = {repr}"
2861 )
2862 }
2863
2864 fn type_tuple(&mut self, _: TypeId, name: &str, tuple: &Tuple, docs: &Docs) {
2865 self.imports.insert(remote_pkg("types"));
2866 let count = tuple.types.len();
2867 self.generator.tuples.insert(count);
2868 let name = name.to_upper_camel_case();
2869 let docs = format_docs(docs);
2870 let types = tuple
2871 .types
2872 .iter()
2873 .map(|ty| self.type_name(self.resolve, *ty))
2874 .collect::<Vec<_>>()
2875 .join(", ");
2876
2877 uwriteln!(
2878 self.src,
2879 "{docs}type {name} = witTypes.Tuple{count}[{types}]"
2880 );
2881 }
2882
2883 fn type_variant(&mut self, _: TypeId, name: &str, variant: &Variant, docs: &Docs) {
2884 let repr = int_repr(variant.tag());
2885
2886 let name = name.to_upper_camel_case();
2887
2888 let constants = variant
2889 .cases
2890 .iter()
2891 .enumerate()
2892 .map(|(i, case)| {
2893 let docs = format_docs(&case.docs);
2894 let case = case.name.to_upper_camel_case();
2895 format!("{docs}{name}{case} {repr} = {i}")
2896 })
2897 .collect::<Vec<_>>()
2898 .join("\n");
2899
2900 let getters = variant
2901 .cases
2902 .iter()
2903 .filter_map(|case| {
2904 case.ty.map(|ty| {
2905 let case = case.name.to_upper_camel_case();
2906 let ty = self.type_name(self.resolve, ty);
2907 format!(
2908 r#"func (self {name}) {case}() {ty} {{
2909 if self.tag != {name}{case} {{
2910 panic("tag mismatch")
2911 }}
2912 return self.value.({ty})
2913}}
2914"#
2915 )
2916 })
2917 })
2918 .collect::<Vec<_>>()
2919 .concat();
2920
2921 let constructors = variant
2922 .cases
2923 .iter()
2924 .map(|case| {
2925 let (param, value) = if let Some(ty) = case.ty {
2926 let ty = self.type_name(self.resolve, ty);
2927 (format!("value {ty}"), "value")
2928 } else {
2929 (String::new(), "nil")
2930 };
2931 let case = case.name.to_upper_camel_case();
2932 format!(
2933 r#"func Make{name}{case}({param}) {name} {{
2934 return {name}{{{name}{case}, {value}}}
2935}}
2936"#
2937 )
2938 })
2939 .collect::<Vec<_>>()
2940 .concat();
2941
2942 let docs = format_docs(docs);
2943
2944 uwriteln!(
2945 self.src,
2946 "
2947const (
2948{constants}
2949)
2950
2951{docs}type {name} struct {{
2952 tag {repr}
2953 value any
2954}}
2955
2956func (self {name}) Tag() {repr} {{
2957 return self.tag
2958}}
2959
2960{getters}
2961{constructors}
2962"
2963 )
2964 }
2965
2966 fn type_option(&mut self, _: TypeId, name: &str, payload: &Type, docs: &Docs) {
2967 self.generator.need_option = true;
2968 self.imports.insert(remote_pkg("types"));
2969 let name = name.to_upper_camel_case();
2970 let ty = self.type_name(self.resolve, *payload);
2971 let docs = format_docs(docs);
2972 uwriteln!(self.src, "{docs}type {name} = witTypes.Option[{ty}]");
2973 }
2974
2975 fn type_result(&mut self, _: TypeId, name: &str, result: &Result_, docs: &Docs) {
2976 self.generator.need_result = true;
2977 self.imports.insert(remote_pkg("types"));
2978 let name = name.to_upper_camel_case();
2979 let ok_type = result
2980 .ok
2981 .map(|ty| self.type_name(self.resolve, ty))
2982 .unwrap_or_else(|| {
2983 self.generator.need_unit = true;
2984 "witTypes.Unit".into()
2985 });
2986 let err_type = result
2987 .err
2988 .map(|ty| self.type_name(self.resolve, ty))
2989 .unwrap_or_else(|| {
2990 self.generator.need_unit = true;
2991 "witTypes.Unit".into()
2992 });
2993 let docs = format_docs(docs);
2994 uwriteln!(
2995 self.src,
2996 "{docs}type {name} = witTypes.Result[{ok_type}, {err_type}]"
2997 );
2998 }
2999
3000 fn type_enum(&mut self, _: TypeId, name: &str, enum_: &Enum, docs: &Docs) {
3001 let repr = int_repr(enum_.tag());
3002
3003 let name = name.to_upper_camel_case();
3004
3005 let constants = enum_
3006 .cases
3007 .iter()
3008 .enumerate()
3009 .map(|(i, case)| {
3010 let docs = format_docs(&case.docs);
3011 let case = case.name.to_upper_camel_case();
3012 format!("{docs}{name}{case} {repr} = {i}")
3013 })
3014 .collect::<Vec<_>>()
3015 .join("\n");
3016
3017 let docs = format_docs(docs);
3018
3019 uwriteln!(
3020 self.src,
3021 "
3022const (
3023 {constants}
3024)
3025{docs}type {name} = {repr}"
3026 )
3027 }
3028
3029 fn type_alias(&mut self, _: TypeId, name: &str, ty: &Type, docs: &Docs) {
3030 let name = name.to_upper_camel_case();
3031 let ty = self.type_name(self.resolve, *ty);
3032 let docs = format_docs(docs);
3033 uwriteln!(self.src, "{docs}type {name} = {ty}");
3034 }
3035
3036 fn type_list(&mut self, _: TypeId, name: &str, ty: &Type, docs: &Docs) {
3037 let name = name.to_upper_camel_case();
3038 let ty = self.type_name(self.resolve, *ty);
3039 let docs = format_docs(docs);
3040 uwriteln!(self.src, "{docs}type {name} = []{ty}");
3041 }
3042
3043 fn type_fixed_length_list(&mut self, _: TypeId, name: &str, ty: &Type, size: u32, docs: &Docs) {
3044 let name = name.to_upper_camel_case();
3045 let ty = self.type_name(self.resolve, *ty);
3046 let docs = format_docs(docs);
3047 uwriteln!(self.src, "{docs}type {name} = [{size}]{ty}");
3048 }
3049
3050 fn type_map(&mut self, _id: TypeId, name: &str, key: &Type, value: &Type, docs: &Docs) {
3051 let name = name.to_upper_camel_case();
3052 let key = self.type_name(self.resolve, *key);
3053 let value = self.type_name(self.resolve, *value);
3054 let docs = format_docs(docs);
3055 uwriteln!(self.src, "{docs}type {name} = map[{key}]{value}");
3056 }
3057
3058 fn type_builtin(&mut self, id: TypeId, name: &str, ty: &Type, docs: &Docs) {
3059 _ = (id, name, ty, docs);
3060 todo!()
3061 }
3062
3063 fn type_future(&mut self, id: TypeId, name: &str, _: &Option<Type>, docs: &Docs) {
3064 let name = name.to_upper_camel_case();
3065 let ty = self.type_name(self.resolve, Type::Id(id));
3066 let docs = format_docs(docs);
3067 uwriteln!(self.src, "{docs}type {name} = {ty}");
3068 }
3069
3070 fn type_stream(&mut self, id: TypeId, name: &str, _: &Option<Type>, docs: &Docs) {
3071 let name = name.to_upper_camel_case();
3072 let ty = self.type_name(self.resolve, Type::Id(id));
3073 let docs = format_docs(docs);
3074 uwriteln!(self.src, "{docs}type {name} = {ty}");
3075 }
3076}
3077
3078fn wasm_type(ty: WasmType) -> &'static str {
3079 match ty {
3080 WasmType::I32 => "int32",
3081 WasmType::I64 => "int64",
3082 WasmType::F32 => "float32",
3083 WasmType::F64 => "float64",
3084 WasmType::Pointer => "uintptr",
3085 WasmType::PointerOrI64 => "int64",
3086 WasmType::Length => "uint32",
3087 }
3088}
3089
3090fn format_docs(docs: &Docs) -> String {
3091 docs.contents
3092 .as_ref()
3093 .map(|v| {
3094 v.trim()
3095 .lines()
3096 .map(|line| format!("// {line}\n"))
3097 .collect::<Vec<_>>()
3098 .concat()
3099 })
3100 .unwrap_or_default()
3101}
3102
3103fn flags_repr(flags: &Flags) -> &'static str {
3104 match flags.repr() {
3105 FlagsRepr::U8 => "uint8",
3106 FlagsRepr::U16 => "uint16",
3107 FlagsRepr::U32(1) => "uint32",
3108 _ => unreachable!(),
3109 }
3110}
3111
3112fn int_repr(int: Int) -> &'static str {
3113 match int {
3114 Int::U8 => "uint8",
3115 Int::U16 => "uint16",
3116 Int::U32 => "uint32",
3117 Int::U64 => unreachable!(),
3118 }
3119}
3120
3121fn cast(op: &str, which: &Bitcast, need_math: &mut bool) -> String {
3122 match which {
3123 Bitcast::I32ToF32 | Bitcast::I64ToF32 => {
3124 *need_math = true;
3125 format!("math.Float32frombits(uint32({op}))")
3126 }
3127 Bitcast::F32ToI32 => {
3128 *need_math = true;
3129 format!("int32(math.Float32bits({op}))")
3130 }
3131 Bitcast::F32ToI64 => {
3132 *need_math = true;
3133 format!("int64(math.Float32bits({op}))")
3134 }
3135 Bitcast::I64ToF64 => {
3136 *need_math = true;
3137 format!("math.Float64frombits(uint64({op}))")
3138 }
3139 Bitcast::F64ToI64 => {
3140 *need_math = true;
3141 format!("int64(math.Float64bits({op}))")
3142 }
3143 Bitcast::I32ToI64 | Bitcast::LToI64 => {
3144 format!("int64({op})")
3145 }
3146 Bitcast::PToP64 => {
3147 format!("int64({op})")
3148 }
3149 Bitcast::I64ToI32 | Bitcast::I64ToL | Bitcast::PToI32 => {
3150 format!("int32({op})")
3151 }
3152 Bitcast::I64ToP64 | Bitcast::P64ToI64 => op.into(),
3153 Bitcast::P64ToP | Bitcast::LToP | Bitcast::I32ToP => {
3154 format!("uintptr({op})")
3155 }
3156 Bitcast::PToL => {
3157 format!("uint32({op})")
3158 }
3159 Bitcast::I32ToL => {
3160 format!("uint32({op})")
3161 }
3162 Bitcast::LToI32 => {
3163 format!("uint32({op})")
3164 }
3165 Bitcast::None => op.to_string(),
3166 Bitcast::Sequence(sequence) => {
3167 let [first, second] = &**sequence;
3168 let inner = cast(op, first, need_math);
3169 cast(&inner, second, need_math)
3170 }
3171 }
3172}
3173
3174fn any(resolve: &Resolve, ty: Type, fun: &dyn Fn(Type) -> bool) -> bool {
3175 if fun(ty) {
3176 return true;
3177 }
3178
3179 match ty {
3180 Type::Bool
3181 | Type::U8
3182 | Type::S8
3183 | Type::U16
3184 | Type::S16
3185 | Type::U32
3186 | Type::S32
3187 | Type::U64
3188 | Type::S64
3189 | Type::F32
3190 | Type::F64
3191 | Type::Char
3192 | Type::String => false,
3193 Type::Id(id) => {
3194 let ty = &resolve.types[id];
3195 match &ty.kind {
3196 TypeDefKind::Flags(_) | TypeDefKind::Enum(_) | TypeDefKind::Resource => false,
3197 TypeDefKind::Handle(Handle::Own(resource) | Handle::Borrow(resource)) => {
3198 any(resolve, Type::Id(*resource), fun)
3199 }
3200 TypeDefKind::Record(record) => record
3201 .fields
3202 .iter()
3203 .any(|field| any(resolve, field.ty, fun)),
3204 TypeDefKind::Variant(variant) => variant
3205 .cases
3206 .iter()
3207 .any(|case| case.ty.map(|ty| any(resolve, ty, fun)).unwrap_or(false)),
3208 TypeDefKind::Option(ty) | TypeDefKind::List(ty) | TypeDefKind::Type(ty) => {
3209 any(resolve, *ty, fun)
3210 }
3211 TypeDefKind::Result(result) => result
3212 .ok
3213 .map(|ty| any(resolve, ty, fun))
3214 .or_else(|| result.err.map(|ty| any(resolve, ty, fun)))
3215 .unwrap_or(false),
3216 TypeDefKind::Tuple(tuple) => tuple.types.iter().any(|ty| any(resolve, *ty, fun)),
3217 TypeDefKind::Future(ty) | TypeDefKind::Stream(ty) => {
3218 ty.map(|ty| any(resolve, ty, fun)).unwrap_or(false)
3219 }
3220 TypeDefKind::Map(key, value) => {
3221 any(resolve, *key, fun) || any(resolve, *value, fun)
3222 }
3223 _ => todo!("{:?}", ty.kind),
3224 }
3225 }
3226 _ => todo!("{ty:?}"),
3227 }
3228}
3229
3230fn func_declaration(resolve: &Resolve, func: &Function) -> (String, bool) {
3231 match &func.kind {
3232 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {
3233 (func.item_name().to_upper_camel_case(), false)
3234 }
3235 FunctionKind::Constructor(ty) => {
3236 let ty = resolve.types[*ty]
3237 .name
3238 .as_ref()
3239 .unwrap()
3240 .to_upper_camel_case();
3241 (format!("Make{ty}"), false)
3242 }
3243 FunctionKind::Method(ty) | FunctionKind::AsyncMethod(ty) => {
3244 let ty = resolve.types[*ty]
3245 .name
3246 .as_ref()
3247 .unwrap()
3248 .to_upper_camel_case();
3249 let camel = func.item_name().to_upper_camel_case();
3250 (format!("(self *{ty}) {camel}"), true)
3251 }
3252 FunctionKind::Static(ty) | FunctionKind::AsyncStatic(ty) => {
3253 let ty = resolve.types[*ty]
3254 .name
3255 .as_ref()
3256 .unwrap()
3257 .to_upper_camel_case();
3258 let camel = func.item_name().to_upper_camel_case();
3259 (format!("{ty}{camel}"), false)
3260 }
3261 }
3262}
3263
3264fn maybe_gofmt<'a>(format: Format, code: &'a [u8]) -> Cow<'a, [u8]> {
3265 thread::scope(|s| {
3266 if let Format::True = format
3267 && let Ok((reader, mut writer)) = io::pipe()
3268 {
3269 s.spawn(move || {
3270 _ = writer.write_all(code);
3271 });
3272
3273 if let Ok(output) = Command::new("gofmt").stdin(reader).output()
3274 && output.status.success()
3275 {
3276 return Cow::Owned(output.stdout);
3277 }
3278 }
3279
3280 Cow::Borrowed(code)
3281 })
3282}