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
|
||||
{
|
||||
/**
|
||||
* 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>
|
||||
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 << "}\n\n")
|
||||
.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;
|
||||
|
@ -546,9 +609,9 @@ struct struct_definition_generator
|
|||
).generate(sink, attributes::unused, context))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (!as_generator(
|
||||
|
||||
|
||||
if (!as_generator(
|
||||
indent << scope_tab << scope_tab << ";\n"
|
||||
<< indent << scope_tab << "}\n"
|
||||
).generate(sink, attributes::unused, context))
|
||||
|
|
|
@ -28,6 +28,30 @@
|
|||
|
||||
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
|
||||
{
|
||||
template<typename OutputIterator, typename Context>
|
||||
|
@ -69,6 +93,16 @@ struct field_argument_docs_generator
|
|||
|
||||
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<>
|
||||
struct is_eager_generator< ::eolian_mono::field_argument_default_generator> : std::true_type {};
|
||||
template<>
|
||||
|
@ -86,6 +120,12 @@ struct is_generator< ::eolian_mono::field_argument_docs_generator> : std::true_t
|
|||
|
||||
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 <>
|
||||
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 {};
|
||||
template <>
|
||||
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