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