Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 65 additions & 46 deletions crates/go/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,15 @@ pub struct Opts {
/// Must be specified in addition to the `pkg-name` flag.
#[cfg_attr(feature = "clap", clap(long))]
pub print_remote_pkg_version: bool,

/// When generating Go package names, include the WIT package version even
/// if only one version of that package is referenced by the specified
/// world.
///
/// By default, the version will only be included in the name if the world
/// references more than one version of the WIT package.
#[cfg_attr(feature = "clap", clap(long))]
pub include_versions: bool,
}

impl Opts {
Expand Down Expand Up @@ -242,7 +251,7 @@ impl Go {
if local == owner && (exported ^ in_import) {
String::new()
} else {
let package = interface_name(resolve, owner);
let package = self.interface_name(resolve, owner);
let package = if exported {
format!("export_{package}")
} else {
Expand Down Expand Up @@ -623,7 +632,7 @@ func Lift{upper_kind}{camel}(handle int32) *witTypes.{upper_kind}Reader[{payload
} else {
format!(
"{}_",
interface_name(
self.interface_name(
resolve,
Some(
&self
Expand Down Expand Up @@ -735,7 +744,7 @@ impl WorldGenerator for Go {
data.extend(self.import(resolve, func, Some(name)));
}
self.interfaces
.entry(interface_name(resolve, Some(name)))
.entry(self.interface_name(resolve, Some(name)))
.or_default()
.extend(data);

Expand All @@ -754,7 +763,7 @@ impl WorldGenerator for Go {
data.extend(self.import(resolve, func, None));
}
self.interfaces
.entry(interface_name(resolve, None))
.entry(self.interface_name(resolve, None))
.or_default()
.extend(data);
}
Expand Down Expand Up @@ -783,12 +792,13 @@ impl WorldGenerator for Go {

let data = generator.into();

let name = self.interface_name(resolve, Some(name));
if exported {
&mut self.export_interfaces
} else {
&mut self.interfaces
}
.entry(interface_name(resolve, Some(name)))
.entry(name)
.or_default()
.extend(data);
}
Expand Down Expand Up @@ -831,7 +841,7 @@ impl WorldGenerator for Go {
}
let data = generator.into();
self.interfaces
.entry(interface_name(resolve, None))
.entry(self.interface_name(resolve, None))
.or_default()
.extend(data);
}
Expand Down Expand Up @@ -1226,7 +1236,7 @@ func {camel}({go_params}) {go_results} {{
let sig = resolve.wasm_signature(variant, func);
let core_module_name = interface.map(|v| resolve.name_world_key(v));
let export_name = func.legacy_core_export_name(core_module_name.as_deref());
let name = func_name(resolve, interface, func);
let name = self.func_name(resolve, interface, func);

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

self.export_interfaces
.entry(interface_name(resolve, interface))
.entry(self.interface_name(resolve, interface))
.or_default()
.extend(InterfaceData {
code: format!(
Expand Down Expand Up @@ -1470,12 +1480,13 @@ func wasm_export_{name}({params}) {results} {{
&func.name,
);

let name = self.interface_name(resolve, interface);
if in_import || !exported {
&mut self.interfaces
} else {
&mut self.export_interfaces
}
.entry(interface_name(resolve, interface))
.entry(name)
.or_default()
.extend(data);
}
Expand All @@ -1494,6 +1505,47 @@ func wasm_export_{name}({params}) {results} {{
}
})
}

fn interface_name(&self, resolve: &Resolve, interface: Option<&WorldKey>) -> String {
match interface {
Some(WorldKey::Name(name)) => name.to_snake_case(),
Some(WorldKey::Interface(id)) => {
let interface = &resolve.interfaces[*id];
let package = &resolve.packages[interface.package.unwrap()];
let package_has_multiple_versions = resolve.packages.iter().any(|(_, p)| {
p.name.namespace == package.name.namespace
&& p.name.name == package.name.name
&& p.name.version != package.name.version
});
let version = if package_has_multiple_versions || self.opts.include_versions {
if let Some(version) = &package.name.version {
format!("{}_", version.to_string().replace(['.', '-', '+'], "_"))
} else {
String::new()
}
} else {
String::new()
};
let namespace = package.name.namespace.to_snake_case();
let package = package.name.name.to_snake_case();
let interface = interface.name.as_ref().unwrap().to_snake_case();
format!("{namespace}_{package}_{version}{interface}")
}
None => "wit_world".into(),
}
}

fn func_name(
&self,
resolve: &Resolve,
interface: Option<&WorldKey>,
func: &Function,
) -> String {
let prefix = self.interface_name(resolve, interface);
let name = func.name.to_snake_case().replace('.', "_");

format!("{prefix}_{name}")
}
}

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

let name = func.item_name().to_upper_camel_case();
let package = format!("export_{}", interface_name(resolve, self.interface));
let package = format!(
"export_{}",
self.generator.interface_name(resolve, self.interface)
);

let call = match &func.kind {
FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {
Expand Down Expand Up @@ -2945,42 +3000,6 @@ const (
}
}

fn interface_name(resolve: &Resolve, interface: Option<&WorldKey>) -> String {
match interface {
Some(WorldKey::Name(name)) => name.to_snake_case(),
Some(WorldKey::Interface(id)) => {
let interface = &resolve.interfaces[*id];
let package = &resolve.packages[interface.package.unwrap()];
let package_has_multiple_versions = resolve.packages.iter().any(|(_, p)| {
p.name.namespace == package.name.namespace
&& p.name.name == package.name.name
&& p.name.version != package.name.version
});
let version = if package_has_multiple_versions {
if let Some(version) = &package.name.version {
format!("{}_", version.to_string().replace(['.', '-', '+'], "_"))
} else {
String::new()
}
} else {
String::new()
};
let namespace = package.name.namespace.to_snake_case();
let package = package.name.name.to_snake_case();
let interface = interface.name.as_ref().unwrap().to_snake_case();
format!("{namespace}_{package}_{version}{interface}")
}
None => "wit_world".into(),
}
}

fn func_name(resolve: &Resolve, interface: Option<&WorldKey>, func: &Function) -> String {
let prefix = interface_name(resolve, interface);
let name = func.name.to_snake_case().replace('.', "_");

format!("{prefix}_{name}")
}

fn wasm_type(ty: WasmType) -> &'static str {
match ty {
WasmType::I32 => "int32",
Expand Down
Loading