From 581bec9598943cc9274dfe7db1a73a4c878c3cdd Mon Sep 17 00:00:00 2001 From: Yeongjong Lee Date: Tue, 28 Jan 2020 14:46:10 +0900 Subject: [PATCH] eolian_mono: make struct immutable Summary: Immutable value type is recommeneded for struct type in cs world. `DO NOT define mutable value types.` (see, https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/struct) Also, this patch include refactoring of generated struct types. 1. Change field type to property type that have only getter. it will fix CA1051(ref T8397). 2. Remove internal NativeStruct. there is private field for marshalling struct instead. 3. Fix some test cases that change value inside struct. because struct is immutable. Test Plan: meson build -Dbindings=mono,cxx -Dmono-beta=true Reviewers: woohyun, felipealmeida, Jaehyun_Cho Subscribers: cedric, #reviewers, #committers Tags: #efl Maniphest Tasks: T8397 Differential Revision: https://phab.enlightenment.org/D11146 --- .../eolian/mono/marshall_type_impl.hh | 4 +- .../eolian_mono/eolian/mono/name_helpers.hh | 20 +- .../eolian/mono/struct_definition.hh | 212 ++++++------------ .../eolian_mono/eolian/mono/struct_fields.hh | 120 +++++++++- src/bin/eolian_mono/eolian/mono/utils.hh | 22 ++ src/bindings/mono/eo_mono/EoWrapper.cs | 8 +- src/bindings/mono/eo_mono/workaround.cs | 61 ++--- src/tests/efl_mono/Events.cs | 3 +- src/tests/efl_mono/StructHelpers.cs | 127 +++++------ src/tests/efl_mono/Structs.cs | 15 +- 10 files changed, 316 insertions(+), 276 deletions(-) diff --git a/src/bin/eolian_mono/eolian/mono/marshall_type_impl.hh b/src/bin/eolian_mono/eolian/mono/marshall_type_impl.hh index 4d1e188997..60b495ea39 100644 --- a/src/bin/eolian_mono/eolian/mono/marshall_type_impl.hh +++ b/src/bin/eolian_mono/eolian/mono/marshall_type_impl.hh @@ -129,7 +129,7 @@ struct marshall_type_visitor_generate , {"event", nullptr, [&] { regular_type_def r = regular; - r.base_type = "Efl.Event.NativeStruct"; + r.base_type = "Efl.Event"; r.namespaces.clear(); return r; }} @@ -190,7 +190,7 @@ struct marshall_type_visitor_generate { if ((is_out || is_return) && is_ptr) return as_generator("System.IntPtr").generate(sink, attributes::unused, *context); - return as_generator(string << ".NativeStruct") + return as_generator(string) .generate(sink, name_helpers::type_full_managed_name(regular), *context); } else if (eina::optional b = type_match::get_match diff --git a/src/bin/eolian_mono/eolian/mono/name_helpers.hh b/src/bin/eolian_mono/eolian/mono/name_helpers.hh index ae958ba623..a6e94ea2f6 100644 --- a/src/bin/eolian_mono/eolian/mono/name_helpers.hh +++ b/src/bin/eolian_mono/eolian/mono/name_helpers.hh @@ -331,7 +331,8 @@ inline std::string enum_field_managed_name(std::string name) inline std::string to_field_name(std::string const& in) { - return utils::capitalize(in); + std::vector names = utils::split(in, '_'); + return utils::to_camel_case(names); } @@ -583,6 +584,16 @@ struct struct_field_name_generator } } const struct_field_name {}; +// Property names // +struct struct_property_name_generator +{ + template + bool generate(OutputIterator sink, attributes::struct_field_def const& field, Context const& context) const + { + return as_generator(string).generate(sink, name_helpers::managed_name(field.name), context); + } +} const struct_property_name {}; + } // namespace name_helpers } // namespace eolian_mono @@ -615,12 +626,19 @@ struct is_eager_generator struct is_generator< ::eolian_mono::name_helpers::struct_field_name_generator> : std::true_type {}; +template <> +struct is_eager_generator : std::true_type {}; +template <> +struct is_generator< ::eolian_mono::name_helpers::struct_property_name_generator> : std::true_type {}; + namespace type_traits { template <> struct attributes_needed : std::integral_constant {}; template <> struct attributes_needed< ::eolian_mono::name_helpers::struct_field_name_generator> : std::integral_constant {}; +template <> +struct attributes_needed< ::eolian_mono::name_helpers::struct_property_name_generator> : std::integral_constant {}; } diff --git a/src/bin/eolian_mono/eolian/mono/struct_definition.hh b/src/bin/eolian_mono/eolian/mono/struct_definition.hh index 48d69dc834..6f19088d52 100644 --- a/src/bin/eolian_mono/eolian/mono/struct_definition.hh +++ b/src/bin/eolian_mono/eolian/mono/struct_definition.hh @@ -181,7 +181,6 @@ struct to_external_field_convert_generator template bool generate(OutputIterator sink, attributes::struct_field_def const& field, Context const& context) const { - auto const& indent = current_indentation(context); auto field_name = name_helpers::to_field_name(field.name); auto regular = efl::eina::get(&field.type.original_type); auto klass = efl::eina::get(&field.type.original_type); @@ -191,113 +190,108 @@ struct to_external_field_convert_generator { auto interface_name = name_helpers::klass_full_interface_name(*klass); if (!as_generator( - "\n" - << indent << scope_tab << scope_tab << "_external_struct." << string - << " = (" << interface_name << ") Efl.Eo.Globals.CreateWrapperFor(_internal_struct." << string << ");\n" + "(" << interface_name << ") Efl.Eo.Globals.CreateWrapperFor(" << string << ");" ).generate(sink, std::make_tuple(field_name, field_name), context)) return false; } else if (field.type.c_type == "Eina_Binbuf *" || field.type.c_type == "const Eina_Binbuf *") { if (!as_generator( - indent << scope_tab << scope_tab << "_external_struct." << string << " = new " << type << "(_internal_struct." << string << ", false);\n") - .generate(sink, std::make_tuple(field_name, field.type, field_name), context)) + "new " << type << "(" << string << ", false);") + .generate(sink, std::make_tuple(field.type, field_name), context)) return false; } else if (complex && (complex->outer.base_type == "array")) { // Always assumes pointer if (!as_generator( - indent << scope_tab << scope_tab << "_external_struct." << string << " = Efl.Eo.Globals.NativeArrayTo" << type << "(_internal_struct." << string << ");\n") - .generate(sink, std::make_tuple(field_name, field.type, field_name), context)) + "Efl.Eo.Globals.NativeArrayTo" << type << "(" << string << ");") + .generate(sink, std::make_tuple(field.type, field_name), context)) return false; } else if (complex && (complex->outer.base_type == "list")) { // Always assumes pointer if (!as_generator( - indent << scope_tab << scope_tab << "_external_struct." << string << " = Efl.Eo.Globals.NativeListTo" << type << "(_internal_struct." << string << ");\n") - .generate(sink, std::make_tuple(field_name, field.type, field_name), context)) + "Efl.Eo.Globals.NativeListTo" << type << "(" << string << ");") + .generate(sink, std::make_tuple(field.type, field_name), context)) return false; } else if (complex && complex->outer.base_type == "hash") { if (!as_generator( - indent << scope_tab << scope_tab << "_external_struct." << string << " = new " << type << "(_internal_struct." << string << ", false, false, false);\n") - .generate(sink, std::make_tuple(field_name, field.type, field_name), context)) + "new " << type << "(" << string << ", false, false, false);") + .generate(sink, std::make_tuple(field.type, field_name), context)) return false; } else if (complex && complex->outer.base_type == "iterator") { if (!as_generator( - indent << scope_tab << scope_tab << "_external_struct." << string << " = Efl.Eo.Globals.IteratorTo" << type << "(_internal_struct." << string << ");\n") - .generate(sink, std::make_tuple(field_name, field.type, field_name), context)) + "Efl.Eo.Globals.IteratorTo" << type << "(" << string << ");") + .generate(sink, std::make_tuple(field.type, field_name), context)) return false; } else if (field.type.is_ptr && helpers::need_pointer_conversion(regular) && !helpers::need_struct_conversion(regular)) { if (!as_generator( - indent << scope_tab << scope_tab << "_external_struct." << string << " = Eina.PrimitiveConversion.PointerToManaged<" << type << ">(_internal_struct." << string << ");\n") - .generate(sink, std::make_tuple(field_name, field.type, field_name), context)) + "Eina.PrimitiveConversion.PointerToManaged<" << type << ">(" << string << ");") + .generate(sink, std::make_tuple(field.type, field_name), context)) return false; } else if (helpers::need_struct_conversion(regular)) { if (!as_generator( - indent << scope_tab << scope_tab << "_external_struct." << string << " = _internal_struct." << string << ";\n") - .generate(sink, std::make_tuple(field_name, field_name), context)) + string << ";") + .generate(sink, field_name, context)) return false; } else if (regular && (regular->base_type == "string" || regular->base_type == "mstring" || regular->base_type == "stringshare")) { if (!as_generator( - indent << scope_tab << scope_tab << "_external_struct." << string << " = Eina.StringConversion.NativeUtf8ToManagedString(_internal_struct." << string << ");\n") + "Eina.StringConversion.NativeUtf8ToManagedString(" << string << ");") .generate(sink, std::make_tuple(field_name, field_name), context)) return false; } else if (field.type.c_type == "Eina_Slice" || field.type.c_type == "const Eina_Slice" || field.type.c_type == "Eina_Rw_Slice" || field.type.c_type == "const Eina_Rw_Slice") { - if (!as_generator( - "\n" << - indent << scope_tab << scope_tab << "_external_struct." << field_name << ".Len = _internal_struct." << field_name << ".Len;\n" << - indent << scope_tab << scope_tab << "_external_struct." << field_name << ".Mem = _internal_struct." << field_name << ".Mem;\n") + if (!as_generator(field_name << ";") .generate(sink, attributes::unused, context)) return false; } else if (field.type.c_type == "Eina_Value" || field.type.c_type == "const Eina_Value") { if (!as_generator( - indent << scope_tab << scope_tab << "_external_struct." << string << " = new Eina.Value(_internal_struct." << string << ");\n" - ).generate(sink, std::make_tuple(field_name, field_name), context)) + "new Eina.Value(" << string << ");" + ).generate(sink, std::make_tuple(field_name), context)) return false; } else if (field.type.c_type == "Eina_Value *" || field.type.c_type == "const Eina_Value *") { if (!as_generator( - indent << scope_tab << scope_tab << "_external_struct." << string << " = new Eina.Value(_internal_struct." << string << ", Eina.Ownership.Unmanaged);\n" - ).generate(sink, std::make_tuple(field_name, field_name), context)) + "new Eina.Value(" << string << ", Eina.Ownership.Unmanaged);" + ).generate(sink, std::make_tuple(field_name), context)) return false; } else if (!field.type.is_ptr && regular && regular->base_type == "bool") { if (!as_generator( - indent << scope_tab << scope_tab << "_external_struct." << string << " = _internal_struct." << string << " != 0;\n" - ).generate(sink, std::make_tuple(field_name, field_name), context)) + string << " != 0;" + ).generate(sink, std::make_tuple(field_name), context)) return false; } else if (!field.type.is_ptr && regular && regular->base_type == "char") { if (!as_generator( - indent << scope_tab << scope_tab << "_external_struct." << string << " = (char)_internal_struct." << string << ";\n" - ).generate(sink, std::make_tuple(field_name, field_name), context)) + "(char)" << string << ";" + ).generate(sink, std::make_tuple(field_name), context)) return false; } else // primitives and enums { if (!as_generator( - indent << scope_tab << scope_tab << "_external_struct." << string << " = _internal_struct." << string << ";\n") - .generate(sink, std::make_tuple(field_name, field_name), context)) + field_name << ";" + ).generate(sink, attributes::unused, context)) return false; } return true; @@ -306,22 +300,12 @@ struct to_external_field_convert_generator // Internal Struct // -struct struct_internal_definition_generator +struct struct_private_property_generator { template bool generate(OutputIterator sink, attributes::struct_def const& struct_, Context const& context) const { auto const& indent = current_indentation(context); - if (!as_generator - ( - "#pragma warning disable CS1591\n\n" - << indent << "/// Internal wrapper for struct " << string << ".\n" - << indent << "[StructLayout(LayoutKind.Sequential)]\n" - << indent << "internal struct " << string << "\n" - << indent << "{\n" - ) - .generate(sink, std::make_tuple<>(binding_struct_name(struct_), struct_internal_decl_name()), context)) - return false; // iterate struct fields for (auto const& field : struct_.fields) @@ -337,7 +321,7 @@ struct struct_internal_definition_generator || regular->base_type == "any_value_ref"))) { if (!as_generator(indent << scope_tab << "/// Internal wrapper for field " << field_name << "\n" - << indent << scope_tab << "public System.IntPtr " << field_name << ";\n") + << indent << scope_tab << "private System.IntPtr " << field_name << ";\n") .generate(sink, nullptr, context)) return false; } @@ -345,7 +329,7 @@ struct struct_internal_definition_generator && regular->base_type == "bool") { if (!as_generator(indent << scope_tab << "/// Internal wrapper for field " << field_name << "\n" - << indent << scope_tab << "public System.Byte " << field_name << ";\n") + << indent << scope_tab << "private System.Byte " << field_name << ";\n") .generate(sink, nullptr, context)) return false; } @@ -353,12 +337,12 @@ struct struct_internal_definition_generator && regular->base_type == "char") { if (!as_generator(indent << scope_tab << "/// Internal wrapper for field " << field_name << "\n" - << indent << scope_tab << "public System.Byte " << field_name << ";\n") + << indent << scope_tab << "private System.Byte " << field_name << ";\n") .generate(sink, nullptr, context)) return false; } else if (!as_generator(indent << scope_tab << eolian_mono::marshall_annotation(false) << "\n" - << indent << scope_tab << "public " << eolian_mono::marshall_type(false) << " " << string << ";\n") + << indent << scope_tab << "private " << eolian_mono::marshall_type(false) << " " << string << ";\n") .generate(sink, std::make_tuple(field.type, field.type, field_name), context)) return false; } @@ -369,59 +353,18 @@ struct struct_internal_definition_generator // those 'mini-amd64.c condition fields not met' crashes. if (struct_.fields.size() == 0) { - if (!as_generator(indent << scope_tab << "internal IntPtr field;\n").generate(sink, nullptr, context)) + if (!as_generator(indent << scope_tab << "/// Placeholder field\n" + << indent << scope_tab << "private IntPtr field;\n").generate(sink, nullptr, context)) return false; } - auto external_name = binding_struct_name(struct_); - auto internal_name = binding_struct_internal_name(struct_); - - // to internal - if (!as_generator( - indent << scope_tab << "/// Implicit conversion to the internal/marshalling representation.\n" - << indent << scope_tab << "public static implicit operator " << string << "(" << string << " _external_struct)\n" - << indent << scope_tab << "{\n" - << indent << scope_tab << scope_tab << "var _internal_struct = new " << string << "();\n" - ).generate(sink, std::make_tuple(internal_name, external_name, internal_name), context)) + if(!as_generator("\n") + .generate(sink, attributes::unused, context)) return false; - for (auto const& field : struct_.fields) - { - if (!to_internal_field_convert.generate(sink, field, context)) - return false; - } - - if (!as_generator(indent << scope_tab << scope_tab << "return _internal_struct;\n" - << indent << scope_tab << "}\n\n").generate(sink, nullptr, context)) - return false; - - // to managed - if (!as_generator( - indent << scope_tab << "/// Implicit conversion to the managed representation.\n" - << indent << scope_tab << "public static implicit operator " << string << "(" << string << " _internal_struct)\n" - << indent << scope_tab << "{\n" - << indent << scope_tab << scope_tab << "var _external_struct = new " << string << "();\n" - ).generate(sink, std::make_tuple(external_name, internal_name, external_name), context)) - return false; - - for (auto const& field : struct_.fields) - { - if (!to_external_field_convert.generate(sink, field, context)) - return false; - } - - if (!as_generator(indent << scope_tab << scope_tab << "return _external_struct;\n" - << indent << scope_tab << "}\n").generate(sink, nullptr, context)) - return false; - - // close internal class - if(!as_generator(indent << "}\n" - << "#pragma warning restore CS1591\n" - ).generate(sink, attributes::unused, context)) return false; - return true; } -} const struct_internal_definition {}; +} const struct_private_property {}; // Managed Struct // @@ -454,34 +397,22 @@ struct struct_definition_generator return false; if (!as_generator( - indent << scope_tab << "public static implicit operator " << struct_name << "(\n" - << indent << scope_tab << scope_tab << "(\n" - << ((indent << scope_tab << scope_tab << " " << field_argument_decl) % ",\n") << "\n" - << indent << scope_tab << scope_tab << ") tuple)\n" - << indent << scope_tab << "{\n" + indent << scope_tab << "public static implicit operator " << struct_name << "((" + << (field_argument_decl % ", ") + << ") tuple)\n" ).generate(sink, struct_.fields, context)) return false; // object constructor if (!as_generator( - indent << scope_tab << scope_tab << "return new " << struct_name << "{\n" + indent << scope_tab << scope_tab << "=> new " << struct_name << "(" ).generate(sink, attributes::unused, context)) return false; - for (const auto& field: struct_.fields) - { - auto field_name = name_helpers::to_field_name(field.name); - - if (!as_generator( - indent << scope_tab << scope_tab << scope_tab << field_name << " = tuple." << field_name << ",\n" - ).generate(sink, attributes::unused, context)) - return false; - } - if (!as_generator( - indent << scope_tab << scope_tab << "};\n" - << indent << scope_tab << "}\n" - ).generate(sink, attributes::unused, context)) + (("tuple." << struct_field_name) % ", ") + << ");\n\n" + ).generate(sink, struct_.fields, context)) return false; return true; @@ -528,10 +459,11 @@ struct struct_definition_generator // assigments for (auto const& field : struct_.fields) { - auto field_name = name_helpers::to_field_name(field.name); + auto field_name = name_helpers::managed_name(field.name); + auto param_name = name_helpers::to_field_name(field.name); if (!as_generator( - indent << scope_tab << scope_tab << field_name << " = this." << field_name << ";\n" + indent << scope_tab << scope_tab << param_name << " = this." << field_name << ";\n" ).generate(sink, attributes::unused, context)) return false; } @@ -561,6 +493,9 @@ struct struct_definition_generator .generate(sink, attributes::unused, context)) return false; + if (!struct_private_property.generate(sink, struct_, change_indentation(indent, context))) + return false; + // iterate struct fields for (auto const& field : struct_.fields) { @@ -574,23 +509,13 @@ struct struct_definition_generator return false; } - if (!as_generator(indent << scope_tab << "public " << type << " " << name_helpers::to_field_name(field.name) << ";\n").generate(sink, field.type, context)) + if (!as_generator(indent << scope_tab << "public " << type << " " << name_helpers::managed_name(field.name) << " { get => " << to_external_field_convert << " }\n").generate(sink, std::make_tuple(field.type, field), context)) return false; } auto struct_name = binding_struct_name(struct_); - // Check whether this is an extern struct without declared fields in .eo file and generate a - // placeholder field if positive. - // Mono's JIT is picky when generating function pointer for delegates with empty structs, leading to - // those 'mini-amd64.c condition fields not met' crashes. - if (struct_.fields.size() == 0) - { - if (!as_generator(indent << scope_tab << "/// Placeholder field\n" - << indent << scope_tab << "public IntPtr field;\n").generate(sink, nullptr, context)) - return false; - } - else + if (struct_.fields.size() != 0) { // Constructor with default parameters for easy struct initialization if(!as_generator( @@ -608,9 +533,9 @@ struct struct_definition_generator << *(indent << scope_tab << field_argument_docs << "\n") << indent << scope_tab << "public " << string << "(\n" << ((indent << scope_tab << scope_tab << field_argument_default) % ",\n") - << indent << scope_tab << ")\n" + << ")\n" << indent << scope_tab << "{\n" - << *(indent << scope_tab << scope_tab << field_argument_assignment << ";\n") + << *(indent << scope_tab << scope_tab << field_argument_assignment) << indent << scope_tab << "}\n\n") .generate(sink, std::make_tuple(struct_.fields, struct_name, struct_.fields, struct_.fields), context)) return false; @@ -638,7 +563,14 @@ struct struct_definition_generator ).generate(sink, attributes::unused, context)) return false; - if (struct_.fields.size() != 0 ) + if (struct_.fields.size() == 1 ) + { + if (!as_generator( + indent << scope_tab << scope_tab << "return " << name_helpers::managed_name(struct_.fields[0].name) << ".GetHashCode();\n" + ).generate(sink, attributes::unused, context)) + return false; + } + else if (struct_.fields.size() != 0 ) { // int hash = 17; // hash = 23 * fieldA.GetHashCode(); @@ -647,7 +579,7 @@ struct struct_definition_generator // return hash if (!as_generator( indent << scope_tab << scope_tab << "int hash = 17;\n" - << *(grammar::attribute_reorder<-1, -1>(indent << scope_tab << scope_tab << "hash = hash * 23 + " << name_helpers::struct_field_name << ".GetHashCode(" << culture_info << ");\n")) + << *(grammar::attribute_reorder<-1, -1>(indent << scope_tab << scope_tab << "hash = hash * 23 + " << name_helpers::struct_property_name << ".GetHashCode(" << culture_info << ");\n")) << indent << scope_tab << scope_tab << "return hash;\n" ).generate(sink, struct_.fields, context)) return false; @@ -656,7 +588,7 @@ struct struct_definition_generator { // Just compare the place holder pointers if (!as_generator( - "return field.GetHashCode();\n" + indent << scope_tab << scope_tab << "return field.GetHashCode();\n" ).generate(sink, attributes::unused, context)) return false; } @@ -680,7 +612,7 @@ struct struct_definition_generator if (struct_.fields.size() != 0 ) { if (!as_generator( - grammar::attribute_reorder<-1, -1>((name_helpers::struct_field_name << " == other." << name_helpers::struct_field_name)) % " && " + grammar::attribute_reorder<-1, -1>((name_helpers::struct_property_name << " == other." << name_helpers::struct_property_name)) % " && " ).generate(sink, struct_.fields, context)) return false; } @@ -695,7 +627,7 @@ struct struct_definition_generator if (!as_generator( - indent << scope_tab << scope_tab << ";\n" + ";\n" << indent << scope_tab << "}\n" ).generate(sink, attributes::unused, context)) return false; @@ -745,8 +677,7 @@ struct struct_definition_generator << indent << scope_tab << "/// Native pointer to be converted.\n" << indent << scope_tab << "public static implicit operator " << struct_name << "(IntPtr ptr)\n" << indent << scope_tab << "{\n" - << indent << scope_tab << scope_tab << "var tmp = (" << struct_name << ".NativeStruct)Marshal.PtrToStructure(ptr, typeof(" << struct_name << ".NativeStruct));\n" - << indent << scope_tab << scope_tab << "return tmp;\n" + << indent << scope_tab << scope_tab << "return (" << struct_name << ")Marshal.PtrToStructure(ptr, typeof(" << struct_name << "));\n" << indent << scope_tab << "}\n\n" ).generate(sink, attributes::unused, context)) return false; @@ -771,9 +702,6 @@ struct struct_definition_generator ).generate(sink, attributes::unused, context)) return false; - if (!struct_internal_definition.generate(sink, struct_, change_indentation(indent.inc(), context))) - return false; - if(!as_generator(indent << "}\n\n").generate(sink, attributes::unused, context)) return false; return true; @@ -809,9 +737,9 @@ template <> struct is_generator< ::eolian_mono::struct_definition_generator> : std::true_type {}; template <> -struct is_eager_generator< ::eolian_mono::struct_internal_definition_generator> : std::true_type {}; +struct is_eager_generator< ::eolian_mono::struct_private_property_generator> : std::true_type {}; template <> -struct is_generator< ::eolian_mono::struct_internal_definition_generator> : std::true_type {}; +struct is_generator< ::eolian_mono::struct_private_property_generator> : std::true_type {}; template <> struct is_eager_generator< ::eolian_mono::to_internal_field_convert_generator> : std::true_type {}; @@ -833,7 +761,7 @@ template <> struct attributes_needed< ::eolian_mono::struct_definition_generator> : std::integral_constant {}; template <> -struct attributes_needed< ::eolian_mono::struct_internal_definition_generator> : std::integral_constant {}; +struct attributes_needed< ::eolian_mono::struct_private_property_generator> : std::integral_constant {}; template <> struct attributes_needed< ::eolian_mono::to_internal_field_convert_generator> : std::integral_constant {}; diff --git a/src/bin/eolian_mono/eolian/mono/struct_fields.hh b/src/bin/eolian_mono/eolian/mono/struct_fields.hh index 76e0f64138..a9f400bbc5 100644 --- a/src/bin/eolian_mono/eolian/mono/struct_fields.hh +++ b/src/bin/eolian_mono/eolian/mono/struct_fields.hh @@ -69,11 +69,121 @@ struct field_argument_assignment_generator template bool generate(OutputIterator sink, attributes::struct_field_def const& field, Context const& context) const { - auto field_name = name_helpers::to_field_name(field.name); - if (!as_generator("this." << field_name << " = " << field_name) - .generate(sink, attributes::unused, context)) - return false; - return true; + auto field_name = to_field_name(field.name); + // FIXME Replace need_struct_conversion(regular) with need_struct_conversion(type) + auto regular = efl::eina::get(&field.type.original_type); + auto klass = efl::eina::get(&field.type.original_type); + auto complex = efl::eina::get(&field.type.original_type); + + if (klass) + { + if (!as_generator( + "this." << string << " = " << string << "?.NativeHandle ?? System.IntPtr.Zero;\n") + .generate(sink, std::make_tuple(field_name, field_name), context)) + return false; + } + else if ((complex && (complex->outer.base_type == "array"))) + { + if (!as_generator( + "this." << string << " = Efl.Eo.Globals.IListToNativeArray(" << string << ", " << (field.type.has_own ? "true" : "false") << ");\n") + .generate(sink, std::make_tuple(field_name, field_name), context)) + return false; + } + else if ((complex && (complex->outer.base_type == "list"))) + { + if (!as_generator( + "this." << string << " = Efl.Eo.Globals.IListToNativeList(" << string << ", " << (field.type.has_own ? "true" : "false") << ");\n") + .generate(sink, std::make_tuple(field_name, field_name), context)) + return false; + } + else if ((complex && (complex->outer.base_type == "iterator"))) + { + if (!as_generator( + "this." << string << " = Efl.Eo.Globals.IEnumerableToIterator(" << string << ", " << (field.type.has_own ? "true" : "false") << ");\n") + .generate(sink, std::make_tuple(field_name, field_name), context)) + return false; + } + else if ((complex && (complex->outer.base_type == "hash")) + || field.type.c_type == "Eina_Binbuf *" || field.type.c_type == "const Eina_Binbuf *") + { + // Always assumes pointer + if (!as_generator( + "this." << string << " = " << string << ".Handle;\n") + .generate(sink, std::make_tuple(field_name, field_name), context)) + return false; + } + else if (field.type.is_ptr && helpers::need_pointer_conversion(regular) && !helpers::need_struct_conversion(regular)) + { + if (!as_generator( + "this." << string << " = Eina.PrimitiveConversion.ManagedToPointerAlloc(" << string << ");\n") + .generate(sink, std::make_tuple(field_name, field_name), context)) + return false; + } + else if (helpers::need_struct_conversion(regular)) + { + if (!as_generator( + "this." << string << " = " << string << ";\n") + .generate(sink, std::make_tuple(field_name, field_name), context)) + return false; + } + else if (regular && (regular->base_type == "string" || regular->base_type == "mstring")) + { + if (!as_generator( + "this." << string << " = Eina.MemoryNative.StrDup(" << string << ");\n") + .generate(sink, std::make_tuple(field_name, field_name), context)) + return false; + } + else if (regular && regular->base_type == "stringshare") + { + if (!as_generator( + "this." << string << " = Eina.MemoryNative.AddStringshare(" << string << ");\n") + .generate(sink, std::make_tuple(field_name, field_name), context)) + return false; + } + else if (field.type.c_type == "Eina_Slice" || field.type.c_type == "const Eina_Slice" + || field.type.c_type == "Eina_Rw_Slice" || field.type.c_type == "const Eina_Rw_Slice") + { + if (!as_generator( + "this." << string << " = " << string << ";\n") + .generate(sink, std::make_tuple(field_name, field_name), context)) + return false; + } + else if (field.type.c_type == "Eina_Value" || field.type.c_type == "const Eina_Value") + { + if (!as_generator( + "this." << string << " = " << string << ".GetNative();\n" + ).generate(sink, std::make_tuple(field_name, field_name), context)) + return false; + } + else if (field.type.c_type == "Eina_Value *" || field.type.c_type == "const Eina_Value *") + { + if (!as_generator( + "this." << string << " = " << string << "?.NativeHandle ?? System.IntPtr.Zero;\n" + ).generate(sink, std::make_tuple(field_name, field_name), context)) + return false; + } + else if (!field.type.is_ptr && regular && regular->base_type == "bool") + { + if (!as_generator( + "this." << string << " = " << string << " ? (byte)1 : (byte)0;\n") + .generate(sink, std::make_tuple(field_name, field_name), context)) + return false; + } + else if (!field.type.is_ptr && regular && regular->base_type == "char") + { + if (!as_generator( + "this." << string << " = (byte)" << string << ";\n") + .generate(sink, std::make_tuple(field_name, field_name), context)) + return false; + } + else // primitives and enums + { + if (!as_generator( + "this." << string << " = " << string << ";\n") + .generate(sink, std::make_tuple(field_name, field_name), context)) + return false; + } + return true; } } const field_argument_assignment {}; diff --git a/src/bin/eolian_mono/eolian/mono/utils.hh b/src/bin/eolian_mono/eolian/mono/utils.hh index d942903aba..7905790b4c 100644 --- a/src/bin/eolian_mono/eolian/mono/utils.hh +++ b/src/bin/eolian_mono/eolian/mono/utils.hh @@ -90,6 +90,28 @@ namespace eolian_mono { namespace utils { return ret; } + std::string to_camel_case(const std::vector &names, std::string const& delim="") + { + std::vector outv(names.size()); + std::stringstream osstream; + + std::transform(names.begin(), names.end(), outv.begin(), + [](std::string name) { + name[0] = std::toupper(name[0]); + return name; + }); + + std::copy(outv.begin(), outv.end(), std::ostream_iterator(osstream, delim.c_str())); + + std::string ret = osstream.str(); + + if (delim != "") + ret.pop_back(); // We could implement an infix_iterator but this pop is enough for now. + + ret[0] = std::tolower(ret[0]); + return ret; + } + inline std::string remove_all(std::string name, char target) { name.erase(std::remove(name.begin(), name.end(), target), name.end()); diff --git a/src/bindings/mono/eo_mono/EoWrapper.cs b/src/bindings/mono/eo_mono/EoWrapper.cs index 99e60b1d2b..db618232c4 100644 --- a/src/bindings/mono/eo_mono/EoWrapper.cs +++ b/src/bindings/mono/eo_mono/EoWrapper.cs @@ -328,7 +328,7 @@ public abstract class EoWrapper : IWrapper, IDisposable internal Efl.EventCb GetInternalEventCallback(EventHandler handler, Func createArgsInstance) where T:EventArgs { - return (IntPtr data, ref Efl.Event.NativeStruct evt) => + return (IntPtr data, ref Efl.Event evt) => { var obj = Efl.Eo.Globals.WrapperSupervisorPtrToManaged(data).Target; if (obj != null) @@ -348,7 +348,7 @@ public abstract class EoWrapper : IWrapper, IDisposable internal Efl.EventCb GetInternalEventCallback(EventHandler handler) { - return (IntPtr data, ref Efl.Event.NativeStruct evt) => + return (IntPtr data, ref Efl.Event evt) => { var obj = Efl.Eo.Globals.WrapperSupervisorPtrToManaged(data).Target; if (obj != null) @@ -383,13 +383,13 @@ public abstract class EoWrapper : IWrapper, IDisposable } } - private static void OwnershipUniqueCallback(IntPtr data, ref Efl.Event.NativeStruct evt) + private static void OwnershipUniqueCallback(IntPtr data, ref Efl.Event evt) { var ws = Efl.Eo.Globals.WrapperSupervisorPtrToManaged(data); ws.MakeUnique(); } - private static void OwnershipSharedCallback(IntPtr data, ref Efl.Event.NativeStruct evt) + private static void OwnershipSharedCallback(IntPtr data, ref Efl.Event evt) { var ws = Efl.Eo.Globals.WrapperSupervisorPtrToManaged(data); ws.MakeShared(); diff --git a/src/bindings/mono/eo_mono/workaround.cs b/src/bindings/mono/eo_mono/workaround.cs index 0afe95807b..3e6829feef 100644 --- a/src/bindings/mono/eo_mono/workaround.cs +++ b/src/bindings/mono/eo_mono/workaround.cs @@ -173,17 +173,24 @@ internal struct EventDescription [Efl.Eo.BindingEntity] internal struct Event { + /// Internal wrapper for field Object + private System.IntPtr obj; + /// Internal wrapper for field Desc + private System.IntPtr desc; + /// Internal wrapper for field Info + private System.IntPtr info; + /// /// The object the callback was called on. /// Since EFL 1.22. /// - public Efl.Object Object; + public Efl.Object Object { get => (Efl.Object) Efl.Eo.Globals.CreateWrapperFor(obj); } /// /// The event description. /// Since EFL 1.22. /// - public Efl.EventDescription Desc; + public Efl.EventDescription Desc { get => Eina.PrimitiveConversion.PointerToManaged(desc); } /// /// Extra event information passed by the event caller. @@ -192,7 +199,7 @@ internal struct Event /// 2) Structs, built-in types and containers are passed as const pointers, with one level of indirection. /// Since EFL 1.22. /// - public System.IntPtr Info; + public System.IntPtr Info { get => info; } /// Constructor for Event. public Event( @@ -200,59 +207,21 @@ internal struct Event Efl.EventDescription desc = default(Efl.EventDescription), System.IntPtr info = default(System.IntPtr)) { - this.Object = obj; - this.Desc = desc; - this.Info = info; + this.obj = obj?.NativeHandle ?? System.IntPtr.Zero; + this.desc = Eina.PrimitiveConversion.ManagedToPointerAlloc(desc); + this.info = info; } /// Implicit conversion to the managed representation from a native pointer. /// Native pointer to be converted. public static implicit operator Event(IntPtr ptr) { - var tmp = (Event.NativeStruct) Marshal.PtrToStructure(ptr, typeof(Event.NativeStruct)); + var tmp = (Event) Marshal.PtrToStructure(ptr, typeof(Event)); return tmp; } - - /// Internal wrapper for struct Event. - [StructLayout(LayoutKind.Sequential)] - public struct NativeStruct - { - /// Internal wrapper for field Object - public System.IntPtr Object; - - /// Internal wrapper for field Desc - public System.IntPtr Desc; - - /// Internal wrapper for field Info - public System.IntPtr Info; - - /// Implicit conversion to the internal/marshalling representation. - /// Managed struct to be converted. - /// Native representation of the managed struct. - public static implicit operator Event.NativeStruct(Event externalStruct) - { - var internalStruct = new Event.NativeStruct(); - internalStruct.Object = externalStruct.Object?.NativeHandle ?? System.IntPtr.Zero; - internalStruct.Desc = Eina.PrimitiveConversion.ManagedToPointerAlloc(externalStruct.Desc); - internalStruct.Info = externalStruct.Info; - return internalStruct; - } - - /// Implicit conversion to the managed representation. - /// Native struct to be converted. - /// Managed representation of the native struct. - public static implicit operator Event(Event.NativeStruct internalStruct) - { - var externalStruct = new Event(); - externalStruct.Object = (Efl.Object) Efl.Eo.Globals.CreateWrapperFor(internalStruct.Object); - externalStruct.Desc = Eina.PrimitiveConversion.PointerToManaged(internalStruct.Desc); - externalStruct.Info = internalStruct.Info; - return externalStruct; - } - } } -internal delegate void EventCb(System.IntPtr data, ref Event.NativeStruct evt); +internal delegate void EventCb(System.IntPtr data, ref Event evt); internal delegate void FreeWrapperSupervisorCb(System.IntPtr obj); namespace Access diff --git a/src/tests/efl_mono/Events.cs b/src/tests/efl_mono/Events.cs index c10c37911e..2abcc98b63 100644 --- a/src/tests/efl_mono/Events.cs +++ b/src/tests/efl_mono/Events.cs @@ -196,8 +196,7 @@ class TestEoEvents received_struct = e.arg; }; - Dummy.StructSimple sent_struct = default(Dummy.StructSimple); - sent_struct.Fstring = "Struct Event"; + Dummy.StructSimple sent_struct = new Dummy.StructSimple(fstring: "Struct Event"); obj.EmitEventWithStruct(sent_struct); diff --git a/src/tests/efl_mono/StructHelpers.cs b/src/tests/efl_mono/StructHelpers.cs index 5e6dc506a7..495638458a 100644 --- a/src/tests/efl_mono/StructHelpers.cs +++ b/src/tests/efl_mono/StructHelpers.cs @@ -30,40 +30,38 @@ internal class StructHelpers internal static Dummy.StructSimple structSimpleWithValues() { - var simple = new Dummy.StructSimple(); - - simple.Fbyte = (sbyte)-126; - simple.Fubyte = (byte) 254u; - simple.Fchar = '~'; - simple.Fshort = (short) -32766; - simple.Fushort = (ushort) 65534u; - simple.Fint = -32766; - simple.Fuint = 65534u; - simple.Flong = -2147483646; - simple.Fulong = 4294967294u; - simple.Fllong = -9223372036854775806; - simple.Fullong = 18446744073709551614u; - simple.Fint8 = (sbyte) -126; - simple.Fuint8 = (byte) 254u; - simple.Fint16 = (short) -32766; - simple.Fuint16 = (ushort) 65534u; - simple.Fint32 = -2147483646; - simple.Fuint32 = 4294967294u; - simple.Fint64 = -9223372036854775806; - simple.Fuint64 = 18446744073709551614u; - simple.Fssize = -2147483646; - simple.Fsize = 4294967294u; - simple.Fintptr = (IntPtr) 0xFE; - simple.Fptrdiff = -2147483646; - simple.Ffloat = -16777216.0f; - simple.Fdouble = -9007199254740992.0; - simple.Fbool = true; - simple.Fenum = Dummy.SampleEnum.V2; - simple.Fstring = "test/string"; - simple.Fmstring = "test/mstring"; - simple.Fstringshare = "test/stringshare"; - - return simple; + return new Dummy.StructSimple( + fbyte: (sbyte)-126, + fubyte: (byte) 254u, + fchar: '~', + fshort: (short) -32766, + fushort: (ushort) 65534u, + fint: -32766, + fuint: 65534u, + flong: -2147483646, + fulong: 4294967294u, + fllong: -9223372036854775806, + fullong: 18446744073709551614u, + fint8: (sbyte) -126, + fuint8: (byte) 254u, + fint16: (short) -32766, + fuint16: (ushort) 65534u, + fint32: -2147483646, + fuint32: 4294967294u, + fint64: -9223372036854775806, + fuint64: 18446744073709551614u, + fssize: -2147483646, + fsize: 4294967294u, + fintptr: (IntPtr) 0xFE, + fptrdiff: -2147483646, + ffloat: -16777216.0f, + fdouble: -9007199254740992.0, + fbool: true, + fenum: Dummy.SampleEnum.V2, + fstring: "test/string", + fmstring: "test/mstring", + fstringshare: "test/stringshare" + ); } internal static void checkStructSimple(Dummy.StructSimple simple) @@ -137,42 +135,41 @@ internal class StructHelpers #if EFL_BETA internal static Dummy.StructComplex structComplexWithValues() { - var complex = new Dummy.StructComplex(); + var Farray = new Eina.Array(); + Farray.Add("0x0"); + Farray.Add("0x2A"); + Farray.Add("0x42"); - complex.Farray = new Eina.Array(); - complex.Farray.Add("0x0"); - complex.Farray.Add("0x2A"); - complex.Farray.Add("0x42"); + var Flist = new Eina.List(); + Flist.Add("0x0"); + Flist.Add("0x2A"); + Flist.Add("0x42"); - complex.Flist = new Eina.List(); - complex.Flist.Add("0x0"); - complex.Flist.Add("0x2A"); - complex.Flist.Add("0x42"); + var Fhash = new Eina.Hash(); + Fhash["aa"] = "aaa"; + Fhash["bb"] = "bbb"; + Fhash["cc"] = "ccc"; - complex.Fhash = new Eina.Hash(); - complex.Fhash["aa"] = "aaa"; - complex.Fhash["bb"] = "bbb"; - complex.Fhash["cc"] = "ccc"; + var Fiterator = ((Eina.Array)Farray).GetIterator(); - complex.Fiterator = ((Eina.Array)complex.Farray).GetIterator(); + var Fany_value = new Eina.Value(Eina.ValueType.Double); + Fany_value.Set(-9007199254740992.0); - complex.Fany_value = new Eina.Value(Eina.ValueType.Double); - complex.Fany_value.Set(-9007199254740992.0); + var Fany_value_ref = new Eina.Value(Eina.ValueType.String); + Fany_value_ref.Set("abc"); - complex.Fany_value_ref = new Eina.Value(Eina.ValueType.String); - complex.Fany_value_ref.Set("abc"); + var Fbinbuf = new Eina.Binbuf(); + Fbinbuf.Append(126); - complex.Fbinbuf = new Eina.Binbuf(); - complex.Fbinbuf.Append(126); + var Fslice = new Eina.Slice(Eina.MemoryNative.Alloc(1), (UIntPtr)1); + Marshal.WriteByte(Fslice.Mem, 125); - complex.Fslice.Length = 1; - complex.Fslice.Mem = Eina.MemoryNative.Alloc(1); - Marshal.WriteByte(complex.Fslice.Mem, 125); + var Fobj = new Dummy.Numberwrapper(); + Fobj.SetNumber(42); - complex.Fobj = new Dummy.Numberwrapper(); - complex.Fobj.SetNumber(42); - - return complex; + return new Dummy.StructComplex(farray: Farray, flist: Flist, fhash: Fhash, + fiterator: Fiterator, fanyValue:Fany_value, fanyValueRef: Fany_value_ref, + fbinbuf: Fbinbuf, fslice:Fslice, fobj: Fobj); } internal static void checkStructComplex(Dummy.StructComplex complex) @@ -194,11 +191,11 @@ internal class StructHelpers Test.AssertEquals(idx, base_seq_str.Length); double double_val = 0; - Test.Assert(complex.Fany_value.Get(out double_val)); + Test.Assert(complex.FanyValue.Get(out double_val)); Test.Assert(double_val == -9007199254740992.0); string str_val = null; - Test.Assert(complex.Fany_value_ref.Get(out str_val)); + Test.Assert(complex.FanyValueRef.Get(out str_val)); Test.Assert(str_val == "abc"); Test.Assert(complex.Fbinbuf.Length == 1); @@ -218,8 +215,8 @@ internal class StructHelpers Test.Assert(complex.Flist == null); Test.Assert(complex.Fhash == null); Test.Assert(complex.Fiterator == null); - Test.Assert(complex.Fany_value == null); - Test.Assert(complex.Fany_value_ref == null); + Test.Assert(complex.FanyValue == null); + Test.Assert(complex.FanyValueRef == null); Test.Assert(complex.Fbinbuf == null); Test.Assert(complex.Fslice.Length == 0); diff --git a/src/tests/efl_mono/Structs.cs b/src/tests/efl_mono/Structs.cs index d546298908..e110f2f15a 100644 --- a/src/tests/efl_mono/Structs.cs +++ b/src/tests/efl_mono/Structs.cs @@ -180,8 +180,7 @@ internal class TestStructs public override bool StructSimpleOut(out Dummy.StructSimple simple) { called = true; - simple = new Dummy.StructSimple(); - simple.Fstring = "Virtual Struct Out"; + simple = new Dummy.StructSimple(fstring: "Virtual Struct Out"); return true; } @@ -206,8 +205,7 @@ internal class TestStructs public override Dummy.StructSimple StructSimpleReturn() { called = true; - var simple = new Dummy.StructSimple(); - simple.Fstring = "Virtual Struct Return"; + var simple = new Dummy.StructSimple(fstring: "Virtual Struct Return"); return simple; } @@ -234,7 +232,6 @@ internal class TestStructs { StructReturner t = new StructReturner(); var simple = structSimpleWithValues(); - simple.Fstring = "Virtual Struct In"; t.CallStructSimpleIn(simple); Test.Assert(t.called); @@ -379,13 +376,13 @@ internal class TestStructs internal class TestStructEquality { - static Dummy.StructSimple a = new Dummy.StructSimple(1, 2, (char)3, 4, Fstring: "", Fmstring: "", Fstringshare: ""); - static Dummy.StructSimple b = new Dummy.StructSimple(1, 2, (char)3, 4, Fstring: "", Fmstring: "", Fstringshare: ""); + static Dummy.StructSimple a = new Dummy.StructSimple(1, 2, (char)3, 4, fstring: "", fmstring: "", fstringshare: ""); + static Dummy.StructSimple b = new Dummy.StructSimple(1, 2, (char)3, 4, fstring: "", fmstring: "", fstringshare: ""); - static Dummy.StructSimple c = new Dummy.StructSimple(4, 3, (char)2, 1, Fstring: "", Fmstring: "", Fstringshare: ""); + static Dummy.StructSimple c = new Dummy.StructSimple(4, 3, (char)2, 1, fstring: "", fmstring: "", fstringshare: ""); // to check if we differ on a single struct field - static Dummy.StructSimple singleDifferentField = new Dummy.StructSimple(1, 2, (char)3, 5, Fstring: "", Fmstring: "", Fstringshare: ""); + static Dummy.StructSimple singleDifferentField = new Dummy.StructSimple(1, 2, (char)3, 5, fstring: "", fmstring: "", fstringshare: ""); public static void test_equals() {