Skip to content

Commit 6a13b24

Browse files
authored
add --include-versions option to Go generator (#1574)
By default, the Go generator (like the C generator) will generate symbols which include the WIT package version in the name only if the target world references more than one version of that package. However, that makes publishing bindings in a library hazardous, because the name of that symbol will change if the world is updated to reference a second version of the package. This new option allows the user to override the default and include the versions in names unconditionally.
1 parent 4efab38 commit 6a13b24

File tree

1 file changed

+65
-46
lines changed

1 file changed

+65
-46
lines changed

crates/go/src/lib.rs

Lines changed: 65 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,15 @@ pub struct Opts {
130130
/// Must be specified in addition to the `pkg-name` flag.
131131
#[cfg_attr(feature = "clap", clap(long))]
132132
pub print_remote_pkg_version: bool,
133+
134+
/// When generating Go package names, include the WIT package version even
135+
/// if only one version of that package is referenced by the specified
136+
/// world.
137+
///
138+
/// By default, the version will only be included in the name if the world
139+
/// references more than one version of the WIT package.
140+
#[cfg_attr(feature = "clap", clap(long))]
141+
pub include_versions: bool,
133142
}
134143

135144
impl Opts {
@@ -242,7 +251,7 @@ impl Go {
242251
if local == owner && (exported ^ in_import) {
243252
String::new()
244253
} else {
245-
let package = interface_name(resolve, owner);
254+
let package = self.interface_name(resolve, owner);
246255
let package = if exported {
247256
format!("export_{package}")
248257
} else {
@@ -623,7 +632,7 @@ func Lift{upper_kind}{camel}(handle int32) *witTypes.{upper_kind}Reader[{payload
623632
} else {
624633
format!(
625634
"{}_",
626-
interface_name(
635+
self.interface_name(
627636
resolve,
628637
Some(
629638
&self
@@ -735,7 +744,7 @@ impl WorldGenerator for Go {
735744
data.extend(self.import(resolve, func, Some(name)));
736745
}
737746
self.interfaces
738-
.entry(interface_name(resolve, Some(name)))
747+
.entry(self.interface_name(resolve, Some(name)))
739748
.or_default()
740749
.extend(data);
741750

@@ -754,7 +763,7 @@ impl WorldGenerator for Go {
754763
data.extend(self.import(resolve, func, None));
755764
}
756765
self.interfaces
757-
.entry(interface_name(resolve, None))
766+
.entry(self.interface_name(resolve, None))
758767
.or_default()
759768
.extend(data);
760769
}
@@ -783,12 +792,13 @@ impl WorldGenerator for Go {
783792

784793
let data = generator.into();
785794

795+
let name = self.interface_name(resolve, Some(name));
786796
if exported {
787797
&mut self.export_interfaces
788798
} else {
789799
&mut self.interfaces
790800
}
791-
.entry(interface_name(resolve, Some(name)))
801+
.entry(name)
792802
.or_default()
793803
.extend(data);
794804
}
@@ -831,7 +841,7 @@ impl WorldGenerator for Go {
831841
}
832842
let data = generator.into();
833843
self.interfaces
834-
.entry(interface_name(resolve, None))
844+
.entry(self.interface_name(resolve, None))
835845
.or_default()
836846
.extend(data);
837847
}
@@ -1226,7 +1236,7 @@ func {camel}({go_params}) {go_results} {{
12261236
let sig = resolve.wasm_signature(variant, func);
12271237
let core_module_name = interface.map(|v| resolve.name_world_key(v));
12281238
let export_name = func.legacy_core_export_name(core_module_name.as_deref());
1229-
let name = func_name(resolve, interface, func);
1239+
let name = self.func_name(resolve, interface, func);
12301240

12311241
let params = sig
12321242
.params
@@ -1351,7 +1361,7 @@ func wasm_export_post_return_{name}(result {results}) {{
13511361
let results = self.func_results(resolve, func, interface, false, &mut imports);
13521362

13531363
self.export_interfaces
1354-
.entry(interface_name(resolve, interface))
1364+
.entry(self.interface_name(resolve, interface))
13551365
.or_default()
13561366
.extend(InterfaceData {
13571367
code: format!(
@@ -1470,12 +1480,13 @@ func wasm_export_{name}({params}) {results} {{
14701480
&func.name,
14711481
);
14721482

1483+
let name = self.interface_name(resolve, interface);
14731484
if in_import || !exported {
14741485
&mut self.interfaces
14751486
} else {
14761487
&mut self.export_interfaces
14771488
}
1478-
.entry(interface_name(resolve, interface))
1489+
.entry(name)
14791490
.or_default()
14801491
.extend(data);
14811492
}
@@ -1494,6 +1505,47 @@ func wasm_export_{name}({params}) {results} {{
14941505
}
14951506
})
14961507
}
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+
}
14971549
}
14981550

14991551
struct FunctionGenerator<'a> {
@@ -1783,7 +1835,10 @@ for index := 0; index < int({length}); index++ {{
17831835
}
17841836

17851837
let name = func.item_name().to_upper_camel_case();
1786-
let package = format!("export_{}", interface_name(resolve, self.interface));
1838+
let package = format!(
1839+
"export_{}",
1840+
self.generator.interface_name(resolve, self.interface)
1841+
);
17871842

17881843
let call = match &func.kind {
17891844
FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {
@@ -2945,42 +3000,6 @@ const (
29453000
}
29463001
}
29473002

2948-
fn interface_name(resolve: &Resolve, interface: Option<&WorldKey>) -> String {
2949-
match interface {
2950-
Some(WorldKey::Name(name)) => name.to_snake_case(),
2951-
Some(WorldKey::Interface(id)) => {
2952-
let interface = &resolve.interfaces[*id];
2953-
let package = &resolve.packages[interface.package.unwrap()];
2954-
let package_has_multiple_versions = resolve.packages.iter().any(|(_, p)| {
2955-
p.name.namespace == package.name.namespace
2956-
&& p.name.name == package.name.name
2957-
&& p.name.version != package.name.version
2958-
});
2959-
let version = if package_has_multiple_versions {
2960-
if let Some(version) = &package.name.version {
2961-
format!("{}_", version.to_string().replace(['.', '-', '+'], "_"))
2962-
} else {
2963-
String::new()
2964-
}
2965-
} else {
2966-
String::new()
2967-
};
2968-
let namespace = package.name.namespace.to_snake_case();
2969-
let package = package.name.name.to_snake_case();
2970-
let interface = interface.name.as_ref().unwrap().to_snake_case();
2971-
format!("{namespace}_{package}_{version}{interface}")
2972-
}
2973-
None => "wit_world".into(),
2974-
}
2975-
}
2976-
2977-
fn func_name(resolve: &Resolve, interface: Option<&WorldKey>, func: &Function) -> String {
2978-
let prefix = interface_name(resolve, interface);
2979-
let name = func.name.to_snake_case().replace('.', "_");
2980-
2981-
format!("{prefix}_{name}")
2982-
}
2983-
29843003
fn wasm_type(ty: WasmType) -> &'static str {
29853004
match ty {
29863005
WasmType::I32 => "int32",

0 commit comments

Comments
 (0)