From d125d2101c75993ff0953475920a945457b0f88f Mon Sep 17 00:00:00 2001 From: Kristupas Antanavicius Date: Thu, 28 Sep 2023 12:08:09 +0300 Subject: [PATCH] Lowercase the numeric types Lowercasing numeric types introduces a problem. In C# custom types are implemented with `using` directive, and the `using` directive expects and identifier on the right side of `=`. Lowercase numeric types are not identifiers, but rather reserved keywords. So its not possible to define a type alias using a lowercase numeric type as the underlying type. To use numeric types as the underlying type, the uppercase system type counterparts must be used To generate correct code for custom types, create new filter `type_name_custom`, that formats these types in their respective system type counterparts. Signed-off-by: Kristupas Antanavicius --- Cargo.lock | 12 +++ bindgen/src/gen_cs/mod.rs | 24 ++++++ bindgen/src/gen_cs/primitives.rs | 22 +++--- bindgen/templates/CustomTypeTemplate.cs | 2 +- bindgen/templates/Float32Helper.cs | 4 +- bindgen/templates/Float64Helper.cs | 4 +- bindgen/templates/Int16Helper.cs | 4 +- bindgen/templates/Int32Helper.cs | 4 +- bindgen/templates/Int64Helper.cs | 4 +- bindgen/templates/Int8Helper.cs | 4 +- bindgen/templates/UInt16Helper.cs | 4 +- bindgen/templates/UInt32Helper.cs | 4 +- bindgen/templates/UInt64Helper.cs | 4 +- bindgen/templates/UInt8Helper.cs | 4 +- .../TestCustomTypesBuiltin.cs | 32 ++++++++ fixtures/Cargo.toml | 1 + fixtures/custom-types-builtin/Cargo.toml | 19 +++++ fixtures/custom-types-builtin/build.rs | 7 ++ .../src/custom-types-builtin.udl | 71 +++++++++++++++++ fixtures/custom-types-builtin/src/lib.rs | 78 +++++++++++++++++++ fixtures/src/lib.rs | 1 + test_bindings.sh | 1 + 22 files changed, 278 insertions(+), 32 deletions(-) create mode 100644 dotnet-tests/UniffiCS.binding_tests/TestCustomTypesBuiltin.cs create mode 100644 fixtures/custom-types-builtin/Cargo.toml create mode 100644 fixtures/custom-types-builtin/build.rs create mode 100644 fixtures/custom-types-builtin/src/custom-types-builtin.udl create mode 100644 fixtures/custom-types-builtin/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 35b6d9f..d18ee7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -764,6 +764,7 @@ name = "uniffi-bindgen-cs-fixtures" version = "0.1.0" dependencies = [ "global-methods-class-name", + "uniffi-cs-custom-types-builtin", "uniffi-cs-disposable-fixture", "uniffi-example-arithmetic", "uniffi-example-callbacks", @@ -779,6 +780,17 @@ dependencies = [ "uniffi-fixture-time", ] +[[package]] +name = "uniffi-cs-custom-types-builtin" +version = "1.0.0" +dependencies = [ + "once_cell", + "paste", + "thiserror", + "uniffi", + "uniffi_macros", +] + [[package]] name = "uniffi-cs-disposable-fixture" version = "1.0.0" diff --git a/bindgen/src/gen_cs/mod.rs b/bindgen/src/gen_cs/mod.rs index 785979c..6827f36 100644 --- a/bindgen/src/gen_cs/mod.rs +++ b/bindgen/src/gen_cs/mod.rs @@ -340,6 +340,30 @@ pub mod filters { Ok(codetype.type_label(oracle())) } + pub fn type_name_custom(typ: &Type) -> Result { + // Lowercasing numeric types introduces a problem. In C# custom types are + // implemented with `using` directive, and the `using` directive expects + // and identifier on the right side of `=`. Lowercase numeric types are + // not identifiers, but rather reserved keywords. So its not possible to + // define a type alias using a lowercase numeric type as the underlying + // type. To use numeric types as the underlying type, the uppercase + // numeric system type counterparts must be used. + match typ { + Type::Boolean => Ok("Boolean".to_string()), + Type::Int8 => Ok("SByte".to_string()), + Type::Int16 => Ok("Int16".to_string()), + Type::Int32 => Ok("Int32".to_string()), + Type::Int64 => Ok("Int64".to_string()), + Type::UInt8 => Ok("Byte".to_string()), + Type::UInt16 => Ok("UInt16".to_string()), + Type::UInt32 => Ok("UInt32".to_string()), + Type::UInt64 => Ok("UInt64".to_string()), + Type::Float32 => Ok("Single".to_string()), + Type::Float64 => Ok("Double".to_string()), + _ => type_name(typ), + } + } + pub fn canonical_name(codetype: &impl CodeType) -> Result { Ok(codetype.canonical_name(oracle())) } diff --git a/bindgen/src/gen_cs/primitives.rs b/bindgen/src/gen_cs/primitives.rs index 05c70ac..e1296dc 100644 --- a/bindgen/src/gen_cs/primitives.rs +++ b/bindgen/src/gen_cs/primitives.rs @@ -73,15 +73,15 @@ macro_rules! impl_code_type_for_primitive { }; } -impl_code_type_for_primitive!(BooleanCodeType, "Boolean", "Boolean"); +impl_code_type_for_primitive!(BooleanCodeType, "bool", "Boolean"); impl_code_type_for_primitive!(StringCodeType, "String", "String"); -impl_code_type_for_primitive!(Int8CodeType, "SByte", "SByte"); -impl_code_type_for_primitive!(Int16CodeType, "Int16", "Short"); -impl_code_type_for_primitive!(Int32CodeType, "Int32", "Int"); -impl_code_type_for_primitive!(Int64CodeType, "Int64", "Long"); -impl_code_type_for_primitive!(UInt8CodeType, "Byte", "Byte"); -impl_code_type_for_primitive!(UInt16CodeType, "UInt16", "UShort"); -impl_code_type_for_primitive!(UInt32CodeType, "UInt32", "UInt"); -impl_code_type_for_primitive!(UInt64CodeType, "UInt64", "ULong"); -impl_code_type_for_primitive!(Float32CodeType, "Single", "Float"); -impl_code_type_for_primitive!(Float64CodeType, "Double", "Double"); +impl_code_type_for_primitive!(Int8CodeType, "sbyte", "Int8"); +impl_code_type_for_primitive!(Int16CodeType, "short", "Int16"); +impl_code_type_for_primitive!(Int32CodeType, "int", "Int32"); +impl_code_type_for_primitive!(Int64CodeType, "long", "Int64"); +impl_code_type_for_primitive!(UInt8CodeType, "byte", "UInt8"); +impl_code_type_for_primitive!(UInt16CodeType, "ushort", "UInt16"); +impl_code_type_for_primitive!(UInt32CodeType, "uint", "UInt32"); +impl_code_type_for_primitive!(UInt64CodeType, "ulong", "UInt64"); +impl_code_type_for_primitive!(Float32CodeType, "float", "Float"); +impl_code_type_for_primitive!(Float64CodeType, "double", "Double"); diff --git a/bindgen/templates/CustomTypeTemplate.cs b/bindgen/templates/CustomTypeTemplate.cs index a06c165..190cb52 100644 --- a/bindgen/templates/CustomTypeTemplate.cs +++ b/bindgen/templates/CustomTypeTemplate.cs @@ -10,7 +10,7 @@ * is needed because the UDL type name is used in function/method signatures. * It's also what we have an external type that references a custom type. */ -{{- self.add_type_alias(name, builtin|type_name) }} +{{- self.add_type_alias(name, builtin|type_name_custom) }} {{- self.add_type_alias(ffi_converter_name, builtin|ffi_converter_name) }} {%- when Some with (config) %} diff --git a/bindgen/templates/Float32Helper.cs b/bindgen/templates/Float32Helper.cs index 07e99b4..c85e32d 100644 --- a/bindgen/templates/Float32Helper.cs +++ b/bindgen/templates/Float32Helper.cs @@ -2,8 +2,8 @@ * 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/. */#} -class FfiConverterFloat: FfiConverter { - public static FfiConverterFloat INSTANCE = new FfiConverterFloat(); +class {{ ffi_converter_name }}: FfiConverter { + public static {{ ffi_converter_name }} INSTANCE = new {{ ffi_converter_name }}(); public override float Lift(float value) { return value; diff --git a/bindgen/templates/Float64Helper.cs b/bindgen/templates/Float64Helper.cs index fdd48a6..9f7cb9d 100644 --- a/bindgen/templates/Float64Helper.cs +++ b/bindgen/templates/Float64Helper.cs @@ -2,8 +2,8 @@ * 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/. */#} -class FfiConverterDouble: FfiConverter { - public static FfiConverterDouble INSTANCE = new FfiConverterDouble(); +class {{ ffi_converter_name }}: FfiConverter { + public static {{ ffi_converter_name }} INSTANCE = new {{ ffi_converter_name }}(); public override double Lift(double value) { return value; diff --git a/bindgen/templates/Int16Helper.cs b/bindgen/templates/Int16Helper.cs index a8a3c2e..d718ef1 100644 --- a/bindgen/templates/Int16Helper.cs +++ b/bindgen/templates/Int16Helper.cs @@ -2,8 +2,8 @@ * 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/. */#} -class FfiConverterShort: FfiConverter { - public static FfiConverterShort INSTANCE = new FfiConverterShort(); +class {{ ffi_converter_name }}: FfiConverter { + public static {{ ffi_converter_name }} INSTANCE = new {{ ffi_converter_name }}(); public override short Lift(short value) { return value; diff --git a/bindgen/templates/Int32Helper.cs b/bindgen/templates/Int32Helper.cs index 72e8f42..3e68523 100644 --- a/bindgen/templates/Int32Helper.cs +++ b/bindgen/templates/Int32Helper.cs @@ -2,8 +2,8 @@ * 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/. */#} -class FfiConverterInt: FfiConverter { - public static FfiConverterInt INSTANCE = new FfiConverterInt(); +class {{ ffi_converter_name }}: FfiConverter { + public static {{ ffi_converter_name }} INSTANCE = new {{ ffi_converter_name }}(); public override int Lift(int value) { return value; diff --git a/bindgen/templates/Int64Helper.cs b/bindgen/templates/Int64Helper.cs index 3f21c55..5faf217 100644 --- a/bindgen/templates/Int64Helper.cs +++ b/bindgen/templates/Int64Helper.cs @@ -2,8 +2,8 @@ * 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/. */#} -class FfiConverterLong: FfiConverter { - public static FfiConverterLong INSTANCE = new FfiConverterLong(); +class {{ ffi_converter_name }}: FfiConverter { + public static {{ ffi_converter_name }} INSTANCE = new {{ ffi_converter_name }}(); public override long Lift(long value) { return value; diff --git a/bindgen/templates/Int8Helper.cs b/bindgen/templates/Int8Helper.cs index 2d0223f..14e4cd1 100644 --- a/bindgen/templates/Int8Helper.cs +++ b/bindgen/templates/Int8Helper.cs @@ -2,8 +2,8 @@ * 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/. */#} -class FfiConverterSByte: FfiConverter { - public static FfiConverterSByte INSTANCE = new FfiConverterSByte(); +class {{ ffi_converter_name }}: FfiConverter { + public static {{ ffi_converter_name }} INSTANCE = new {{ ffi_converter_name }}(); public override sbyte Lift(sbyte value) { return value; diff --git a/bindgen/templates/UInt16Helper.cs b/bindgen/templates/UInt16Helper.cs index 20c0057..9a78ece 100644 --- a/bindgen/templates/UInt16Helper.cs +++ b/bindgen/templates/UInt16Helper.cs @@ -2,8 +2,8 @@ * 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/. */#} -class FfiConverterUShort: FfiConverter { - public static FfiConverterUShort INSTANCE = new FfiConverterUShort(); +class {{ ffi_converter_name }}: FfiConverter { + public static {{ ffi_converter_name }} INSTANCE = new {{ ffi_converter_name }}(); public override ushort Lift(ushort value) { return value; diff --git a/bindgen/templates/UInt32Helper.cs b/bindgen/templates/UInt32Helper.cs index e92f7b1..f31da57 100644 --- a/bindgen/templates/UInt32Helper.cs +++ b/bindgen/templates/UInt32Helper.cs @@ -2,8 +2,8 @@ * 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/. */#} -class FfiConverterUInt: FfiConverter { - public static FfiConverterUInt INSTANCE = new FfiConverterUInt(); +class {{ ffi_converter_name }}: FfiConverter { + public static {{ ffi_converter_name }} INSTANCE = new {{ ffi_converter_name }}(); public override uint Lift(uint value) { return value; diff --git a/bindgen/templates/UInt64Helper.cs b/bindgen/templates/UInt64Helper.cs index deaf178..54c6a95 100644 --- a/bindgen/templates/UInt64Helper.cs +++ b/bindgen/templates/UInt64Helper.cs @@ -2,8 +2,8 @@ * 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/. */#} -class FfiConverterULong: FfiConverter { - public static FfiConverterULong INSTANCE = new FfiConverterULong(); +class {{ ffi_converter_name }}: FfiConverter { + public static {{ ffi_converter_name }} INSTANCE = new {{ ffi_converter_name }}(); public override ulong Lift(ulong value) { return value; diff --git a/bindgen/templates/UInt8Helper.cs b/bindgen/templates/UInt8Helper.cs index 7b483fd..728bd17 100644 --- a/bindgen/templates/UInt8Helper.cs +++ b/bindgen/templates/UInt8Helper.cs @@ -2,8 +2,8 @@ * 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/. */#} -class FfiConverterByte: FfiConverter { - public static FfiConverterByte INSTANCE = new FfiConverterByte(); +class {{ ffi_converter_name }}: FfiConverter { + public static {{ ffi_converter_name }} INSTANCE = new {{ ffi_converter_name }}(); public override byte Lift(byte value) { return value; diff --git a/dotnet-tests/UniffiCS.binding_tests/TestCustomTypesBuiltin.cs b/dotnet-tests/UniffiCS.binding_tests/TestCustomTypesBuiltin.cs new file mode 100644 index 0000000..a500959 --- /dev/null +++ b/dotnet-tests/UniffiCS.binding_tests/TestCustomTypesBuiltin.cs @@ -0,0 +1,32 @@ +/* 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 System; +using uniffi.custom_types_builtin; + +public class TestCustomTypesBuiltin { + [Fact] + public void CustomTypesWork() { + var demo = CustomTypesBuiltinMethods.GetCustomTypesBuiltin(); + AssertDemo(demo); + + demo = CustomTypesBuiltinMethods.ReturnCustomTypesBuiltin(demo); + AssertDemo(demo); + } + + void AssertDemo(CustomTypesBuiltin demo) { + Assert.Equal("Hello, world!", demo.@string); + Assert.True(demo.boolean); + Assert.Equal(SByte.MaxValue, demo.int8); + Assert.Equal(Int16.MaxValue, demo.int16); + Assert.Equal(Int32.MaxValue, demo.int32); + Assert.Equal(Int64.MaxValue, demo.int64); + Assert.Equal(Byte.MaxValue, demo.uint8); + Assert.Equal(UInt16.MaxValue, demo.uint16); + Assert.Equal(UInt32.MaxValue, demo.uint32); + Assert.Equal(UInt64.MaxValue, demo.uint64); + Assert.Equal(Single.MaxValue, demo.@float); + Assert.Equal(Double.MaxValue, demo.@double); + } +} diff --git a/fixtures/Cargo.toml b/fixtures/Cargo.toml index 74888b1..8f510f8 100644 --- a/fixtures/Cargo.toml +++ b/fixtures/Cargo.toml @@ -10,6 +10,7 @@ crate-type = ["cdylib", "lib"] [dependencies] global-methods-class-name = { path = "global-methods-class-name" } +uniffi-cs-custom-types-builtin = { path = "custom-types-builtin" } uniffi-cs-disposable-fixture = { path = "disposable" } uniffi-example-arithmetic = { path = "../3rd-party/uniffi-rs/examples/arithmetic" } uniffi-example-callbacks = { path = "../3rd-party/uniffi-rs/examples/callbacks" } diff --git a/fixtures/custom-types-builtin/Cargo.toml b/fixtures/custom-types-builtin/Cargo.toml new file mode 100644 index 0000000..eeb5cdd --- /dev/null +++ b/fixtures/custom-types-builtin/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "uniffi-cs-custom-types-builtin" +version = "1.0.0" +edition = "2021" +publish = false + +[lib] +crate-type = ["lib", "cdylib"] +name = "uniffi_cs_custom_types_builtin" + +[dependencies] +once_cell = "1.12" +paste = "1.0" +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/custom-types-builtin/build.rs b/fixtures/custom-types-builtin/build.rs new file mode 100644 index 0000000..daa763e --- /dev/null +++ b/fixtures/custom-types-builtin/build.rs @@ -0,0 +1,7 @@ +/* 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/. */ + +fn main() { + uniffi::generate_scaffolding("./src/custom-types-builtin.udl").unwrap(); +} diff --git a/fixtures/custom-types-builtin/src/custom-types-builtin.udl b/fixtures/custom-types-builtin/src/custom-types-builtin.udl new file mode 100644 index 0000000..f3e17d2 --- /dev/null +++ b/fixtures/custom-types-builtin/src/custom-types-builtin.udl @@ -0,0 +1,71 @@ +/* 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/. */ + +// Ensure that builtin types can be used as the underlying type in custom types. + +[Custom] +typedef string MyString; + +// using sequence or record as the underlying type produces broken code + +// [Custom] +// typedef sequence Array; + +// [Custom] +// typedef record Table; + +[Custom] +typedef boolean Boolean; + +[Custom] +typedef i8 Int8; + +[Custom] +typedef i16 Int16; + +[Custom] +typedef i32 Int32; + +[Custom] +typedef i64 Int64; + +[Custom] +typedef u8 UInt8; + +[Custom] +typedef u16 UInt16; + +[Custom] +typedef u32 UInt32; + +[Custom] +typedef u64 UInt64; + +[Custom] +typedef float Float; + +[Custom] +typedef double Double; + +dictionary CustomTypesBuiltin { + MyString string; + // Array array; + // Table table; + Boolean boolean; + Int8 int8; + Int16 int16; + Int32 int32; + Int64 int64; + UInt8 uint8; + UInt16 uint16; + UInt32 uint32; + UInt64 uint64; + Float float; + Double double; +}; + +namespace custom_types_builtin { + CustomTypesBuiltin get_custom_types_builtin(); + CustomTypesBuiltin return_custom_types_builtin(CustomTypesBuiltin custom_types); +}; diff --git a/fixtures/custom-types-builtin/src/lib.rs b/fixtures/custom-types-builtin/src/lib.rs new file mode 100644 index 0000000..0cceb86 --- /dev/null +++ b/fixtures/custom-types-builtin/src/lib.rs @@ -0,0 +1,78 @@ +use paste::paste; + +macro_rules! define_custom_builtin_type { + ($custom:ty, $underlying:ty) => { + paste! { + pub struct $custom(pub $underlying); + + impl UniffiCustomTypeConverter for $custom { + type Builtin = $underlying; + + fn into_custom(val: Self::Builtin) -> uniffi::Result { + Ok($custom(val)) + } + + fn from_custom(obj: Self) -> Self::Builtin { + obj.0 + } + } + } + }; +} + +define_custom_builtin_type!(MyString, String); +// define_custom_builtin_type!(Array, Vec); +// define_custom_builtin_type!(Table, HashMap); +define_custom_builtin_type!(Boolean, bool); +define_custom_builtin_type!(Int8, i8); +define_custom_builtin_type!(Int16, i16); +define_custom_builtin_type!(Int32, i32); +define_custom_builtin_type!(Int64, i64); +define_custom_builtin_type!(UInt8, u8); +define_custom_builtin_type!(UInt16, u16); +define_custom_builtin_type!(UInt32, u32); +define_custom_builtin_type!(UInt64, u64); +define_custom_builtin_type!(Float, f32); +define_custom_builtin_type!(Double, f64); + +pub struct CustomTypesBuiltin { + string: MyString, + // array: Array, + // table: Table, + boolean: Boolean, + int8: Int8, + int16: Int16, + int32: Int32, + int64: Int64, + uint8: UInt8, + uint16: UInt16, + uint32: UInt32, + uint64: UInt64, + float: Float, + double: Double, +} + +pub fn get_custom_types_builtin() -> CustomTypesBuiltin { + return CustomTypesBuiltin { + string: MyString("Hello, world!".to_string()), + // array: Array(vec!["Hello, world!".to_string()]), + // table: Table(HashMap::from([("hello".to_string(), "world".to_string())])), + boolean: Boolean(true), + int8: Int8(i8::MAX), + int16: Int16(i16::MAX), + int32: Int32(i32::MAX), + int64: Int64(i64::MAX), + uint8: UInt8(u8::MAX), + uint16: UInt16(u16::MAX), + uint32: UInt32(u32::MAX), + uint64: UInt64(u64::MAX), + float: Float(f32::MAX), + double: Double(f64::MAX), + }; +} + +pub fn return_custom_types_builtin(custom_types: CustomTypesBuiltin) -> CustomTypesBuiltin { + custom_types +} + +include!(concat!(env!("OUT_DIR"), "/custom-types-builtin.uniffi.rs")); diff --git a/fixtures/src/lib.rs b/fixtures/src/lib.rs index 5467b07..371cf2c 100644 --- a/fixtures/src/lib.rs +++ b/fixtures/src/lib.rs @@ -18,5 +18,6 @@ mod uniffi_fixtures { uniffi_fixture_docstring::uniffi_reexport_scaffolding!(); global_methods_class_name::uniffi_reexport_scaffolding!(); + uniffi_cs_custom_types_builtin::uniffi_reexport_scaffolding!(); uniffi_cs_disposable::uniffi_reexport_scaffolding!(); } diff --git a/test_bindings.sh b/test_bindings.sh index dbc2bc6..c0559ae 100755 --- a/test_bindings.sh +++ b/test_bindings.sh @@ -25,6 +25,7 @@ bindings 3rd-party/uniffi-rs/fixtures/coverall/src/coverall.udl bindings 3rd-party/uniffi-rs/fixtures/docstring/src/docstring.udl bindings 3rd-party/uniffi-rs/fixtures/external-types/lib/src/external-types-lib.udl bindings 3rd-party/uniffi-rs/fixtures/uniffi-fixture-time/src/chronological.udl +bindings fixtures/custom-types-builtin/src/custom-types-builtin.udl bindings fixtures/disposable/src/disposable.udl CONFIG="fixtures/global-methods-class-name/uniffi.toml" \