summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoão Paulo Taylor Ienczak Zanette <joao.tiz@expertisesolutions.com.br>2019-12-12 13:16:22 -0300
committerLauro Moura <lauromoura@expertisesolutions.com.br>2019-12-12 13:16:22 -0300
commite617ff441aa9cc9286846f3a49eca5ae26e85d0a (patch)
tree3f9aba198f038050d3f59d627441aaa3afa53717
parent8a2ccfefe1b27f99e2848a7cf1f25ee7aee74107 (diff)
downloadefl-e617ff441aa9cc9286846f3a49eca5ae26e85d0a.tar.gz
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
-rw-r--r--src/bin/eolian_mono/eolian/mono/struct_definition.hh71
-rw-r--r--src/bin/eolian_mono/eolian/mono/struct_fields.hh40
-rw-r--r--src/lib/eolian_cxx/grammar/klass_def.hpp2
-rw-r--r--src/tests/efl_mono/Structs.cs38
4 files changed, 146 insertions, 5 deletions
diff --git a/src/bin/eolian_mono/eolian/mono/struct_definition.hh b/src/bin/eolian_mono/eolian/mono/struct_definition.hh
index d83e91b591..03085335d1 100644
--- a/src/bin/eolian_mono/eolian/mono/struct_definition.hh
+++ b/src/bin/eolian_mono/eolian/mono/struct_definition.hh
@@ -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))
diff --git a/src/bin/eolian_mono/eolian/mono/struct_fields.hh b/src/bin/eolian_mono/eolian/mono/struct_fields.hh
index b8bb0a231b..76e0f64138 100644
--- a/src/bin/eolian_mono/eolian/mono/struct_fields.hh
+++ b/src/bin/eolian_mono/eolian/mono/struct_fields.hh
@@ -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>
@@ -70,6 +94,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<>
struct is_generator< ::eolian_mono::field_argument_default_generator> : std::true_type {};
@@ -87,6 +121,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> {};
template <>
diff --git a/src/lib/eolian_cxx/grammar/klass_def.hpp b/src/lib/eolian_cxx/grammar/klass_def.hpp
index d6969315e7..ad3b6eecbd 100644
--- a/src/lib/eolian_cxx/grammar/klass_def.hpp
+++ b/src/lib/eolian_cxx/grammar/klass_def.hpp
@@ -1816,7 +1816,7 @@ template <>
struct is_tuple<attributes::parameter_def> : std::true_type {};
template <>
struct is_tuple<attributes::event_def> : std::true_type {};
-
+
}
} } }
diff --git a/src/tests/efl_mono/Structs.cs b/src/tests/efl_mono/Structs.cs
index 60be42eea5..521d39ba35 100644
--- a/src/tests/efl_mono/Structs.cs
+++ b/src/tests/efl_mono/Structs.cs
@@ -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);
+ }
+}
+
}