summaryrefslogtreecommitdiff
path: root/src/bin/eolian_mono/eolian/mono/struct_definition.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/eolian_mono/eolian/mono/struct_definition.hh')
-rw-r--r--src/bin/eolian_mono/eolian/mono/struct_definition.hh276
1 files changed, 272 insertions, 4 deletions
diff --git a/src/bin/eolian_mono/eolian/mono/struct_definition.hh b/src/bin/eolian_mono/eolian/mono/struct_definition.hh
index 7501449..403778f 100644
--- a/src/bin/eolian_mono/eolian/mono/struct_definition.hh
+++ b/src/bin/eolian_mono/eolian/mono/struct_definition.hh
@@ -1,3 +1,18 @@
1/*
2 * Copyright 2019 by its authors. See AUTHORS.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
1#ifndef EOLIAN_MONO_STRUCT_DEFINITION_HH 16#ifndef EOLIAN_MONO_STRUCT_DEFINITION_HH
2#define EOLIAN_MONO_STRUCT_DEFINITION_HH 17#define EOLIAN_MONO_STRUCT_DEFINITION_HH
3 18
@@ -6,6 +21,7 @@
6#include "grammar/indentation.hpp" 21#include "grammar/indentation.hpp"
7#include "grammar/list.hpp" 22#include "grammar/list.hpp"
8#include "grammar/alternative.hpp" 23#include "grammar/alternative.hpp"
24#include "grammar/attribute_reorder.hpp"
9#include "name_helpers.hh" 25#include "name_helpers.hh"
10#include "helpers.hh" 26#include "helpers.hh"
11#include "type.hh" 27#include "type.hh"
@@ -13,6 +29,7 @@
13#include "documentation.hh" 29#include "documentation.hh"
14#include "struct_fields.hh" 30#include "struct_fields.hh"
15#include "blacklist.hh" 31#include "blacklist.hh"
32#include "culture_info.hh"
16 33
17namespace eolian_mono { 34namespace eolian_mono {
18 35
@@ -276,7 +293,7 @@ struct struct_internal_definition_generator
276 indent << "#pragma warning disable CS1591\n\n" 293 indent << "#pragma warning disable CS1591\n\n"
277 << indent << "/// <summary>Internal wrapper for struct " << string << ".</summary>\n" 294 << indent << "/// <summary>Internal wrapper for struct " << string << ".</summary>\n"
278 << indent << "[StructLayout(LayoutKind.Sequential)]\n" 295 << indent << "[StructLayout(LayoutKind.Sequential)]\n"
279 << indent << "public struct " << string << "\n" 296 << indent << "internal struct " << string << "\n"
280 << indent << "{\n" 297 << indent << "{\n"
281 ) 298 )
282 .generate(sink, std::make_tuple<>(binding_struct_name(struct_), struct_internal_decl_name()), context)) 299 .generate(sink, std::make_tuple<>(binding_struct_name(struct_), struct_internal_decl_name()), context))
@@ -386,6 +403,121 @@ struct struct_internal_definition_generator
386 403
387struct struct_definition_generator 404struct struct_definition_generator
388{ 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
466 template <typename OutputIterator, typename Context>
467 bool generate_deconstruct_method(OutputIterator sink, attributes::struct_def const& struct_, Context const& context) const
468 {
469 auto const& indent = current_indentation(context);
470 auto struct_name = binding_struct_name(struct_);
471
472 if (!as_generator(
473 indent << scope_tab << "/// <summary>Unpacks " << struct_name << " into tuple.\n"
474 << indent << scope_tab << "/// <para>Since EFL 1.24.</para>\n"
475 << indent << scope_tab << "/// </summary>\n"
476 << indent << scope_tab << "public void Deconstruct(\n"
477 ).generate(sink, attributes::unused, context))
478 return false;
479
480 // parameters
481 {
482 auto i = 0u;
483 for (auto const& field : struct_.fields)
484 {
485 auto field_name = name_helpers::to_field_name(field.name);
486
487 auto suffix = i == struct_.fields.size() - 1 ? "\n" : ",\n";
488
489 if (!as_generator(
490 indent << scope_tab << scope_tab << "out " << type << " " << field_name << suffix
491 ).generate(sink, std::make_tuple(field.type), context))
492 return false;
493
494 ++i;
495 }
496 }
497
498 if (!as_generator(
499 indent << scope_tab << ")\n"
500 << indent << scope_tab << "{\n"
501 ).generate(sink, attributes::unused, context))
502 return false;
503
504 // assigments
505 for (auto const& field : struct_.fields)
506 {
507 auto field_name = name_helpers::to_field_name(field.name);
508
509 if (!as_generator(
510 indent << scope_tab << scope_tab << field_name << " = this." << field_name << ";\n"
511 ).generate(sink, attributes::unused, context))
512 return false;
513 }
514
515 // the end
516 return as_generator(
517 indent << scope_tab << "}\n"
518 ).generate(sink, attributes::unused, context);
519 }
520
389 template <typename OutputIterator, typename Context> 521 template <typename OutputIterator, typename Context>
390 bool generate(OutputIterator sink, attributes::struct_def const& struct_, Context const& context) const 522 bool generate(OutputIterator sink, attributes::struct_def const& struct_, Context const& context) const
391 { 523 {
@@ -393,14 +525,16 @@ struct struct_definition_generator
393 auto const& indent = current_indentation(context); 525 auto const& indent = current_indentation(context);
394 if(!as_generator(documentation).generate(sink, struct_, context)) 526 if(!as_generator(documentation).generate(sink, struct_, context))
395 return false; 527 return false;
528 auto struct_managed_name = binding_struct_name(struct_);
396 if(!as_generator 529 if(!as_generator
397 ( 530 (
398 indent << "[StructLayout(LayoutKind.Sequential)]\n" 531 indent << "[StructLayout(LayoutKind.Sequential)]\n"
399 << indent << "[Efl.Eo.BindingEntity]\n" 532 << indent << "[Efl.Eo.BindingEntity]\n"
400 << indent << "public struct " << string << "\n" 533 << "[SuppressMessage(\"Microsoft.Naming\", \"CA1724:TypeNamesShouldNotMatchNamespaces\")]\n"
534 << indent << "public struct " << struct_managed_name << " : IEquatable<" << struct_managed_name << ">\n"
401 << indent << "{\n" 535 << indent << "{\n"
402 ) 536 )
403 .generate(sink, binding_struct_name(struct_), context)) 537 .generate(sink, attributes::unused, context))
404 return false; 538 return false;
405 539
406 // iterate struct fields 540 // iterate struct fields
@@ -454,9 +588,123 @@ struct struct_definition_generator
454 << *(indent << scope_tab << scope_tab << field_argument_assignment << ";\n") 588 << *(indent << scope_tab << scope_tab << field_argument_assignment << ";\n")
455 << indent << scope_tab << "}\n\n") 589 << indent << scope_tab << "}\n\n")
456 .generate(sink, std::make_tuple(struct_.fields, struct_name, struct_.fields, struct_.fields), context)) 590 .generate(sink, std::make_tuple(struct_.fields, struct_name, struct_.fields, struct_.fields), context))
457 return false; 591 return false;
592
593 if (!generate_implicit_operator(struct_, sink, context))
594 return false;
595
596 if (!generate_deconstruct_method(sink, struct_, context))
597 return false;
458 } 598 }
459 599
600 std::string since_line;
601 if (!struct_.documentation.since.empty())
602 if (!as_generator(indent << scope_tab << "/// <para>Since EFL " + struct_.documentation.since + ".</para>\n"
603 ).generate(std::back_inserter(since_line), attributes::unused, context))
604 return false;
605
606 // GetHashCode (needed by the equality comparisons)
607 if (!as_generator(
608 indent << scope_tab << "/// <summary>Get a hash code for this item.\n"
609 << since_line
610 << indent << scope_tab << "/// </summary>\n"
611 << indent << scope_tab << "public override int GetHashCode()\n"
612 << indent << scope_tab << "{\n"
613 ).generate(sink, attributes::unused, context))
614 return false;
615
616 if (struct_.fields.size() != 0 )
617 {
618 // int hash = 17;
619 // hash = 23 * fieldA.GetHashCode();
620 // hash = 23 * fieldB.GetHashCode();
621 // hash = 23 * fieldC.GetHashCode();
622 // return hash
623 if (!as_generator(
624 indent << scope_tab << scope_tab << "int hash = 17;\n"
625 << *(grammar::attribute_reorder<-1, -1>(indent << scope_tab << scope_tab << "hash = hash * 23 + " << name_helpers::struct_field_name << ".GetHashCode(" << culture_info << ");\n"))
626 << indent << scope_tab << scope_tab << "return hash;\n"
627 ).generate(sink, struct_.fields, context))
628 return false;
629 }
630 else
631 {
632 // Just compare the place holder pointers
633 if (!as_generator(
634 "return field.GetHashCode();\n"
635 ).generate(sink, attributes::unused, context))
636 return false;
637 }
638
639 if (!as_generator(
640 indent << scope_tab << "}\n"
641 ).generate(sink, attributes::unused, context))
642 return false;
643
644 // IEquatable<T> Equals
645 if (!as_generator(
646 indent << scope_tab << "/// <summary>Equality comparison.\n"
647 << since_line
648 << indent << scope_tab << "/// </summary>\n"
649 << indent << scope_tab << "public bool Equals(" << struct_managed_name << " other)\n"
650 << indent << scope_tab << "{\n"
651 << indent << scope_tab << scope_tab << "return "
652 ).generate(sink, attributes::unused, context))
653 return false;
654
655 if (struct_.fields.size() != 0 )
656 {
657 if (!as_generator(
658 grammar::attribute_reorder<-1, -1>((name_helpers::struct_field_name << " == other." << name_helpers::struct_field_name)) % " && "
659 ).generate(sink, struct_.fields, context))
660 return false;
661 }
662 else
663 {
664 // Just compare the place holder pointers
665 if (!as_generator(
666 "field.Equals(other.field)"
667 ).generate(sink, attributes::unused, context))
668 return false;
669 }
670
671
672 if (!as_generator(
673 indent << scope_tab << scope_tab << ";\n"
674 << indent << scope_tab << "}\n"
675 ).generate(sink, attributes::unused, context))
676 return false;
677
678 // ValueType.Equals
679 if (!as_generator(
680 indent << scope_tab << "/// <summary>Equality comparison.\n"
681 << since_line
682 << indent << scope_tab << "/// </summary>\n"
683 << indent << scope_tab << "public override bool Equals(object other)\n"
684 << indent << scope_tab << scope_tab << "=> ((other is " << struct_managed_name << ") ? Equals((" << struct_managed_name << ")other) : false);\n"
685 ).generate(sink, attributes::unused, context))
686 return false;
687
688 // Equality operators
689 if (!as_generator(
690 indent << scope_tab << "/// <summary>Equality comparison.\n"
691 << since_line
692 << indent << scope_tab << "/// </summary>\n"
693 << indent << scope_tab << "public static bool operator ==(" << struct_managed_name << " lhs, " << struct_managed_name << " rhs)\n"
694 << indent << scope_tab << scope_tab << "=> lhs.Equals(rhs);"
695 ).generate(sink, attributes::unused, context))
696 return false;
697
698 if (!as_generator(
699 indent << scope_tab << "/// <summary>Equality comparison.\n"
700 << since_line
701 << indent << scope_tab << "/// </summary>\n"
702 << indent << scope_tab << "public static bool operator !=(" << struct_managed_name << " lhs, " << struct_managed_name << " rhs)\n"
703 << indent << scope_tab << scope_tab << "=> !lhs.Equals(rhs);"
704 ).generate(sink, attributes::unused, context))
705 return false;
706
707 // Conversions from/to internal struct and IntPtrs
460 if(!as_generator( 708 if(!as_generator(
461 indent << scope_tab << "/// <summary>Implicit conversion to the managed representation from a native pointer.\n" 709 indent << scope_tab << "/// <summary>Implicit conversion to the managed representation from a native pointer.\n"
462 ).generate(sink, attributes::unused, context)) 710 ).generate(sink, attributes::unused, context))
@@ -478,6 +726,26 @@ struct struct_definition_generator
478 ).generate(sink, attributes::unused, context)) 726 ).generate(sink, attributes::unused, context))
479 return false; 727 return false;
480 728
729 if(!as_generator(
730 indent << scope_tab << "/// <summary>Conversion to the managed representation from a native pointer.\n"
731 ).generate(sink, attributes::unused, context))
732 return false;
733
734 if (!struct_.documentation.since.empty())
735 if (!as_generator(indent << scope_tab << "/// <para>Since EFL " + struct_.documentation.since + ".</para>\n"
736 ).generate(sink, attributes::unused, context))
737 return false;
738
739 if (!as_generator(
740 indent << scope_tab << "/// </summary>\n"
741 << indent << scope_tab << "/// <param name=\"ptr\">Native pointer to be converted.</param>\n"
742 << indent << scope_tab << "public static " << struct_name << " FromIntPtr(IntPtr ptr)\n"
743 << indent << scope_tab << "{\n"
744 << indent << scope_tab << scope_tab << "return ptr;\n"
745 << indent << scope_tab << "}\n\n"
746 ).generate(sink, attributes::unused, context))
747 return false;
748
481 if (!struct_internal_definition.generate(sink, struct_, change_indentation(indent.inc(), context))) 749 if (!struct_internal_definition.generate(sink, struct_, change_indentation(indent.inc(), context)))
482 return false; 750 return false;
483 751