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