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