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)
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 d83e91b..0308533 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
403 403
404struct struct_definition_generator 404struct struct_definition_generator
405{ 405{
406 /**
407 * Generates an implicit operator for packing only if the struct has more
408 * than one attribute. Then operator will receive a tuple with the same of
409 * each attribute's type in the same order they were declared.
410 *
411 * Remarks: due to the MCS compiler's limitations, no operator is generated
412 * for structs with more than 4 fields.
413 */
414 template <typename OutputIterator, typename Context>
415 bool generate_implicit_operator(attributes::struct_def const& struct_
416 , OutputIterator sink
417 , Context const& context) const
418 {
419 if (struct_.fields.size() <= 1 || struct_.fields.size() > 4)
420 return true;
421
422 auto struct_name = binding_struct_name(struct_);
423 auto const& indent = current_indentation(context);
424
425 if (!as_generator(
426 indent << scope_tab << "/// <summary>Packs tuple into " << struct_name << " object.\n"
427 << indent << scope_tab << "///<para>Since EFL 1.24.</para>\n"
428 << indent << scope_tab << "///</summary>\n"
429 ).generate(sink, attributes::unused, context))
430 return false;
431
432 if (!as_generator(
433 indent << scope_tab << "public static implicit operator " << struct_name << "(\n"
434 << indent << scope_tab << scope_tab << "(\n"
435 << ((indent << scope_tab << scope_tab << " " << field_argument_decl) % ",\n") << "\n"
436 << indent << scope_tab << scope_tab << ") tuple)\n"
437 << indent << scope_tab << "{\n"
438 ).generate(sink, struct_.fields, context))
439 return false;
440
441 // object constructor
442 if (!as_generator(
443 indent << scope_tab << scope_tab << "return new " << struct_name << "{\n"
444 ).generate(sink, attributes::unused, context))
445 return false;
446
447 for (const auto& field: struct_.fields)
448 {
449 auto field_name = name_helpers::to_field_name(field.name);
450
451 if (!as_generator(
452 indent << scope_tab << scope_tab << scope_tab << field_name << " = tuple." << field_name << ",\n"
453 ).generate(sink, attributes::unused, context))
454 return false;
455 }
456
457 if (!as_generator(
458 indent << scope_tab << scope_tab << "};\n"
459 << indent << scope_tab << "}\n"
460 ).generate(sink, attributes::unused, context))
461 return false;
462
463 return true;
464 }
465
406 template <typename OutputIterator, typename Context> 466 template <typename OutputIterator, typename Context>
407 bool generate(OutputIterator sink, attributes::struct_def const& struct_, Context const& context) const 467 bool generate(OutputIterator sink, attributes::struct_def const& struct_, Context const& context) const
408 { 468 {
@@ -473,7 +533,10 @@ struct struct_definition_generator
473 << *(indent << scope_tab << scope_tab << field_argument_assignment << ";\n") 533 << *(indent << scope_tab << scope_tab << field_argument_assignment << ";\n")
474 << indent << scope_tab << "}\n\n") 534 << indent << scope_tab << "}\n\n")
475 .generate(sink, std::make_tuple(struct_.fields, struct_name, struct_.fields, struct_.fields), context)) 535 .generate(sink, std::make_tuple(struct_.fields, struct_name, struct_.fields, struct_.fields), context))
476 return false; 536 return false;
537
538 if (!generate_implicit_operator(struct_, sink, context))
539 return false;
477 } 540 }
478 541
479 std::string since_line; 542 std::string since_line;
@@ -546,9 +609,9 @@ struct struct_definition_generator
546 ).generate(sink, attributes::unused, context)) 609 ).generate(sink, attributes::unused, context))
547 return false; 610 return false;
548 } 611 }
549 612
550 613
551 if (!as_generator( 614 if (!as_generator(
552 indent << scope_tab << scope_tab << ";\n" 615 indent << scope_tab << scope_tab << ";\n"
553 << indent << scope_tab << "}\n" 616 << indent << scope_tab << "}\n"
554 ).generate(sink, attributes::unused, context)) 617 ).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 b8bb0a2..76e0f64 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 @@
28 28
29namespace eolian_mono { 29namespace eolian_mono {
30 30
31struct field_argument_name_generator
32{
33 template<typename OutputIterator, typename Context>
34 bool generate(OutputIterator sink, attributes::struct_field_def const& field, Context const& context) const
35 {
36 if (!as_generator(name_helpers::to_field_name(field.name))
37 .generate(sink, attributes::unused, context))
38 return false;
39 return true;
40 }
41} const field_argument_name {};
42
43struct field_argument_decl_generator
44{
45 template<typename OutputIterator, typename Context>
46 bool generate(OutputIterator sink, attributes::struct_field_def const& field, Context const& context) const
47 {
48 if (!as_generator(type << " " << string)
49 .generate(sink, std::make_tuple(field.type, name_helpers::to_field_name(field.name)), context))
50 return false;
51 return true;
52 }
53} const field_argument_decl {};
54
31struct field_argument_default_generator 55struct field_argument_default_generator
32{ 56{
33 template<typename OutputIterator, typename Context> 57 template<typename OutputIterator, typename Context>
@@ -70,6 +94,16 @@ struct field_argument_docs_generator
70namespace efl { namespace eolian { namespace grammar { 94namespace efl { namespace eolian { namespace grammar {
71 95
72template<> 96template<>
97struct is_eager_generator< ::eolian_mono::field_argument_name_generator> : std::true_type {};
98template<>
99struct is_generator< ::eolian_mono::field_argument_name_generator> : std::true_type {};
100
101template<>
102struct is_eager_generator< ::eolian_mono::field_argument_decl_generator> : std::true_type {};
103template<>
104struct is_generator< ::eolian_mono::field_argument_decl_generator> : std::true_type {};
105
106template<>
73struct is_eager_generator< ::eolian_mono::field_argument_default_generator> : std::true_type {}; 107struct is_eager_generator< ::eolian_mono::field_argument_default_generator> : std::true_type {};
74template<> 108template<>
75struct is_generator< ::eolian_mono::field_argument_default_generator> : std::true_type {}; 109struct 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
87namespace type_traits { 121namespace type_traits {
88 122
89template <> 123template <>
124struct attributes_needed< ::eolian_mono::field_argument_name_generator> : std::integral_constant<int, 1> {};
125
126template <>
127struct attributes_needed< ::eolian_mono::field_argument_decl_generator> : std::integral_constant<int, 1> {};
128
129template <>
90struct attributes_needed< ::eolian_mono::field_argument_default_generator> : std::integral_constant<int, 1> {}; 130struct attributes_needed< ::eolian_mono::field_argument_default_generator> : std::integral_constant<int, 1> {};
91 131
92template <> 132template <>
diff --git a/src/lib/eolian_cxx/grammar/klass_def.hpp b/src/lib/eolian_cxx/grammar/klass_def.hpp
index d696931..ad3b6ee 100644
--- a/src/lib/eolian_cxx/grammar/klass_def.hpp
+++ b/src/lib/eolian_cxx/grammar/klass_def.hpp
@@ -1816,7 +1816,7 @@ template <>
1816struct is_tuple<attributes::parameter_def> : std::true_type {}; 1816struct is_tuple<attributes::parameter_def> : std::true_type {};
1817template <> 1817template <>
1818struct is_tuple<attributes::event_def> : std::true_type {}; 1818struct is_tuple<attributes::event_def> : std::true_type {};
1819 1819
1820} 1820}
1821 1821
1822} } } 1822} } }
diff --git a/src/tests/efl_mono/Structs.cs b/src/tests/efl_mono/Structs.cs
index 60be42e..521d39b 100644
--- a/src/tests/efl_mono/Structs.cs
+++ b/src/tests/efl_mono/Structs.cs
@@ -421,4 +421,42 @@ internal class TestStructEquality
421 } 421 }
422} 422}
423 423
424internal class TestStructTuples
425{
426 private static Eina.Position2D simulate_position_usage(Eina.Position2D p) {
427 return p;
428 }
429
430 public static void test_same_type_fields_assign_conversion() {
431 Eina.Position2D p = (1, 2);
432 Test.AssertEquals(p.X, 1);
433 Test.AssertEquals(p.Y, 2);
434 }
435
436 public static void test_same_type_fields_call_conversion() {
437 var p = simulate_position_usage((1, 2));
438 Test.AssertEquals(p.X, 1);
439 Test.AssertEquals(p.Y, 2);
440 }
441
442 public static void test_different_type_fields_assign_conversion() {
443 Efl.Ui.FormatValue v = (1, "Format");
444 Test.AssertEquals(v.Value, 1);
445 Test.AssertEquals(v.Text, "Format");
446 }
447
448 public static void test_complex_fields_assign_conversion() {
449 var pos = new Eina.Position2D(1, 2);
450 var action = Efl.Ui.SelectionAction.Unknown;
451 var format = Efl.Ui.SelectionFormat.None;
452 var item = null as Efl.Canvas.Vg.Object;
453
454 Efl.Dnd.DragPos attr = (pos, action, format, item);
455 Test.AssertEquals(attr.Pos, pos);
456 Test.AssertEquals(attr.Action, action);
457 Test.AssertEquals(attr.Format, format);
458 Test.AssertEquals(attr.Item, item);
459 }
460}
461
424} 462}