From 6a67bfff32ca312aca185cd1f144c80ce9f1c164 Mon Sep 17 00:00:00 2001 From: Kristupas Antanavicius Date: Thu, 16 Jan 2025 13:22:07 +0200 Subject: [PATCH] Fix enums/errors case names conflicting with parameters to top level type names (#95) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kristupas Antanavičius --- Cargo.lock | 10 +++++ README.md | 6 --- bindgen/templates/EnumTemplate.cs | 4 +- bindgen/templates/ErrorTemplate.cs | 4 +- bindgen/templates/macros.cs | 20 ++++++++- .../UniffiCS.BindingTests/TestIssue60.cs | 17 +++++++ fixtures/Cargo.toml | 1 + fixtures/regressions/issue-60/Cargo.toml | 17 +++++++ fixtures/regressions/issue-60/README.md | 13 ++++++ fixtures/regressions/issue-60/src/lib.rs | 45 +++++++++++++++++++ fixtures/src/lib.rs | 1 + 11 files changed, 127 insertions(+), 11 deletions(-) create mode 100644 dotnet-tests/UniffiCS.BindingTests/TestIssue60.cs create mode 100644 fixtures/regressions/issue-60/Cargo.toml create mode 100644 fixtures/regressions/issue-60/README.md create mode 100644 fixtures/regressions/issue-60/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 54d6a76..839def1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -536,6 +536,15 @@ dependencies = [ "uniffi_macros", ] +[[package]] +name = "issue-60" +version = "1.0.0" +dependencies = [ + "thiserror", + "uniffi", + "uniffi_macros", +] + [[package]] name = "issue-75" version = "1.0.0" @@ -1227,6 +1236,7 @@ version = "0.1.0" dependencies = [ "global-methods-class-name", "issue-28", + "issue-60", "issue-75", "issue-76", "null-to-empty-string", diff --git a/README.md b/README.md index 63c95d7..19ed0b4 100644 --- a/README.md +++ b/README.md @@ -52,12 +52,6 @@ The following uniffi features are unsupported. - Async functions [#41](https://github.com/NordSecurity/uniffi-bindgen-cs/issues/41) -# Known Limitations - -The following valid Rust type definitions fail to be converted properly, but a simple work-around is given: - -- Enum variants having the same name as their member type [#60](https://github.com/NordSecurity/uniffi-bindgen-cs/issues/60) - # Configuration options It's possible to [configure some settings](docs/CONFIGURATION.md) by passing `--config` diff --git a/bindgen/templates/EnumTemplate.cs b/bindgen/templates/EnumTemplate.cs index 435d4b9..6e94ca2 100644 --- a/bindgen/templates/EnumTemplate.cs +++ b/bindgen/templates/EnumTemplate.cs @@ -48,8 +48,8 @@ public override void Write({{ type_name }} value, BigEndianStream stream) { public record {{ variant.name()|class_name }}: {{ type_name }} {} {% else -%} public record {{ variant.name()|class_name }} ( - {% for field in variant.fields() -%} - {{ field|type_name}} {{ field.name()|var_name }}{% if !loop.last %},{% endif %} + {%- for field in variant.fields() %} + {% call cs::enum_parameter_type_name(field|type_name, variant.name()|class_name) %} {{ field.name()|var_name }}{% if !loop.last %},{% endif %} {%- endfor %} ) : {{ type_name }} {} {%- endif %} diff --git a/bindgen/templates/ErrorTemplate.cs b/bindgen/templates/ErrorTemplate.cs index 8e75e6c..e6f8c59 100644 --- a/bindgen/templates/ErrorTemplate.cs +++ b/bindgen/templates/ErrorTemplate.cs @@ -64,13 +64,13 @@ public class {{ variant.name()|exception_name }} : {{ type_name }} {} public class {{ variant.name()|exception_name }} : {{ type_name }} { // Members {%- for field in variant.fields() %} - public {{ field|type_name}} {{ field.name()|var_name }}; + public {% call cs::enum_parameter_type_name(field|type_name, variant.name()|exception_name) %} {{ field.name()|var_name }}; {%- endfor %} // Constructor public {{ variant.name()|exception_name }}( {%- for field in variant.fields() %} - {{ field|type_name}} {{ field.name()|var_name }}{% if loop.last %}{% else %}, {% endif %} + {% call cs::enum_parameter_type_name(field|type_name, variant.name()|exception_name) %} {{ field.name()|var_name }}{% if loop.last %}{% else %}, {% endif %} {%- endfor %}) { {%- for field in variant.fields() %} this.{{ field.name()|var_name }} = {{ field.name()|var_name }}; diff --git a/bindgen/templates/macros.cs b/bindgen/templates/macros.cs index 8081427..a21030f 100644 --- a/bindgen/templates/macros.cs +++ b/bindgen/templates/macros.cs @@ -121,4 +121,22 @@ void {%- endmatch -%} {%- endif -%} -{%- endmacro -%} \ No newline at end of file +{%- endmacro -%} + +{# +// Break the following cycle, where `Rectangle` case name shadow top level `Rectangle` type name. +// If param type name matches the enum name, prefix the param type name with top level namespace. +// https://github.com/NordSecurity/uniffi-bindgen-cs/issues/60 +// public record Rectangle(double @width, double @height) { } +// public record Shape +// { ____________ +// ∨ ∧ +// public record Rectangle(Rectangle @s) : Shape { } +// public record Ellipse(Ellipse @s) : Shape { } +// } +#} +{%- macro enum_parameter_type_name(param_type_name, enum_name) %} +{%- if param_type_name == enum_name %}{{ config.namespace() }}.{{ param_type_name }} +{%- else %}{{ param_type_name }} +{%- endif %} +{%- endmacro %} diff --git a/dotnet-tests/UniffiCS.BindingTests/TestIssue60.cs b/dotnet-tests/UniffiCS.BindingTests/TestIssue60.cs new file mode 100644 index 0000000..d566274 --- /dev/null +++ b/dotnet-tests/UniffiCS.BindingTests/TestIssue60.cs @@ -0,0 +1,17 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +using uniffi.issue_60; + +namespace UniffiCS.BindingTests; + +public class ClassIssue60 +{ + [Fact] + public void TestIssue60() + { + new Shape.Rectangle(new Rectangle(1f, 2f)); + new ShapeException.Rectangle(new Rectangle(1f, 2f)); + } +} diff --git a/fixtures/Cargo.toml b/fixtures/Cargo.toml index 5ad4a2b..ed01f8c 100644 --- a/fixtures/Cargo.toml +++ b/fixtures/Cargo.toml @@ -11,6 +11,7 @@ crate-type = ["cdylib", "lib"] [dependencies] global-methods-class-name = { path = "global-methods-class-name" } issue-28 = { path = "regressions/issue-28" } +issue-60 = { path = "regressions/issue-60" } issue-75 = { path = "regressions/issue-75" } issue-76 = { path = "regressions/issue-76" } null-to-empty-string = { path = "null-to-empty-string" } diff --git a/fixtures/regressions/issue-60/Cargo.toml b/fixtures/regressions/issue-60/Cargo.toml new file mode 100644 index 0000000..325fcae --- /dev/null +++ b/fixtures/regressions/issue-60/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "issue-60" +version = "1.0.0" +edition = "2021" +publish = false + +[lib] +crate-type = ["lib", "cdylib"] +name = "issue_60" + +[dependencies] +thiserror = "1.0" +uniffi = {path = "../../../3rd-party/uniffi-rs/uniffi", features=["build"]} +uniffi_macros = {path = "../../../3rd-party/uniffi-rs/uniffi_macros"} + +[build-dependencies] +uniffi = {path = "../../../3rd-party/uniffi-rs/uniffi", features=["bindgen-tests"]} diff --git a/fixtures/regressions/issue-60/README.md b/fixtures/regressions/issue-60/README.md new file mode 100644 index 0000000..326b2d1 --- /dev/null +++ b/fixtures/regressions/issue-60/README.md @@ -0,0 +1,13 @@ +# https://github.com/NordSecurity/uniffi-bindgen-cs/issues/60 + +Associated enum class names conflict with top level type definitions. + +```C# +public record Rectangle(double @width, double @height) { } +public record Shape +{ ____________ + ∨ ∧ + public record Rectangle(Rectangle @s) : Shape { } + public record Ellipse(Ellipse @s) : Shape { } +} +``` diff --git a/fixtures/regressions/issue-60/src/lib.rs b/fixtures/regressions/issue-60/src/lib.rs new file mode 100644 index 0000000..73f5730 --- /dev/null +++ b/fixtures/regressions/issue-60/src/lib.rs @@ -0,0 +1,45 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use std::fmt; + +#[derive(uniffi::Enum)] +pub enum Shape { + Rectangle { s: Rectangle }, + Ellipse { s: Ellipse }, +} + +#[derive(Debug, thiserror::Error, uniffi::Error)] +pub enum ShapeError { + #[error("Rectangle: {s}")] + Rectangle { s: Rectangle }, + #[error("Ellipse: {s}")] + Ellipse { s: Ellipse }, +} + +#[derive(uniffi::Record, Debug)] +pub struct Rectangle { + width: f64, + height: f64, +} + +#[derive(uniffi::Record, Debug)] +pub struct Ellipse { + x_radius: f64, + y_radius: f64, +} + +impl fmt::Display for Rectangle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "width: {}, height: {}", self.width, self.height) + } +} + +impl fmt::Display for Ellipse { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "x_radius: {}, y_radius: {}", self.x_radius, self.y_radius) + } +} + +uniffi::setup_scaffolding!(); diff --git a/fixtures/src/lib.rs b/fixtures/src/lib.rs index d34d6e0..c9a693d 100644 --- a/fixtures/src/lib.rs +++ b/fixtures/src/lib.rs @@ -25,6 +25,7 @@ mod uniffi_fixtures { uniffi_cs_optional_parameters::uniffi_reexport_scaffolding!(); stringify::uniffi_reexport_scaffolding!(); issue_28::uniffi_reexport_scaffolding!(); + issue_60::uniffi_reexport_scaffolding!(); issue_75::uniffi_reexport_scaffolding!(); issue_76::uniffi_reexport_scaffolding!(); }