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