forked from enlightenment/efl
csharp: Add implicit conversion from tuples to structs.
Summary: Also generates implicit conversion for 1-field structs. Usage examples: ``` // With tuples Point2D p = (1, 2); obj.SetPoint((1, 2)); // With 1-field structs StringWrapper sw = "Must be handled by wrapper."; ``` Due to limitations of MSC compiler, implicit conversions are generated only if struct has 4 fields or less. Ref T8489. Reviewers: brunobelo, cedric, lauromoura, segfaultxavi Reviewed By: lauromoura Subscribers: #reviewers, #committers Tags: #efl Maniphest Tasks: T8489 Differential Revision: https://phab.enlightenment.org/D10801
This commit is contained in:
parent
8a2ccfefe1
commit
e617ff441a
|
@ -403,6 +403,66 @@ struct struct_internal_definition_generator
|
||||||
|
|
||||||
struct struct_definition_generator
|
struct struct_definition_generator
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Generates an implicit operator for packing only if the struct has more
|
||||||
|
* than one attribute. Then operator will receive a tuple with the same of
|
||||||
|
* each attribute's type in the same order they were declared.
|
||||||
|
*
|
||||||
|
* Remarks: due to the MCS compiler's limitations, no operator is generated
|
||||||
|
* for structs with more than 4 fields.
|
||||||
|
*/
|
||||||
|
template <typename OutputIterator, typename Context>
|
||||||
|
bool generate_implicit_operator(attributes::struct_def const& struct_
|
||||||
|
, OutputIterator sink
|
||||||
|
, Context const& context) const
|
||||||
|
{
|
||||||
|
if (struct_.fields.size() <= 1 || struct_.fields.size() > 4)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
auto struct_name = binding_struct_name(struct_);
|
||||||
|
auto const& indent = current_indentation(context);
|
||||||
|
|
||||||
|
if (!as_generator(
|
||||||
|
indent << scope_tab << "/// <summary>Packs tuple into " << struct_name << " object.\n"
|
||||||
|
<< indent << scope_tab << "///<para>Since EFL 1.24.</para>\n"
|
||||||
|
<< indent << scope_tab << "///</summary>\n"
|
||||||
|
).generate(sink, attributes::unused, context))
|
||||||
|
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"
|
||||||
|
).generate(sink, struct_.fields, context))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// object constructor
|
||||||
|
if (!as_generator(
|
||||||
|
indent << scope_tab << scope_tab << "return new " << struct_name << "{\n"
|
||||||
|
).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))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename OutputIterator, typename Context>
|
template <typename OutputIterator, typename Context>
|
||||||
bool generate(OutputIterator sink, attributes::struct_def const& struct_, Context const& context) const
|
bool generate(OutputIterator sink, attributes::struct_def const& struct_, Context const& context) const
|
||||||
{
|
{
|
||||||
|
@ -473,7 +533,10 @@ struct struct_definition_generator
|
||||||
<< *(indent << scope_tab << scope_tab << field_argument_assignment << ";\n")
|
<< *(indent << scope_tab << scope_tab << field_argument_assignment << ";\n")
|
||||||
<< indent << scope_tab << "}\n\n")
|
<< indent << scope_tab << "}\n\n")
|
||||||
.generate(sink, std::make_tuple(struct_.fields, struct_name, struct_.fields, struct_.fields), context))
|
.generate(sink, std::make_tuple(struct_.fields, struct_name, struct_.fields, struct_.fields), context))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!generate_implicit_operator(struct_, sink, context))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string since_line;
|
std::string since_line;
|
||||||
|
@ -546,9 +609,9 @@ struct struct_definition_generator
|
||||||
).generate(sink, attributes::unused, context))
|
).generate(sink, attributes::unused, context))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!as_generator(
|
if (!as_generator(
|
||||||
indent << scope_tab << scope_tab << ";\n"
|
indent << scope_tab << scope_tab << ";\n"
|
||||||
<< indent << scope_tab << "}\n"
|
<< indent << scope_tab << "}\n"
|
||||||
).generate(sink, attributes::unused, context))
|
).generate(sink, attributes::unused, context))
|
||||||
|
|
|
@ -28,6 +28,30 @@
|
||||||
|
|
||||||
namespace eolian_mono {
|
namespace eolian_mono {
|
||||||
|
|
||||||
|
struct field_argument_name_generator
|
||||||
|
{
|
||||||
|
template<typename OutputIterator, typename Context>
|
||||||
|
bool generate(OutputIterator sink, attributes::struct_field_def const& field, Context const& context) const
|
||||||
|
{
|
||||||
|
if (!as_generator(name_helpers::to_field_name(field.name))
|
||||||
|
.generate(sink, attributes::unused, context))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} const field_argument_name {};
|
||||||
|
|
||||||
|
struct field_argument_decl_generator
|
||||||
|
{
|
||||||
|
template<typename OutputIterator, typename Context>
|
||||||
|
bool generate(OutputIterator sink, attributes::struct_field_def const& field, Context const& context) const
|
||||||
|
{
|
||||||
|
if (!as_generator(type << " " << string)
|
||||||
|
.generate(sink, std::make_tuple(field.type, name_helpers::to_field_name(field.name)), context))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} const field_argument_decl {};
|
||||||
|
|
||||||
struct field_argument_default_generator
|
struct field_argument_default_generator
|
||||||
{
|
{
|
||||||
template<typename OutputIterator, typename Context>
|
template<typename OutputIterator, typename Context>
|
||||||
|
@ -69,6 +93,16 @@ struct field_argument_docs_generator
|
||||||
|
|
||||||
namespace efl { namespace eolian { namespace grammar {
|
namespace efl { namespace eolian { namespace grammar {
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct is_eager_generator< ::eolian_mono::field_argument_name_generator> : std::true_type {};
|
||||||
|
template<>
|
||||||
|
struct is_generator< ::eolian_mono::field_argument_name_generator> : std::true_type {};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct is_eager_generator< ::eolian_mono::field_argument_decl_generator> : std::true_type {};
|
||||||
|
template<>
|
||||||
|
struct is_generator< ::eolian_mono::field_argument_decl_generator> : std::true_type {};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct is_eager_generator< ::eolian_mono::field_argument_default_generator> : std::true_type {};
|
struct is_eager_generator< ::eolian_mono::field_argument_default_generator> : std::true_type {};
|
||||||
template<>
|
template<>
|
||||||
|
@ -86,6 +120,12 @@ struct is_generator< ::eolian_mono::field_argument_docs_generator> : std::true_t
|
||||||
|
|
||||||
namespace type_traits {
|
namespace type_traits {
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct attributes_needed< ::eolian_mono::field_argument_name_generator> : std::integral_constant<int, 1> {};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct attributes_needed< ::eolian_mono::field_argument_decl_generator> : std::integral_constant<int, 1> {};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct attributes_needed< ::eolian_mono::field_argument_default_generator> : std::integral_constant<int, 1> {};
|
struct attributes_needed< ::eolian_mono::field_argument_default_generator> : std::integral_constant<int, 1> {};
|
||||||
|
|
||||||
|
|
|
@ -1816,7 +1816,7 @@ template <>
|
||||||
struct is_tuple<attributes::parameter_def> : std::true_type {};
|
struct is_tuple<attributes::parameter_def> : std::true_type {};
|
||||||
template <>
|
template <>
|
||||||
struct is_tuple<attributes::event_def> : std::true_type {};
|
struct is_tuple<attributes::event_def> : std::true_type {};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} } }
|
} } }
|
||||||
|
|
|
@ -421,4 +421,42 @@ internal class TestStructEquality
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class TestStructTuples
|
||||||
|
{
|
||||||
|
private static Eina.Position2D simulate_position_usage(Eina.Position2D p) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void test_same_type_fields_assign_conversion() {
|
||||||
|
Eina.Position2D p = (1, 2);
|
||||||
|
Test.AssertEquals(p.X, 1);
|
||||||
|
Test.AssertEquals(p.Y, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void test_same_type_fields_call_conversion() {
|
||||||
|
var p = simulate_position_usage((1, 2));
|
||||||
|
Test.AssertEquals(p.X, 1);
|
||||||
|
Test.AssertEquals(p.Y, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void test_different_type_fields_assign_conversion() {
|
||||||
|
Efl.Ui.FormatValue v = (1, "Format");
|
||||||
|
Test.AssertEquals(v.Value, 1);
|
||||||
|
Test.AssertEquals(v.Text, "Format");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void test_complex_fields_assign_conversion() {
|
||||||
|
var pos = new Eina.Position2D(1, 2);
|
||||||
|
var action = Efl.Ui.SelectionAction.Unknown;
|
||||||
|
var format = Efl.Ui.SelectionFormat.None;
|
||||||
|
var item = null as Efl.Canvas.Vg.Object;
|
||||||
|
|
||||||
|
Efl.Dnd.DragPos attr = (pos, action, format, item);
|
||||||
|
Test.AssertEquals(attr.Pos, pos);
|
||||||
|
Test.AssertEquals(attr.Action, action);
|
||||||
|
Test.AssertEquals(attr.Format, format);
|
||||||
|
Test.AssertEquals(attr.Item, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue