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
This commit is contained in:
Yeongjong Lee 2020-01-28 14:46:10 +09:00 committed by WooHyun Jung
parent b3c0da13d8
commit 581bec9598
10 changed files with 316 additions and 276 deletions

View File

@ -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<bool> b = type_match::get_match

View File

@ -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<std::string> 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 <typename OutputIterator, typename Context>
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<eolian_mono::name_helpers::struct_field_name_generator
template <>
struct is_generator< ::eolian_mono::name_helpers::struct_field_name_generator> : std::true_type {};
template <>
struct is_eager_generator<eolian_mono::name_helpers::struct_property_name_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<struct ::eolian_mono::name_helpers::klass_full_concrete_or_interface_name_generator> : std::integral_constant<int, 1> {};
template <>
struct attributes_needed< ::eolian_mono::name_helpers::struct_field_name_generator> : std::integral_constant<int, 1> {};
template <>
struct attributes_needed< ::eolian_mono::name_helpers::struct_property_name_generator> : std::integral_constant<int, 1> {};
}

View File

@ -181,7 +181,6 @@ struct to_external_field_convert_generator
template <typename OutputIterator, typename Context>
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<attributes::regular_type_def>(&field.type.original_type);
auto klass = efl::eina::get<attributes::klass_name>(&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 <typename OutputIterator, typename Context>
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 << "/// <summary>Internal wrapper for struct " << string << ".</summary>\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 << "/// <summary>Internal wrapper for field " << field_name << "</summary>\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 << "/// <summary>Internal wrapper for field " << field_name << "</summary>\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 << "/// <summary>Internal wrapper for field " << field_name << "</summary>\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 << "/// <summary>Placeholder field</summary>\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 << "/// <summary>Implicit conversion to the internal/marshalling representation.</summary>\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 << "/// <summary>Implicit conversion to the managed representation.</summary>\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 << "/// <summary>Placeholder field</summary>\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 << "/// <param name=\"ptr\">Native pointer to be converted.</param>\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<int, 1> {};
template <>
struct attributes_needed< ::eolian_mono::struct_internal_definition_generator> : std::integral_constant<int, 1> {};
struct attributes_needed< ::eolian_mono::struct_private_property_generator> : std::integral_constant<int, 1> {};
template <>
struct attributes_needed< ::eolian_mono::to_internal_field_convert_generator> : std::integral_constant<int, 1> {};

View File

@ -69,11 +69,121 @@ struct field_argument_assignment_generator
template<typename OutputIterator, typename Context>
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<attributes::regular_type_def>(&field.type.original_type);
auto klass = efl::eina::get<attributes::klass_name>(&field.type.original_type);
auto complex = efl::eina::get<attributes::complex_type_def>(&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 {};

View File

@ -90,6 +90,28 @@ namespace eolian_mono { namespace utils {
return ret;
}
std::string to_camel_case(const std::vector<std::string> &names, std::string const& delim="")
{
std::vector<std::string> 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<std::string>(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());

View File

@ -328,7 +328,7 @@ public abstract class EoWrapper : IWrapper, IDisposable
internal Efl.EventCb GetInternalEventCallback<T>(EventHandler<T> handler, Func<IntPtr, T> 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();

View File

@ -173,17 +173,24 @@ internal struct EventDescription
[Efl.Eo.BindingEntity]
internal struct Event
{
/// <summary>Internal wrapper for field Object</summary>
private System.IntPtr obj;
/// <summary>Internal wrapper for field Desc</summary>
private System.IntPtr desc;
/// <summary>Internal wrapper for field Info</summary>
private System.IntPtr info;
/// <summary>
/// The object the callback was called on.
/// <para>Since EFL 1.22.</para>
/// </summary>
public Efl.Object Object;
public Efl.Object Object { get => (Efl.Object) Efl.Eo.Globals.CreateWrapperFor(obj); }
/// <summary>
/// The event description.
/// <para>Since EFL 1.22.</para>
/// </summary>
public Efl.EventDescription Desc;
public Efl.EventDescription Desc { get => Eina.PrimitiveConversion.PointerToManaged<Efl.EventDescription>(desc); }
/// <summary>
/// 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.
/// <para>Since EFL 1.22.</para>
/// </summary>
public System.IntPtr Info;
public System.IntPtr Info { get => info; }
/// <summary>Constructor for Event.</summary>
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;
}
/// <summary>Implicit conversion to the managed representation from a native pointer.</summary>
/// <param name="ptr">Native pointer to be converted.</param>
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;
}
/// <summary>Internal wrapper for struct Event.</summary>
[StructLayout(LayoutKind.Sequential)]
public struct NativeStruct
{
/// <summary>Internal wrapper for field Object</summary>
public System.IntPtr Object;
/// <summary>Internal wrapper for field Desc</summary>
public System.IntPtr Desc;
/// <summary>Internal wrapper for field Info</summary>
public System.IntPtr Info;
/// <summary>Implicit conversion to the internal/marshalling representation.</summary>
/// <param name="externalStruct">Managed struct to be converted.</param>
/// <returns>Native representation of the managed struct.</returns>
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;
}
/// <summary>Implicit conversion to the managed representation.</summary>
/// <param name="internalStruct">Native struct to be converted.</param>
/// <returns>Managed representation of the native struct.</returns>
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<Efl.EventDescription>(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

View File

@ -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);

View File

@ -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<string>();
Farray.Add("0x0");
Farray.Add("0x2A");
Farray.Add("0x42");
complex.Farray = new Eina.Array<string>();
complex.Farray.Add("0x0");
complex.Farray.Add("0x2A");
complex.Farray.Add("0x42");
var Flist = new Eina.List<string>();
Flist.Add("0x0");
Flist.Add("0x2A");
Flist.Add("0x42");
complex.Flist = new Eina.List<string>();
complex.Flist.Add("0x0");
complex.Flist.Add("0x2A");
complex.Flist.Add("0x42");
var Fhash = new Eina.Hash<string, string>();
Fhash["aa"] = "aaa";
Fhash["bb"] = "bbb";
Fhash["cc"] = "ccc";
complex.Fhash = new Eina.Hash<string, string>();
complex.Fhash["aa"] = "aaa";
complex.Fhash["bb"] = "bbb";
complex.Fhash["cc"] = "ccc";
var Fiterator = ((Eina.Array<string>)Farray).GetIterator();
complex.Fiterator = ((Eina.Array<string>)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);

View File

@ -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()
{