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