Ver Fonte

Merged in develop (pull request #35)

Release 2.0.0
Bart Hertog há 5 anos atrás
pai
commit
8775a3879c
45 ficheiros alterados com 2683 adições e 1039 exclusões
  1. 1 1
      README.md
  2. 3 0
      build_test.sh
  3. 0 537
      generator/Header_Template.h
  4. 73 292
      generator/protoc-gen-eams.py
  5. 486 0
      generator/support/Field.py
  6. 78 0
      generator/support/Oneof.py
  7. 104 0
      generator/support/ProtoFile.py
  8. 210 0
      generator/support/TypeDefinitions.py
  9. 0 0
      generator/support/__init__.py
  10. 50 0
      generator/templates/FieldBasic_Deserialize.h
  11. 62 0
      generator/templates/FieldBasic_GetSet.h
  12. 33 0
      generator/templates/FieldBasic_Serialize.h
  13. 52 0
      generator/templates/FieldBytes_GetSet.h
  14. 43 0
      generator/templates/FieldEnum_Deserialize.h
  15. 61 0
      generator/templates/FieldEnum_GetSet.h
  16. 35 0
      generator/templates/FieldEnum_Serialize.h
  17. 50 0
      generator/templates/FieldMsg_Deserialize.h
  18. 70 0
      generator/templates/FieldMsg_GetSet.h
  19. 33 0
      generator/templates/FieldMsg_Serialize.h
  20. 90 0
      generator/templates/FieldRepeated_GetSet.h
  21. 33 0
      generator/templates/FieldRepeated_Serialize.h
  22. 52 0
      generator/templates/FieldString_GetSet.h
  23. 69 0
      generator/templates/Header.h
  24. 35 0
      generator/templates/TypeDefEnum.h
  25. 200 0
      generator/templates/TypeDefMsg.h
  26. 106 0
      generator/templates/TypeOneof.h
  27. 12 9
      src/FieldStringBytes.h
  28. 1 1
      src/MessageInterface.cpp
  29. 77 38
      src/RepeatedField.h
  30. 20 2
      src/RepeatedFieldFixedSize.h
  31. 123 107
      src/WireFormatter.h
  32. 37 0
      test/proto/empty_message.proto
  33. 5 0
      test/proto/include_other_files.proto
  34. 9 1
      test/proto/nested_message.proto
  35. 12 0
      test/proto/oneof_fields.proto
  36. 1 1
      test/proto/repeated_fields.proto
  37. 7 1
      test/proto/string_bytes.proto
  38. 41 0
      test/proto/subfolder/file_to_include_from_subfolder.proto
  39. 4 3
      test/test_IncludeOtherFiles.cpp
  40. 59 32
      test/test_NestedMessage.cpp
  41. 24 0
      test/test_RepeatedFieldMessage.cpp
  42. 45 0
      test/test_empty_messages.cpp
  43. 28 0
      test/test_oneof_fields.cpp
  44. 115 0
      test/test_string_bytes.cpp
  45. 34 14
      test_data.py

+ 1 - 1
README.md

@@ -143,7 +143,7 @@ Various examples how to use and integrate Embedded in your project are given on
 
 ## PC Unit Tests
 
-The unit tests for PC are mend to test the logic of Embedded Proto. The test are build upon the GTest and GMock libraries which are include as a submodule in this repository. 
+The unit tests for PC are meant to test the logic of Embedded Proto. The test are build upon the GTest and GMock libraries which are include as a submodule in this repository. 
 
 The tests are build using a small script in the root folder of the project:
 ```bash

+ 3 - 0
build_test.sh

@@ -37,7 +37,10 @@ protoc --plugin=protoc-gen-eams=protoc-gen-eams -I./test/proto --eams_out=./buil
 protoc --plugin=protoc-gen-eams=protoc-gen-eams -I./test/proto --eams_out=./build/EAMS ./test/proto/repeated_fields.proto
 protoc --plugin=protoc-gen-eams=protoc-gen-eams -I./test/proto --eams_out=./build/EAMS ./test/proto/oneof_fields.proto
 protoc --plugin=protoc-gen-eams=protoc-gen-eams -I./test/proto --eams_out=./build/EAMS ./test/proto/include_other_files.proto
+# Delibertly do not manually generate file_to_include.proto and subfolder/file_to_include_from_subfolder.proto 
+# to test the automatic generation of files from including them in include_other_files.proto.
 protoc --plugin=protoc-gen-eams=protoc-gen-eams -I./test/proto --eams_out=./build/EAMS ./test/proto/string_bytes.proto
+protoc --plugin=protoc-gen-eams=protoc-gen-eams -I./test/proto --eams_out=./build/EAMS ./test/proto/empty_message.proto
 
 # For validation and testing generate the same message using python
 mkdir -p ./build/python

+ 0 - 537
generator/Header_Template.h

@@ -1,537 +0,0 @@
-{% macro enum_macro(_enum) %}
-enum {{ _enum.name }}
-{
-  {% for value in _enum.values() %}
-  {{ value.name }} = {{ value.number }}{{ "," if not loop.last }}
-  {% endfor %}
-};
-
-{% endmacro %}
-{# #}
-{# ------------------------------------------------------------------------------------------------------------------ #}
-{# #}
-{% macro oneof_init(_oneof) %}
-void init_{{_oneof.name}}(const id field_id)
-{
-  if(id::NOT_SET != {{_oneof.which_oneof}})
-  {
-    // First delete the old object in the oneof.
-    clear_{{_oneof.name}}();
-  }
-
-  // C++11 unions only support nontrivial members when you explicitly call the placement new statement.
-  switch(field_id)
-  {
-    {% for field in _oneof.fields() %}
-    case id::{{field.variable_id_name}}:
-      {% if field.of_type_message or field.is_repeated_field or field.is_string or field.is_bytes %}
-      new(&{{field.variable_full_name}}) {{field.type}};
-      {{_oneof.which_oneof}} = id::{{field.variable_id_name}};
-      {% endif %}
-      break;
-    {% endfor %}
-    default:
-      break;
-   }
-}
-{% endmacro %}
-{# #}
-{# ------------------------------------------------------------------------------------------------------------------ #}
-{% macro oneof_clear(_oneof) %}
-void clear_{{_oneof.name}}()
-{
-  switch({{_oneof.which_oneof}})
-  {
-    {% for field in _oneof.fields() %}
-    case id::{{field.variable_id_name}}:
-      {% if field.of_type_message or field.is_repeated_field or field.is_string or field.is_bytes%}
-      {{field.variable_full_name}}.~{{field.short_type}}();
-      {% else %}
-      {{field.variable_full_name}}.set(0);
-      {% endif %}
-      break;
-    {% endfor %}
-    default:
-      break;
-  }
-  {{_oneof.which_oneof}} = id::NOT_SET;
-}
-{% endmacro %}
-{# #}
-{# ------------------------------------------------------------------------------------------------------------------ #}
-{# #}
-{% macro field_get_set_macro(_field) %}
-{% if _field.is_string or _field.is_bytes %}
-inline const {{_field.repeated_type}}& {{_field.name}}() const { return {{_field.variable_full_name}}; }
-{% if _field.which_oneof is defined %}
-inline void clear_{{_field.name}}()
-{
-  if(id::{{_field.variable_id_name}} == {{_field.which_oneof}})
-  {
-    {{_field.which_oneof}} = id::NOT_SET;
-    {{_field.variable_full_name}}.~{{_field.short_type}}();
-  }
-}
-inline {{_field.repeated_type}}& mutable_{{_field.name}}()
-{
-  if(id::{{_field.variable_id_name}} != {{_field.which_oneof}})
-  {
-    init_{{_field.oneof_name}}(id::{{_field.variable_id_name}});
-  }
-  return {{_field.variable_full_name}};
-}
-{% else %}
-inline void clear_{{_field.name}}() { {{_field.variable_full_name}}.clear(); }
-inline {{_field.repeated_type}}& mutable_{{_field.name}}() { return {{_field.variable_full_name}}; }
-{% endif %}
-{% if _field.is_string %}
-inline const char* get_{{_field.name}}() const { return {{_field.variable_full_name}}.get_const(); }
-{% else %}{# is bytes #}
-inline const uint8_t* get_{{_field.name}}() const { return {{_field.variable_full_name}}.get_const(); }
-{% endif %}
-{% elif _field.is_repeated_field %}
-inline const {{_field.type}}& {{_field.name}}(uint32_t index) const { return {{_field.variable_full_name}}[index]; }
-{% if _field.which_oneof is defined %}
-inline void clear_{{_field.name}}()
-{
-  if(id::{{_field.variable_id_name}} == {{_field.which_oneof}})
-  {
-    {{_field.which_oneof}} = id::NOT_SET;
-    {{_field.variable_full_name}}.~{{_field.short_type}}();
-  }
-}
-inline void set_{{_field.name}}(uint32_t index, const {{_field.type}}& value)
-{
-  {{_field.which_oneof}} = id::{{_field.variable_id_name}};
-  {{_field.variable_full_name}}.set(index, value);
-}
-inline void set_{{_field.name}}(uint32_t index, const {{_field.type}}&& value)
-{
-  {{_field.which_oneof}} = id::{{_field.variable_id_name}};
-  {{_field.variable_full_name}}.set(index, value);
-}
-inline void add_{{_field.name}}(const {{_field.type}}& value)
-{
-  {{_field.which_oneof}} = id::{{_field.variable_id_name}};
-  {{_field.variable_full_name}}.add(value);
-}
-inline {{_field.repeated_type}}& mutable_{{_field.name}}()
-{
-  {{_field.which_oneof}} = id::{{_field.variable_id_name}};
-  return {{_field.variable_full_name}};
-}
-{% else %}
-inline void clear_{{_field.name}}() { {{_field.variable_full_name}}.clear(); }
-inline void set_{{_field.name}}(uint32_t index, const {{_field.type}}& value) { {{_field.variable_full_name}}.set(index, value); }
-inline void set_{{_field.name}}(uint32_t index, const {{_field.type}}&& value) { {{_field.variable_full_name}}.set(index, value); }
-inline void add_{{_field.name}}(const {{_field.type}}& value) { {{_field.variable_full_name}}.add(value); }
-inline {{_field.repeated_type}}& mutable_{{_field.name}}() { return {{_field.variable_full_name}}; }
-{% endif %}
-inline const {{_field.repeated_type}}& get_{{_field.name}}() const { return {{_field.variable_full_name}}; }
-{% elif _field.of_type_message %}
-inline const {{_field.type}}& {{_field.name}}() const { return {{_field.variable_full_name}}; }
-{% if _field.which_oneof is defined %}
-inline void clear_{{_field.name}}()
-{
-  if(id::{{_field.variable_id_name}} == {{_field.which_oneof}})
-  {
-    {{_field.which_oneof}} = id::NOT_SET;
-    {{_field.variable_full_name}}.~{{_field.short_type}}();
-  }
-}
-inline void set_{{_field.name}}(const {{_field.type}}& value)
-{
-  if(id::{{_field.variable_id_name}} != {{_field.which_oneof}})
-  {
-    init_{{_field.oneof_name}}(id::{{_field.variable_id_name}});
-  }
-  {{_field.variable_full_name}} = value;
-}
-inline void set_{{_field.name}}(const {{_field.type}}&& value)
-{
-  if(id::{{_field.variable_id_name}} != {{_field.which_oneof}})
-  {
-    init_{{_field.oneof_name}}(id::{{_field.variable_id_name}});
-  }
-  {{_field.variable_full_name}} = value;
-}
-inline {{_field.type}}& mutable_{{_field.name}}()
-{
-  if(id::{{_field.variable_id_name}} != {{_field.which_oneof}})
-  {
-    init_{{_field.oneof_name}}(id::{{_field.variable_id_name}});
-  }
-  return {{_field.variable_full_name}};
-}
-{% else %}
-inline void clear_{{_field.name}}() { {{_field.variable_full_name}}.clear(); }
-inline void set_{{_field.name}}(const {{_field.type}}& value) { {{_field.variable_full_name}} = value; }
-inline void set_{{_field.name}}(const {{_field.type}}&& value) { {{_field.variable_full_name}} = value; }
-inline {{_field.type}}& mutable_{{_field.name}}() { return {{_field.variable_full_name}}; }
-{% endif %}
-inline const {{_field.type}}& get_{{_field.name}}() const { return {{_field.variable_full_name}}; }
-{% elif _field.of_type_enum %}
-inline {{_field.type}} {{_field.name}}() const { return {{_field.variable_full_name}}; }
-{% if _field.which_oneof is defined %}
-inline void clear_{{_field.name}}()
-{
-  if(id::{{_field.variable_id_name}} == {{_field.which_oneof}})
-  {
-    {{_field.which_oneof}} = id::NOT_SET;
-    {{_field.variable_full_name}} = static_cast<{{_field.type}}>({{_field.default_value}});
-  }
-}
-inline void set_{{_field.name}}(const {{_field.type}}& value)
-{
-  {{_field.which_oneof}} = id::{{_field.variable_id_name}};
-  {{_field.variable_full_name}} = value;
-}
-inline void set_{{_field.name}}(const {{_field.type}}&& value)
-{
-  {{_field.which_oneof}} = id::{{_field.variable_id_name}};
-  {{_field.variable_full_name}} = value;
-}
-{% else %}
-inline void clear_{{_field.name}}() { {{_field.variable_full_name}} = static_cast<{{_field.type}}>({{_field.default_value}}); }
-inline void set_{{_field.name}}(const {{_field.type}}& value) { {{_field.variable_full_name}} = value; }
-inline void set_{{_field.name}}(const {{_field.type}}&& value) { {{_field.variable_full_name}} = value; }
-{% endif %}    inline {{_field.type}} get_{{_field.name}}() const { return {{_field.variable_full_name}}; }
-{% else %}
-inline {{_field.type}}::FIELD_TYPE {{_field.name}}() const { return {{_field.variable_full_name}}.get(); }
-{% if _field.which_oneof is defined %}
-inline void clear_{{_field.name}}()
-{
-  if(id::{{_field.variable_id_name}} == {{_field.which_oneof}})
-  {
-    {{_field.which_oneof}} = id::NOT_SET;
-    {{_field.variable_full_name}}.set({{_field.default_value}});
-  }
-}
-inline void set_{{_field.name}}(const {{_field.type}}::FIELD_TYPE& value)
-{
-  {{_field.which_oneof}} = id::{{_field.variable_id_name}};
-  {{_field.variable_full_name}}.set(value);
-}
-inline void set_{{_field.name}}(const {{_field.type}}::FIELD_TYPE&& value)
-{
-  {{_field.which_oneof}} = id::{{_field.variable_id_name}};
-  {{_field.variable_full_name}}.set(value);
-}
-{% else %}
-inline void clear_{{_field.name}}() { {{_field.variable_full_name}}.set({{_field.default_value}}); }
-inline void set_{{_field.name}}(const {{_field.type}}::FIELD_TYPE& value) { {{_field.variable_full_name}}.set(value); }
-inline void set_{{_field.name}}(const {{_field.type}}::FIELD_TYPE&& value) { {{_field.variable_full_name}}.set(value); }
-{% endif %}
-inline {{_field.type}}::FIELD_TYPE get_{{_field.name}}() const { return {{_field.variable_full_name}}.get(); }
-{% endif %}
-{% endmacro %}
-{# #}
-{# ------------------------------------------------------------------------------------------------------------------ #}
-{# #}
-{% macro field_serialize_macro(_field) %}
-{% if _field.is_repeated_field or _field.is_string or _field.is_bytes %}
-if(::EmbeddedProto::Error::NO_ERRORS == return_value)
-{
-  return_value = {{_field.variable_full_name}}.serialize_with_id(static_cast<uint32_t>(id::{{_field.variable_id_name}}), buffer);
-}
-{% elif _field.of_type_message %}
-if(::EmbeddedProto::Error::NO_ERRORS == return_value)
-{
-  return_value = {{_field.variable_full_name}}.serialize_with_id(static_cast<uint32_t>(id::{{_field.variable_id_name}}), buffer);
-}
-{% elif _field.of_type_enum %}
-if(({{_field.default_value}} != {{_field.variable_full_name}}) && (::EmbeddedProto::Error::NO_ERRORS == return_value))
-{
-  EmbeddedProto::uint32 value;
-  value.set(static_cast<uint32_t>({{_field.variable_full_name}}));
-  return_value = value.serialize_with_id(static_cast<uint32_t>(id::{{_field.variable_id_name}}), buffer);
-}
-{% else %}
-if(({{_field.default_value}} != {{_field.variable_full_name}}.get()) && (::EmbeddedProto::Error::NO_ERRORS == return_value))
-{
-  return_value = {{_field.variable_full_name}}.serialize_with_id(static_cast<uint32_t>(id::{{_field.variable_id_name}}), buffer);
-} {% endif %} {% endmacro %}
-{# #}
-{# ------------------------------------------------------------------------------------------------------------------ #}
-{# #}
-{% macro field_deserialize_macro(_field) %}
-{% if _field.is_repeated_field %}
-if(::EmbeddedProto::WireFormatter::WireType::LENGTH_DELIMITED == wire_type)
-{
-  return_value = {{_field.variable_full_name}}.deserialize(buffer);
-}
-{% else %}
-if(::EmbeddedProto::WireFormatter::WireType::{{_field.wire_type}} == wire_type)
-{
-  {% if _field.of_type_message %}
-  uint32_t size;
-  return_value = ::EmbeddedProto::WireFormatter::DeserializeVarint(buffer, size);
-  ::EmbeddedProto::ReadBufferSection bufferSection(buffer, size);
-  if(::EmbeddedProto::Error::NO_ERRORS == return_value)
-  {
-    return_value = mutable_{{_field.name}}().deserialize(bufferSection);
-  }
-  {% elif _field.is_string or _field.is_bytes %}
-  return_value = mutable_{{_field.name}}().deserialize(buffer);
-  {% elif _field.of_type_enum %}
-  uint32_t value;
-  return_value = ::EmbeddedProto::WireFormatter::DeserializeVarint(buffer, value);
-  if(::EmbeddedProto::Error::NO_ERRORS == return_value)
-  {
-    set_{{_field.name}}(static_cast<{{_field.type}}>(value));
-  }
-  {% else %}
-  return_value = {{_field.variable_full_name}}.deserialize(buffer);
-  {% endif %}
-  {% if _field.which_oneof is defined %}
-  if(::EmbeddedProto::Error::NO_ERRORS == return_value)
-  {
-    {{_field.which_oneof}} = id::{{_field.variable_id_name}};
-  }
-  {% endif %}
-}
-{% endif %}
-else
-{
-  // Wire type does not match field.
-  return_value = ::EmbeddedProto::Error::INVALID_WIRETYPE;
-} {% endmacro %}
-{# #}
-{# ------------------------------------------------------------------------------------------------------------------ #}
-{# #}
-{% macro msg_macro(msg) %}
-{% if msg.templates is defined %}
-{% for template in msg.templates %}
-{{"template<" if loop.first}}{{template['type']}} {{template['name']}}{{", " if not loop.last}}{{">" if loop.last}}
-{% endfor %}
-{% endif %}
-class {{ msg.name }} final: public ::EmbeddedProto::MessageInterface
-{
-  public:
-    {{ msg.name }}() :
-    {% for field in msg.fields() %}
-        {% if field.of_type_enum %}
-        {{field.variable_full_name}}({{field.default_value}}){{"," if not loop.last}}
-        {% else %}
-        {{field.variable_full_name}}(){{"," if not loop.last}}{{"," if loop.last and msg.has_oneofs}}
-        {% endif %}
-    {% endfor %}
-    {% for oneof in msg.oneofs() %}
-        {{oneof.which_oneof}}(id::NOT_SET){{"," if not loop.last}}
-    {% endfor %}
-    {
-
-    };
-    ~{{ msg.name }}() override = default;
-
-    {% for enum in msg.nested_enums() %}
-    {{ enum_macro(enum) }}
-
-    {% endfor %}
-    enum class id
-    {
-      NOT_SET = 0,
-      {% for id_set in msg.field_ids %}
-      {{id_set[1]}} = {{id_set[0]}}{{ "," if not loop.last }}
-      {% endfor %}
-    };
-
-    {% for field in msg.fields() %}
-    {{ field_get_set_macro(field)|indent(4) }}
-    {% endfor %}
-    {% for oneof in msg.oneofs() %}
-    id get_which_{{oneof.name}}() const { return {{oneof.which_oneof}}; }
-
-    {% for field in oneof.fields() %}
-    {{ field_get_set_macro(field)|indent(4) }}
-    {% endfor %}
-    {% endfor %}
-    ::EmbeddedProto::Error serialize(::EmbeddedProto::WriteBufferInterface& buffer) const final
-    {
-      ::EmbeddedProto::Error return_value = ::EmbeddedProto::Error::NO_ERRORS;
-
-      {% for field in msg.fields() %}
-      {{ field_serialize_macro(field)|indent(6) }}
-
-      {% endfor %}
-      {% for oneof in msg.oneofs() %}
-      switch({{oneof.which_oneof}})
-      {
-        {% for field in oneof.fields() %}
-        case id::{{field.variable_id_name}}:
-          {{ field_serialize_macro(field)|indent(12) }}
-          break;
-
-        {% endfor %}
-        default:
-          break;
-      }
-
-      {% endfor %}
-      return return_value;
-    };
-
-    ::EmbeddedProto::Error deserialize(::EmbeddedProto::ReadBufferInterface& buffer) final
-    {
-      ::EmbeddedProto::Error return_value = ::EmbeddedProto::Error::NO_ERRORS;
-      ::EmbeddedProto::WireFormatter::WireType wire_type;
-      uint32_t id_number = 0;
-
-      ::EmbeddedProto::Error tag_value = ::EmbeddedProto::WireFormatter::DeserializeTag(buffer, wire_type, id_number);
-      while((::EmbeddedProto::Error::NO_ERRORS == return_value) && (::EmbeddedProto::Error::NO_ERRORS == tag_value))
-      {
-        switch(id_number)
-        {
-          {% for field in msg.fields() %}
-          case static_cast<uint32_t>(id::{{field.variable_id_name}}):
-          {
-            {{ field_deserialize_macro(field)|indent(12) }}
-            break;
-          }
-
-          {% endfor %}
-          {% for oneof in msg.oneofs() %}
-          {% for field in oneof.fields() %}
-          case static_cast<uint32_t>(id::{{field.variable_id_name}}):
-          {
-            {{ field_deserialize_macro(field)|indent(12) }}
-            break;
-          }
-
-          {% endfor %}
-          {% endfor %}
-          default:
-            break;
-        }
-        
-        if(::EmbeddedProto::Error::NO_ERRORS == return_value)
-        {
-            // Read the next tag.
-            tag_value = ::EmbeddedProto::WireFormatter::DeserializeTag(buffer, wire_type, id_number);
-        }
-      }
-
-      // When an error was detect while reading the tag but no other errors where found, set it in the return value.
-      if((::EmbeddedProto::Error::NO_ERRORS == return_value)
-         && (::EmbeddedProto::Error::NO_ERRORS != tag_value)
-         && (::EmbeddedProto::Error::END_OF_BUFFER != tag_value)) // The end of the buffer is not an array in this case.
-      {
-        return_value = tag_value;
-      }
-
-      return return_value;
-    };
-
-    void clear() final
-    {
-      {% for field in msg.fields() %}
-      clear_{{field.name}}();
-      {% endfor %}
-      {% for oneof in msg.oneofs() %}
-      clear_{{oneof.name}}();
-      {% endfor %}
-    }
-
-  private:
-
-    {% for field in msg.fields() %}
-    {% if field.is_repeated_field or field.is_string or field.is_bytes %}
-    {{field.repeated_type}} {{field.variable_name}};
-    {% else %}
-    {{field.type}} {{field.variable_name}};
-    {% endif %}
-    {% endfor %}
-
-    {% for oneof in msg.oneofs() %}
-    id {{oneof.which_oneof}};
-    union {{oneof.name}}
-    {
-      {{oneof.name}}() {}
-      ~{{oneof.name}}() {}
-      {% for field in oneof.fields() %}
-      {% if field.is_repeated_field or field.is_string or field.is_bytes %}
-      {{field.repeated_type}} {{field.variable_name}};
-      {% else %}
-      {{field.type}} {{field.variable_name}};
-      {% endif %}
-      {% endfor %}
-    };
-    {{oneof.name}} {{oneof.name}}_;
-
-    {{ oneof_init(oneof)|indent(4) }}
-    {{ oneof_clear(oneof)|indent(4) }}
-    {% endfor %}
-};
-{% endmacro %}
-{# #}
-{# ------------------------------------------------------------------------------------------------------------------ #}
-{# #}
-/*
- *  Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
- *
- *  This file is part of Embedded Proto.
- *
- *  Embedded Proto is open source software: you can redistribute it and/or 
- *  modify it under the terms of the GNU General Public License as published 
- *  by the Free Software Foundation, version 3 of the license.
- *
- *  Embedded Proto  is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
- *
- *  For commercial and closed source application please visit:
- *  <https://EmbeddedProto.com/license/>.
- *
- *  Embedded AMS B.V.
- *  Info:
- *    info at EmbeddedProto dot com
- *
- *  Postal address:
- *    Johan Huizingalaan 763a
- *    1066 VH, Amsterdam
- *    the Netherlands
- */
-
-// This file is generated. Please do not edit!
-#ifndef _{{filename.upper()}}_H_
-#define _{{filename.upper()}}_H_
-
-#include <cstdint>
-{% if messages %}
-#include <MessageInterface.h>
-#include <WireFormatter.h>
-#include <Fields.h>
-#include <MessageSizeCalculator.h>
-#include <ReadBufferSection.h>
-#include <RepeatedFieldFixedSize.h>
-#include <FieldStringBytes.h>
-#include <Errors.h>
-{% endif %}
-{% if dependencies %}
-
-// Include external proto definitions
-{% for dependency in dependencies %}
-#include <{{dependency}}>
-{% endfor %}
-{% endif %}
-{% if namespace %}
-
-namespace {{ namespace }}
-{
-{% endif %}
-
-{% for enum in enums %}
-{{ enum_macro(enum) }}
-{% endfor %}
-{% for msg in messages %}
-{{ msg_macro(msg) }}
-{% endfor %}
-{% if namespace %}
-} // End of namespace {{ namespace }}
-{% endif %}
-#endif // _{{filename.upper()}}_H_
-

+ 73 - 292
generator/protoc-gen-eams.py

@@ -3,8 +3,8 @@
 #
 # This file is part of Embedded Proto.
 #
-# Embedded Proto is open source software: you can redistribute it and/or 
-# modify it under the terms of the GNU General Public License as published 
+# Embedded Proto is open source software: you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as published
 # by the Free Software Foundation, version 3 of the license.
 #
 # Embedded Proto  is distributed in the hope that it will be useful,
@@ -31,305 +31,58 @@
 import io
 import sys
 import os
-import jinja2
-from copy import deepcopy
-
+from support.ProtoFile import ProtoFile
 from google.protobuf.compiler import plugin_pb2 as plugin
-from google.protobuf.descriptor_pb2 import DescriptorProto, FieldDescriptorProto, EnumDescriptorProto
-
-# -----------------------------------------------------------------------------
-
-
-class EnumTemplateParameters:
-    def __init__(self, enum_proto):
-        self.name = enum_proto.name
-        self.enum_proto = enum_proto
-
-    def values(self):
-        for value in self.enum_proto.value:
-            yield value
-
-
-def generate_enums(enums):
-    for enum in enums:
-        yield EnumTemplateParameters(enum)
-
-# -----------------------------------------------------------------------------
-
-
-class FieldTemplateParameters:
-    type_to_default_value = {FieldDescriptorProto.TYPE_DOUBLE:   "0.0",
-                             FieldDescriptorProto.TYPE_FLOAT:    "0.0",
-                             FieldDescriptorProto.TYPE_INT64:    "0",
-                             FieldDescriptorProto.TYPE_UINT64:   "0U",
-                             FieldDescriptorProto.TYPE_INT32:    "0",
-                             FieldDescriptorProto.TYPE_FIXED64:  "0U",
-                             FieldDescriptorProto.TYPE_FIXED32:  "0U",
-                             FieldDescriptorProto.TYPE_BOOL:     "false",
-                             FieldDescriptorProto.TYPE_STRING:   "''",
-                             FieldDescriptorProto.TYPE_MESSAGE:  "",
-                             FieldDescriptorProto.TYPE_BYTES:    "0U",
-                             FieldDescriptorProto.TYPE_UINT32:   "0U",
-                             FieldDescriptorProto.TYPE_ENUM:     "0",
-                             FieldDescriptorProto.TYPE_SFIXED32: "0",
-                             FieldDescriptorProto.TYPE_SFIXED64: "0",
-                             FieldDescriptorProto.TYPE_SINT32:   "0",
-                             FieldDescriptorProto.TYPE_SINT64:   "0"}
-
-    type_to_cpp_type = {FieldDescriptorProto.TYPE_DOUBLE:   "EmbeddedProto::doublefixed",
-                        FieldDescriptorProto.TYPE_FLOAT:    "EmbeddedProto::floatfixed",
-                        FieldDescriptorProto.TYPE_INT64:    "EmbeddedProto::int64",
-                        FieldDescriptorProto.TYPE_UINT64:   "EmbeddedProto::uint64",
-                        FieldDescriptorProto.TYPE_INT32:    "EmbeddedProto::int32",
-                        FieldDescriptorProto.TYPE_FIXED64:  "EmbeddedProto::fixed64",
-                        FieldDescriptorProto.TYPE_FIXED32:  "EmbeddedProto::fixed32",
-                        FieldDescriptorProto.TYPE_BOOL:     "EmbeddedProto::boolean",
-                        FieldDescriptorProto.TYPE_STRING:   "char",
-                        FieldDescriptorProto.TYPE_BYTES:    "uint8_t",
-                        FieldDescriptorProto.TYPE_UINT32:   "EmbeddedProto::uint32",
-                        FieldDescriptorProto.TYPE_SFIXED32: "EmbeddedProto::sfixed32",
-                        FieldDescriptorProto.TYPE_SFIXED64: "EmbeddedProto::sfixed64",
-                        FieldDescriptorProto.TYPE_SINT32:   "EmbeddedProto::sint32",
-                        FieldDescriptorProto.TYPE_SINT64:   "EmbeddedProto::sint64"}
-
-    type_to_wire_type = {FieldDescriptorProto.TYPE_INT32:    "VARINT",
-                         FieldDescriptorProto.TYPE_INT64:    "VARINT",
-                         FieldDescriptorProto.TYPE_UINT32:   "VARINT",
-                         FieldDescriptorProto.TYPE_UINT64:   "VARINT",
-                         FieldDescriptorProto.TYPE_SINT32:   "VARINT",
-                         FieldDescriptorProto.TYPE_SINT64:   "VARINT",
-                         FieldDescriptorProto.TYPE_BOOL:     "VARINT",
-                         FieldDescriptorProto.TYPE_ENUM:     "VARINT",
-                         FieldDescriptorProto.TYPE_FIXED64:  "FIXED64",
-                         FieldDescriptorProto.TYPE_SFIXED64: "FIXED64",
-                         FieldDescriptorProto.TYPE_DOUBLE:   "FIXED64",
-                         FieldDescriptorProto.TYPE_STRING:   "LENGTH_DELIMITED",
-                         FieldDescriptorProto.TYPE_BYTES:    "LENGTH_DELIMITED",
-                         FieldDescriptorProto.TYPE_MESSAGE:  "LENGTH_DELIMITED",
-                         FieldDescriptorProto.TYPE_FIXED32:  "FIXED32",
-                         FieldDescriptorProto.TYPE_FLOAT:    "FIXED32",
-                         FieldDescriptorProto.TYPE_SFIXED32: "FIXED32"}
-
-    def __init__(self, field_proto, oneof=None):
-        self.name = field_proto.name
-        self.variable_name = self.name + "_"
-        self.variable_id_name = self.name.upper()
-        self.variable_id = field_proto.number
-
-        if oneof:
-            # When set this field is part of a oneof.
-            self.oneof_name = oneof
-            self.which_oneof = "which_" + oneof + "_"
-            self.variable_full_name = oneof + "_." + self.variable_name
-        else:
-            self.variable_full_name = self.variable_name
-
-        self.of_type_message = FieldDescriptorProto.TYPE_MESSAGE == field_proto.type
-        self.wire_type = self.type_to_wire_type[field_proto.type]
-
-        self.of_type_enum = FieldDescriptorProto.TYPE_ENUM == field_proto.type
-        self.is_repeated_field = FieldDescriptorProto.LABEL_REPEATED == field_proto.label
-        self.is_string = FieldDescriptorProto.TYPE_STRING == field_proto.type
-        self.is_bytes = FieldDescriptorProto.TYPE_BYTES == field_proto.type
-
-        if FieldDescriptorProto.TYPE_MESSAGE == field_proto.type or self.of_type_enum:
-            self.type = field_proto.type_name if "." != field_proto.type_name[0] else field_proto.type_name[1:]
-            self.type = self.type.replace(".", "::")
-            # Store only the type without namespace or class scopes
-            self.short_type = self.type.split("::")[-1]
-        elif self.is_string:
-            self.type = "::EmbeddedProto::FieldString"
-            self.short_type = "FieldString"
-        elif self.is_bytes:
-            self.type = "::EmbeddedProto::FieldBytes"
-            self.short_type = "FieldBytes"
-        else:
-            self.type = self.type_to_cpp_type[field_proto.type]
-
-        self.default_value = None
-        self.repeated_type = None
-        self.templates = []
-
-        self.field_proto = field_proto
-
-    def update_templates(self, messages):
-        if self.of_type_message:
-            for msg in messages:
-                if msg.name == self.type:
-                    msg_templates = deepcopy(msg.templates)
-                    for tmpl in msg_templates:
-                        tmpl["name"] = self.variable_name + tmpl["name"]
-                    self.templates.extend(msg_templates)
-
-                    if self.templates:
-                        self.type += "<"
-                        for tmpl in self.templates[:-1]:
-                            self.type += tmpl["name"] + ", "
-                        self.type += self.templates[-1]["name"] + ">"
-
-                    break
-
-        if self.of_type_enum:
-            self.default_value = "static_cast<" + self.type + ">(0)"
-        else:
-            self.default_value = self.type_to_default_value[self.field_proto.type]
-
-        if self.is_repeated_field:
-            self.repeated_type = "::EmbeddedProto::RepeatedFieldFixedSize<" + self.type + ", " + self.variable_name \
-                                 + "LENGTH>"
-
-        if self. is_string or self.is_bytes:
-            self.repeated_type = self.type + "<" + self.variable_name + "LENGTH>"
-            self.type = self.repeated_type
-
-        if self.is_repeated_field or self.is_string or self.is_bytes:
-            self.templates.append({"type": "uint32_t", "name": self.variable_name + "LENGTH"})
-
-
-# -----------------------------------------------------------------------------
-
-
-class OneofTemplateParameters:
-    def __init__(self, name, index, msg_proto):
-        self.name = name
-        self.which_oneof = "which_" + name + "_"
-        self.index = index
-        self.msg_proto = msg_proto
-
-        self.fields_array = []
-        # Loop over all the fields in this oneof
-        for f in self.msg_proto.field:
-            if f.HasField('oneof_index') and self.index == f.oneof_index:
-                self.fields_array.append(FieldTemplateParameters(f, self.name))
-
-    def fields(self):
-        for f in self.fields_array:
-            yield f
-
-    def update_templates(self, messages):
-        for f in self.fields_array:
-            f.update_templates(messages)
-
-# -----------------------------------------------------------------------------
-
-
-class MessageTemplateParameters:
-    def __init__(self, msg_proto):
-        self.name = msg_proto.name
-        self.msg_proto = msg_proto
-        self.has_fields = len(self.msg_proto.field) > 0
-        self.has_oneofs = len(self.msg_proto.oneof_decl) > 0
-
-        self.fields_array = []
-        # Loop over only the normal fields in this message.
-        for f in self.msg_proto.field:
-            if not f.HasField('oneof_index'):
-                self.fields_array.append(FieldTemplateParameters(f))
-
-        self.oneof_fields = []
-        # Loop over all the oneofs in this message.
-        for index, oneof in enumerate(self.msg_proto.oneof_decl):
-            self.oneof_fields.append(OneofTemplateParameters(oneof.name, index, self.msg_proto))
-
-        self.templates = []
-        self.field_ids = []
-
-        for field in self.fields_array:
-            self.field_ids.append((field.variable_id, field.variable_id_name))
-
-        for oneof in self.oneof_fields:
-            for field in oneof.fields():
-                self.field_ids.append((field.variable_id, field.variable_id_name))
-
-        # Sort the field id's such they will appear in order in the id enum.
-        self.field_ids.sort()
-
-    def fields(self):
-        for f in self.fields_array:
-            yield f
-
-    def oneofs(self):
-        for o in self.oneof_fields:
-            yield o
-
-    def nested_enums(self):
-        # Yield all the enumerations defined in the scope of this message.
-        for enum in self.msg_proto.enum_type:
-            yield EnumTemplateParameters(enum)
-
-    def update_templates(self, messages):
-        for field in self.fields_array:
-            field.update_templates(messages)
-
-            self.templates.extend(field.templates)
-
-        for oneof in self.oneof_fields:
-            for field in oneof.fields():
-                field.update_templates(messages)
+import jinja2
 
-                self.templates.extend(field.templates)
 
 # -----------------------------------------------------------------------------
 
 
 def generate_code(request, respones):
-    # Based upon the request from protoc generate
-
-    filepath = os.path.dirname(os.path.abspath(__file__))
+    # Create definitions for al proto files in the request.
+    file_definitions = [ProtoFile(proto_file) for proto_file in request.proto_file]
+
+    # Obtain all definitions made in all the files to properly link definitions with fields using them. This to properly
+    # create template parameters.
+    all_types_definitions = {"enums": [], "messages": []}
+    for fd in file_definitions:
+        nt = fd.get_all_nested_types()
+        all_types_definitions["enums"].extend(nt["enums"])
+        all_types_definitions["messages"].extend(nt["messages"])
+
+    # Match all fields with their respective type definition.
+    for fd in file_definitions:
+        fd.match_fields_with_definitions(all_types_definitions)
+
+    # Add template parameters to the fields that need them.
+    all_parameters_registered = True
+    for _ in range(3):
+        for fd in file_definitions:
+            all_parameters_registered = fd.register_template_parameters() and all_parameters_registered
+        if all_parameters_registered:
+            break
+
+    if not all_parameters_registered:
+        raise Exception("Messages with repeated, string or byte fields use template parameters to define their length."
+                        "For some reason it was not to add all required template parameters.")
+
+    curr_location = os.path.dirname(os.path.abspath(__file__))
+    filepath = os.path.join(curr_location, "templates")
     template_loader = jinja2.FileSystemLoader(searchpath=filepath)
     template_env = jinja2.Environment(loader=template_loader, trim_blocks=True, lstrip_blocks=True)
-    template_file = "Header_Template.h"
-    template = template_env.get_template(template_file)
 
-    messages_array = []
-    number_of_processed_msg = 0
-
-    # Loop over all proto files in the request
-    for proto_file in request.proto_file:
-
-        if "proto2" == proto_file.syntax:
-            raise Exception(proto_file.name + ": Sorry, proto2 is not supported, please use proto3.")
-
-        for msg_type in proto_file.message_type:
-            msg = MessageTemplateParameters(msg_type)
-            msg.update_templates(messages_array)
-            messages_array.append(msg)
-
-        enums_generator = generate_enums(proto_file.enum_type)
-
-        filename_str = os.path.splitext(proto_file.name)[0]
-
-        imported_dependencies = []
-        if proto_file.dependency:
-            imported_dependencies = [os.path.splitext(dependency)[0] + ".h" for dependency in proto_file.dependency]
-
-        namespace_name = ""
-        if proto_file.package:
-            namespace_name = proto_file.package.replace(".", "::")
-
-        try:
-            file_str = template.render(filename=filename_str, namespace=namespace_name,
-                                       messages=messages_array[number_of_processed_msg:],
-                                       enums=enums_generator, dependencies=imported_dependencies)
-
-        except jinja2.TemplateError as e:
-            print("TemplateError exception: " + str(e))
-        except jinja2.UndefinedError as e:
-            print("UndefinedError exception: " + str(e))
-        except jinja2.TemplateSyntaxError as e:
-            print("TemplateSyntaxError exception: " + str(e))
-        except jinja2.TemplateRuntimeError as e:
-            print("TemplateRuntimeError exception: " + str(e))
-        except jinja2.TemplateAssertionError as e:
-            print("TemplateAssertionError exception: " + str(e))
-        except Exception as e:
-            print("Template renderer exception: " + str(e))
-        else:
-            number_of_processed_msg = len(messages_array)
+    for fd in file_definitions:
+        file_str = fd.render(template_env)
+        if file_str:
             f = respones.file.add()
-            f.name = filename_str + ".h"
+            f.name = fd.filename_with_folder + ".h"
             f.content = file_str
+        else:
+            break
+
 
+# -----------------------------------------------------------------------------
 
 def main_plugin():
     # The main function when running the scrip as a protoc plugin. It will read in the protoc data from the stdin and
@@ -348,7 +101,21 @@ def main_plugin():
     response = plugin.CodeGeneratorResponse()
 
     # Generate code
-    generate_code(request, response)
+    try:
+        generate_code(request, response)
+    except jinja2.UndefinedError as e:
+        response.error = "Embedded Proto error - Template Undefined Error exception: " + str(e)
+    except jinja2.TemplateRuntimeError as e:
+        response.error = "Embedded Proto error - Template Runtime Error exception: " + str(e)
+    except jinja2.TemplateAssertionError as e:
+        response.error = "Embedded Proto error - TemplateAssertionError exception: " + str(e)
+    except jinja2.TemplateSyntaxError as e:
+        response.error = "Embedded Proto error - TemplateSyntaxError exception: " + str(e)
+    except jinja2.TemplateError as e:
+        response.error = "Embedded Proto error - TemplateError exception: " + str(e)
+    except Exception as e:
+        response.error = "Embedded Proto error - " + str(e)
+
 
     # Serialize response message
     output = response.SerializeToString()
@@ -357,6 +124,8 @@ def main_plugin():
     io.open(sys.stdout.fileno(), "wb").write(output)
 
 
+# -----------------------------------------------------------------------------
+
 def main_cli():
     # The main function when running from the command line and debugging.  Instead of receiving data from protoc this
     # will read in a binary file stored the previous time main_plugin() is ran.
@@ -369,8 +138,22 @@ def main_cli():
         response = plugin.CodeGeneratorResponse()
 
         # Generate code
-        generate_code(request, response)
+        try:
+            generate_code(request, response)
+        except jinja2.UndefinedError as e:
+            response.error = "Embedded Proto error - Template Undefined Error exception: " + str(e)
+        except jinja2.TemplateRuntimeError as e:
+            response.error = "Embedded Proto error - Template Runtime Error exception: " + str(e)
+        except jinja2.TemplateAssertionError as e:
+            response.error = "Embedded Proto error - TemplateAssertionError exception: " + str(e)
+        except jinja2.TemplateSyntaxError as e:
+            response.error = "Embedded Proto error - TemplateSyntaxError exception: " + str(e)
+        except jinja2.TemplateError as e:
+            response.error = "Embedded Proto error - TemplateError exception: " + str(e)
+        except Exception as e:
+            response.error = "Embedded Proto error - " + str(e)
 
+        # For debugging purposes print the result to the console.
         for response_file in response.file:
             print(response_file.name)
             print(response_file.content)
@@ -384,5 +167,3 @@ if __name__ == '__main__':
         main_plugin()
     else:
         main_cli()
-
-# protoc --plugin=protoc-gen-eams=protoc-gen-eams --eams_out=./build ./test/proto/state.proto

+ 486 - 0
generator/support/Field.py

@@ -0,0 +1,486 @@
+#
+# Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+#
+# This file is part of Embedded Proto.
+#
+# Embedded Proto is open source software: you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as published
+# by the Free Software Foundation, version 3 of the license.
+#
+# Embedded Proto  is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+#
+# For commercial and closed source application please visit:
+# <https://EmbeddedProto.com/license/>.
+#
+# Embedded AMS B.V.
+# Info:
+#   info at EmbeddedProto dot com
+#
+# Postal address:
+#   Johan Huizingalaan 763a
+#   1066 VH, Amsterdam
+#   the Netherlands
+#
+
+from google.protobuf.descriptor_pb2 import FieldDescriptorProto
+import copy
+
+
+# This class is the base class for any kind of field used in protobuf messages.
+class Field:
+    def __init__(self, proto_descriptor, parent_msg, template_filename, oneof=None):
+        # A reference to the FieldDescriptorProto object which defines this field.
+        self.descriptor = proto_descriptor
+
+        # A reference to the parent message in which this field is defined.
+        self.parent = parent_msg
+
+        # If this field is part of a oneof this is the reference to it.
+        self.oneof = oneof
+
+        self.name = self.descriptor.name
+        self.variable_name = self.name + "_"
+        self.variable_id_name = self.name.upper()
+        self.variable_id = self.descriptor.number
+        self.template_file = template_filename
+        
+        self.of_type_enum = FieldDescriptorProto.TYPE_ENUM == proto_descriptor.type
+
+
+    @staticmethod
+    # This function create the appropriate field object for a variable defined in the message.
+    # The descriptor and parent message parameters are required parameters, all field need them to be created. The oneof
+    # parameter is only required for fields which are part of a oneof. The parameter is the reference to the oneof
+    # object.
+    # The last parameter is not to be used manually. It is set when we are already in a FieldNested class.
+    def factory(proto_descriptor, parent_msg, oneof=None, already_nested=False):
+        if (FieldDescriptorProto.LABEL_REPEATED == proto_descriptor.label) and not already_nested:
+            result = FieldRepeated(proto_descriptor, parent_msg, oneof)
+        elif FieldDescriptorProto.TYPE_MESSAGE == proto_descriptor.type:
+            result = FieldMessage(proto_descriptor, parent_msg, oneof)
+        elif FieldDescriptorProto.TYPE_ENUM == proto_descriptor.type:
+            result = FieldEnum(proto_descriptor, parent_msg, oneof)
+        elif FieldDescriptorProto.TYPE_STRING == proto_descriptor.type:
+            result = FieldString(proto_descriptor, parent_msg, oneof)
+        elif FieldDescriptorProto.TYPE_BYTES == proto_descriptor.type:
+            result = FieldBytes(proto_descriptor, parent_msg, oneof)
+        else:
+            result = FieldBasic(proto_descriptor, parent_msg, oneof)
+        return result
+
+    def get_wire_type_str(self):
+        return ""
+
+    def get_type(self):
+        return ""
+
+    def get_short_type(self):
+        return ""
+
+    def get_default_value(self):
+        return ""
+
+    def get_name(self):
+        return self.name
+
+    def get_variable_name(self):
+        var_name = ""
+        if self.oneof:
+            var_name = self.oneof.get_variable_name() + "."
+        var_name += self.variable_name
+        return var_name
+
+    def get_variable_id_name(self):
+        return self.variable_id_name
+
+    # Returns a list with a dictionaries for each template parameter this field had. The dictionary holds the parameter
+    # name and its type.
+    def get_template_parameters(self):
+        # For the field that do not have any templates return an empty list.
+        return []
+
+    def match_field_with_definitions(self, all_types_definitions):
+        pass
+
+    def register_template_parameters(self):
+        return True
+
+    # Returns true if in oneof.init the new& function needs to be call to initialize already allocated memory.
+    def oneof_allocation_required(self):
+        return (type(self) is FieldMessage) or (type(self) is FieldRepeated) or (type(self) is FieldString) or \
+               (type(self) is FieldBytes)
+
+    def get_oneof_name(self):
+        return self.oneof.get_name()
+
+    def get_which_oneof(self):
+        return self.oneof.get_which_oneof()
+
+    # Get the scope relevant compared to the scope this field is used in.
+    def get_reduced_scope(self):
+        parent_scope = self.parent.scope.get()
+        def_scope = self.definition.scope.get()
+        start_index = 0
+        for ds, ps in zip(def_scope[:-1], parent_scope):
+            if ds == ps:
+                start_index += 1
+            else:
+                break
+        reduced_scope = def_scope[start_index:]
+        return reduced_scope
+
+    def render(self, filename, jinja_environment):
+        template = jinja_environment.get_template(filename)
+        rendered_str = template.render(field=self, environment=jinja_environment)
+        return rendered_str
+
+# -----------------------------------------------------------------------------
+
+
+# This class is used to define any type of basic field.
+class FieldBasic(Field):
+    # A dictionary to convert the wire type into a default value.
+    type_to_default_value = {FieldDescriptorProto.TYPE_DOUBLE:   "0.0",
+                             FieldDescriptorProto.TYPE_FLOAT:    "0.0",
+                             FieldDescriptorProto.TYPE_INT64:    "0",
+                             FieldDescriptorProto.TYPE_UINT64:   "0U",
+                             FieldDescriptorProto.TYPE_INT32:    "0",
+                             FieldDescriptorProto.TYPE_FIXED64:  "0U",
+                             FieldDescriptorProto.TYPE_FIXED32:  "0U",
+                             FieldDescriptorProto.TYPE_BOOL:     "false",
+                             FieldDescriptorProto.TYPE_UINT32:   "0U",
+                             FieldDescriptorProto.TYPE_SFIXED32: "0",
+                             FieldDescriptorProto.TYPE_SFIXED64: "0",
+                             FieldDescriptorProto.TYPE_SINT32:   "0",
+                             FieldDescriptorProto.TYPE_SINT64:   "0"}
+
+    # A dictionary to convert the protobuf wire type into a C++ type.
+    type_to_cpp_type = {FieldDescriptorProto.TYPE_DOUBLE:   "EmbeddedProto::doublefixed",
+                        FieldDescriptorProto.TYPE_FLOAT:    "EmbeddedProto::floatfixed",
+                        FieldDescriptorProto.TYPE_INT64:    "EmbeddedProto::int64",
+                        FieldDescriptorProto.TYPE_UINT64:   "EmbeddedProto::uint64",
+                        FieldDescriptorProto.TYPE_INT32:    "EmbeddedProto::int32",
+                        FieldDescriptorProto.TYPE_FIXED64:  "EmbeddedProto::fixed64",
+                        FieldDescriptorProto.TYPE_FIXED32:  "EmbeddedProto::fixed32",
+                        FieldDescriptorProto.TYPE_BOOL:     "EmbeddedProto::boolean",
+                        FieldDescriptorProto.TYPE_UINT32:   "EmbeddedProto::uint32",
+                        FieldDescriptorProto.TYPE_SFIXED32: "EmbeddedProto::sfixed32",
+                        FieldDescriptorProto.TYPE_SFIXED64: "EmbeddedProto::sfixed64",
+                        FieldDescriptorProto.TYPE_SINT32:   "EmbeddedProto::sint32",
+                        FieldDescriptorProto.TYPE_SINT64:   "EmbeddedProto::sint64"}
+
+    # A dictionary to convert the wire type number into a wire type string.
+    type_to_wire_type = {FieldDescriptorProto.TYPE_INT32:    "VARINT",
+                         FieldDescriptorProto.TYPE_INT64:    "VARINT",
+                         FieldDescriptorProto.TYPE_UINT32:   "VARINT",
+                         FieldDescriptorProto.TYPE_UINT64:   "VARINT",
+                         FieldDescriptorProto.TYPE_SINT32:   "VARINT",
+                         FieldDescriptorProto.TYPE_SINT64:   "VARINT",
+                         FieldDescriptorProto.TYPE_BOOL:     "VARINT",
+                         FieldDescriptorProto.TYPE_FIXED64:  "FIXED64",
+                         FieldDescriptorProto.TYPE_SFIXED64: "FIXED64",
+                         FieldDescriptorProto.TYPE_DOUBLE:   "FIXED64",
+                         FieldDescriptorProto.TYPE_FIXED32:  "FIXED32",
+                         FieldDescriptorProto.TYPE_FLOAT:    "FIXED32",
+                         FieldDescriptorProto.TYPE_SFIXED32: "FIXED32"}
+
+    def __init__(self, proto_descriptor, parent_msg, oneof=None):
+        super().__init__(proto_descriptor, parent_msg, "FieldBasic.h", oneof)
+
+    def get_wire_type_str(self):
+        return self.type_to_wire_type[self.descriptor.type]
+
+    def get_type(self):
+        return self.type_to_cpp_type[self.descriptor.type]
+
+    def get_short_type(self):
+        return self.get_type().split("::")[-1]
+
+    def get_default_value(self):
+        return self.type_to_default_value[self.descriptor.type]
+
+    def render_get_set(self, jinja_env):
+        return self.render("FieldBasic_GetSet.h", jinja_environment=jinja_env)
+
+    def render_serialize(self, jinja_env):
+        return self.render("FieldBasic_Serialize.h", jinja_environment=jinja_env)
+
+    def render_deserialize(self, jinja_env):
+        return self.render("FieldBasic_Deserialize.h", jinja_environment=jinja_env)
+
+# -----------------------------------------------------------------------------
+
+
+# This class defines a string field
+class FieldString(Field):
+    def __init__(self, proto_descriptor, parent_msg, oneof=None):
+        super().__init__(proto_descriptor, parent_msg, "FieldString.h", oneof)
+
+        # This is the name given to the template parameter for the length.
+        self.template_param_str = self.variable_name + "LENGTH"
+
+    def get_wire_type_str(self):
+        return "LENGTH_DELIMITED"
+
+    def get_type(self):
+        return "::EmbeddedProto::FieldString<" + self.template_param_str + ">"
+
+    def get_short_type(self):
+        return "FieldString"
+
+    def get_template_parameters(self):
+        return [{"name": self.template_param_str, "type": "uint32_t"}]
+
+    def register_template_parameters(self):
+        self.parent.scope.register_template_parameters(self)
+        return True
+
+    def render_get_set(self, jinja_env):
+        return self.render("FieldString_GetSet.h", jinja_environment=jinja_env)
+
+    def render_serialize(self, jinja_env):
+        return self.render("FieldRepeated_Serialize.h", jinja_environment=jinja_env)
+
+    def render_deserialize(self, jinja_env):
+        return self.render("FieldBasic_Deserialize.h", jinja_environment=jinja_env)
+
+# -----------------------------------------------------------------------------
+
+
+# This class defines a bytes array field
+class FieldBytes(Field):
+    def __init__(self, proto_descriptor, parent_msg, oneof=None):
+        super().__init__(proto_descriptor, parent_msg, "FieldBytes.h", oneof)
+
+        # This is the name given to the template parameter for the length.
+        self.template_param_str = self.variable_name + "LENGTH"
+
+    def get_wire_type_str(self):
+        return "LENGTH_DELIMITED"
+
+    def get_type(self):
+        return "::EmbeddedProto::FieldBytes<" + self.template_param_str + ">"
+
+    def get_short_type(self):
+        return "FieldBytes"
+
+    def get_template_parameters(self):
+        return [{"name": self.template_param_str, "type": "uint32_t"}]
+
+    def register_template_parameters(self):
+        self.parent.register_child_with_template(self)
+        return True
+
+    def render_get_set(self, jinja_env):
+        return self.render("FieldBytes_GetSet.h", jinja_environment=jinja_env)
+
+    def render_serialize(self, jinja_env):
+        return self.render("FieldRepeated_Serialize.h", jinja_environment=jinja_env)
+
+    def render_deserialize(self, jinja_env):
+        return self.render("FieldBasic_Deserialize.h", jinja_environment=jinja_env)
+
+# -----------------------------------------------------------------------------
+
+
+# This class is used to wrap around any enum used as a field.
+class FieldEnum(Field):
+    def __init__(self, proto_descriptor, parent_msg, oneof=None):
+        super().__init__(proto_descriptor, parent_msg, "FieldEnum.h", oneof)
+
+        # Reserve a member variable for the reference to the enum definition used for this field.
+        self.definition = None
+
+    def get_wire_type_str(self):
+        return "VARINT"
+
+    def get_type(self):
+        if not self.definition:
+            # When the actual definition is unknown use the protobuf type.
+            type_name = self.descriptor.type_name if "." != self.descriptor.type_name[0] else self.descriptor.type_name[1:]
+            type_name = type_name.replace(".", "::")
+        else:
+            scopes = self.get_reduced_scope()
+            type_name = ""
+            for scope in scopes:
+                if scope["templates"]:
+                    raise Exception("You are trying to use a field with the type: \"" + self.descriptor.type_name +
+                                    "\". It is defined in different scope as where you are using it. But the scope of "
+                                    "definition includes template parameters for repeated, string or byte fields. It "
+                                    "is there for not possible to define the field where you are using it as we do not "
+                                    "know the template value. Try defining the field in the main scope or the one you "
+                                    "are using it in.")
+
+                type_name += scope["name"] + "::"
+            # Remove the last ::
+            type_name = type_name[:-2]
+        return type_name
+
+    def get_short_type(self):
+        return self.get_type().split("::")[-1]
+
+    def get_default_value(self):
+        return "static_cast<" + self.get_type() + ">(0)"
+
+    def match_field_with_definitions(self, all_types_definitions):
+        found = False
+        my_type = self.get_type()
+        for enum_defs in all_types_definitions["enums"]:
+            other_scope = enum_defs.scope.get_scope_str()
+            if my_type == other_scope:
+                self.definition = enum_defs
+                found = True
+                break
+
+        if not found:
+            raise Exception("Unable to find the definition of this enum: " + self.name)
+
+    def render_get_set(self, jinja_env):
+        return self.render("FieldEnum_GetSet.h", jinja_environment=jinja_env)
+
+    def render_serialize(self, jinja_env):
+        return self.render("FieldEnum_Serialize.h", jinja_environment=jinja_env)
+
+    def render_deserialize(self, jinja_env):
+        return self.render("FieldEnum_Deserialize.h", jinja_environment=jinja_env)
+
+# -----------------------------------------------------------------------------
+
+
+# This class is used to wrap around any type of message used as a field.
+class FieldMessage(Field):
+    def __init__(self, proto_descriptor, parent_msg, oneof=None):
+        super().__init__(proto_descriptor, parent_msg, "FieldMsg.h", oneof)
+
+        # Reserve a member variable for the reference to the message definition used for this field.
+        self.definition = None
+
+    def get_wire_type_str(self):
+        return "LENGTH_DELIMITED"
+
+    def get_type(self):
+        if not self.definition:
+            # When the actual definition is unknown use the protobuf type.
+            type_name = self.descriptor.type_name if "." != self.descriptor.type_name[0] else self.descriptor.type_name[1:]
+            type_name = type_name.replace(".", "::")
+        else:
+            scopes = self.get_reduced_scope()
+            type_name = ""
+            for scope in scopes:
+                type_name += scope["name"] + "::"
+            # Remove the last ::
+            type_name = type_name[:-2]
+
+            tmpl_param = self.get_template_parameters()
+            if tmpl_param:
+                type_name += "<"
+                for param in tmpl_param:
+                    type_name += param["name"] + ", "
+                type_name = type_name[:-2] + ">"
+
+        return type_name
+
+    def get_short_type(self):
+        return self.get_type().split("::")[-1]
+
+    def get_default_value(self):
+        # Just call the default constructor.
+        return ""
+
+    def get_template_parameters(self):
+        # Get the template names used by the definition.
+        templates = copy.deepcopy(self.definition.get_templates())
+        # Next add our variable name to make them unique.
+        for tmp in templates:
+            tmp["name"] = self.variable_name + tmp["name"]
+        return templates
+
+    def match_field_with_definitions(self, all_types_definitions):
+        found = False
+        my_type = self.get_type()
+        for msg_defs in all_types_definitions["messages"]:
+            other_scope = msg_defs.scope.get_scope_str()
+            if my_type == other_scope:
+                self.definition = msg_defs
+                found = True
+                break
+
+        if not found:
+            raise Exception("Unable to find the definition of this message: " + self.name)
+
+    def register_template_parameters(self):
+        if self.definition.all_parameters_registered:
+            if self.definition.contains_template_parameters:
+                self.parent.register_child_with_template(self)
+            return True
+        else:
+            return False
+
+    # Get the whole scope of the definition of this field.
+    def get_scope(self):
+        return self.definition.scope.get()
+
+    def render_get_set(self, jinja_env):
+        return self.render("FieldMsg_GetSet.h", jinja_environment=jinja_env)
+
+    def render_serialize(self, jinja_env):
+        return self.render("FieldMsg_Serialize.h", jinja_environment=jinja_env)
+
+    def render_deserialize(self, jinja_env):
+        return self.render("FieldMsg_Deserialize.h", jinja_environment=jinja_env)
+
+# -----------------------------------------------------------------------------
+
+
+# This class wraps around any other type of field which is repeated.
+class FieldRepeated(Field):
+    def __init__(self, proto_descriptor, parent_msg, oneof=None):
+        super().__init__(proto_descriptor, parent_msg, "FieldRepeated.h", oneof)
+
+        # To make use of the field object actual type create one of their objects.
+        self.actual_type = Field.factory(proto_descriptor, parent_msg, oneof, already_nested=True)
+
+        # This is the name given to the template parameter for the length.
+        self.template_param_str = self.variable_name + "REP_LENGTH"
+
+    def get_wire_type_str(self):
+        return "LENGTH_DELIMITED"
+
+    def get_type(self):
+        return "::EmbeddedProto::RepeatedFieldFixedSize<" + self.actual_type.get_type() + ", " + \
+               self.template_param_str + ">"
+
+    def get_short_type(self):
+        return "::EmbeddedProto::RepeatedFieldFixedSize<" + self.actual_type.get_short_type() + ", " + \
+               self.template_param_str + ">"
+
+    # As this is a repeated field we need a function to get the type we are repeating.
+    def get_base_type(self):
+        return self.actual_type.get_type()
+
+    def get_template_parameters(self):
+        result = [{"name": self.template_param_str, "type": "uint32_t"}]
+        result.extend(self.actual_type.get_template_parameters())
+        return result
+
+    def match_field_with_definitions(self, all_types_definitions):
+        self.actual_type.match_field_with_definitions(all_types_definitions)
+
+    def register_template_parameters(self):
+        self.parent.register_child_with_template(self)
+        return True
+
+    def render_get_set(self, jinja_env):
+        return self.render("FieldRepeated_GetSet.h", jinja_environment=jinja_env)
+
+    def render_serialize(self, jinja_env):
+        return self.render("FieldRepeated_Serialize.h", jinja_environment=jinja_env)
+
+    def render_deserialize(self, jinja_env):
+        return self.render("FieldBasic_Deserialize.h", jinja_environment=jinja_env)

+ 78 - 0
generator/support/Oneof.py

@@ -0,0 +1,78 @@
+#
+# Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+#
+# This file is part of Embedded Proto.
+#
+# Embedded Proto is open source software: you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as published
+# by the Free Software Foundation, version 3 of the license.
+#
+# Embedded Proto  is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+#
+# For commercial and closed source application please visit:
+# <https://EmbeddedProto.com/license/>.
+#
+# Embedded AMS B.V.
+# Info:
+#   info at EmbeddedProto dot com
+#
+# Postal address:
+#   Johan Huizingalaan 763a
+#   1066 VH, Amsterdam
+#   the Netherlands
+#
+
+from .Field import Field
+
+
+class Oneof:
+    def __init__(self, oneof_proto_descriptor, index, msg_descriptor, parent_msg):
+        # A reference to the OneofDescriptorProto object which defines this field.
+        self.descriptor = oneof_proto_descriptor
+
+        # A reference to the parent message in which this oneof is defined.
+        self.parent = parent_msg
+
+        self.fields = []
+        # Loop over all the fields in this oneof
+        for f in msg_descriptor.field:
+            if f.HasField('oneof_index') and index == f.oneof_index:
+                new_field = Field.factory(f, self.parent, oneof=self)
+                self.fields.append(new_field)
+
+    def get_name(self):
+        return self.descriptor.name
+
+    def get_variable_name(self):
+        return self.get_name() + "_"
+
+    def get_which_oneof(self):
+        return "which_" + self.get_name() + "_"
+
+    def get_fields(self):
+        return self.fields
+
+    def match_field_with_definitions(self, all_types_definitions):
+        for field in self.fields:
+            field.match_field_with_definitions(all_types_definitions)
+
+    def register_template_parameters(self):
+        all_parameters_registered = True
+        for field in self.fields:
+            all_parameters_registered = field.register_template_parameters() and all_parameters_registered
+        return all_parameters_registered
+
+    # Returns true if in oneof.init the new& function needs to be call to initialize already allocated memory.
+    def oneof_allocation_required(self):
+        result = False
+        for field in self.fields:
+            result = field.oneof_allocation_required()
+            if result:
+                break
+        return result

+ 104 - 0
generator/support/ProtoFile.py

@@ -0,0 +1,104 @@
+#
+# Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+#
+# This file is part of Embedded Proto.
+#
+# Embedded Proto is open source software: you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as published
+# by the Free Software Foundation, version 3 of the license.
+#
+# Embedded Proto  is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+#
+# For commercial and closed source application please visit:
+# <https://EmbeddedProto.com/license/>.
+#
+# Embedded AMS B.V.
+# Info:
+#   info at EmbeddedProto dot com
+#
+# Postal address:
+#   Johan Huizingalaan 763a
+#   1066 VH, Amsterdam
+#   the Netherlands
+#
+
+from .TypeDefinitions import *
+import os
+import jinja2
+
+
+class ProtoFile:
+    def __init__(self, proto_descriptor):
+        self.descriptor = proto_descriptor
+
+        if "proto2" == proto_descriptor.syntax:
+            raise Exception(proto_descriptor.name + ": Sorry, proto2 is not supported, please use proto3.")
+
+        # These file names are the ones used for creating the C++ files.
+        self.filename_with_folder = os.path.splitext(proto_descriptor.name)[0]
+        self.filename_without_folder = os.path.basename(self.filename_with_folder)
+
+        # Construct the base scope used in this file.
+        self.scope = None
+        if self.descriptor.package:
+            package_list = self.descriptor.package.split(".")
+            # The first element is the base scope.
+            self.scope = Scope(package_list[0], None)
+            # Next add additional scopes nesting the previous one.
+            for package in package_list[1:]:
+                self.scope = Scope(package, self.scope)
+
+        self.enum_definitions = [EnumDefinition(enum, self.scope) for enum in self.descriptor.enum_type]
+        self.msg_definitions = [MessageDefinition(msg, self.scope) for msg in self.descriptor.message_type]
+
+        self.all_parameters_registered = False
+
+    def get_dependencies(self):
+        imported_dependencies = []
+        if self.descriptor.dependency:
+            imported_dependencies = [os.path.splitext(dependency)[0] + ".h" for dependency in
+                                     self.descriptor.dependency]
+        return imported_dependencies
+
+    def get_namespaces(self):
+        if self.scope:
+            result = self.scope.get_list_of_scope_str()
+        else:
+            result = []
+        return result
+
+    def get_header_guard(self):
+        return self.filename_with_folder.replace("/", "_").upper()
+
+    # Obtain a dictionary with references to all nested enums and messages
+    def get_all_nested_types(self):
+        nested_types = {"enums": self.enum_definitions, "messages": []}
+        for msg in self.msg_definitions:
+            nt = msg.get_all_nested_types()
+            nested_types["enums"].extend(nt["enums"])
+            nested_types["messages"].extend(nt["messages"])
+            nested_types["messages"].append(msg)
+
+        return nested_types
+
+    def match_fields_with_definitions(self, all_types_definitions):
+        for msg in self.msg_definitions:
+            msg.match_fields_with_definitions(all_types_definitions)
+
+    def register_template_parameters(self):
+        all_parameters_registered = True
+        for msg in self.msg_definitions:
+            all_parameters_registered = msg.register_template_parameters() and all_parameters_registered
+        return all_parameters_registered
+
+    def render(self, jinja_environment):
+        template_file = "Header.h"
+        template = jinja_environment.get_template(template_file)
+        file_str = template.render(proto_file=self, environment=jinja_environment)
+        return file_str

+ 210 - 0
generator/support/TypeDefinitions.py

@@ -0,0 +1,210 @@
+#
+# Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+#
+# This file is part of Embedded Proto.
+#
+# Embedded Proto is open source software: you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as published
+# by the Free Software Foundation, version 3 of the license.
+#
+# Embedded Proto  is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+#
+# For commercial and closed source application please visit:
+# <https://EmbeddedProto.com/license/>.
+#
+# Embedded AMS B.V.
+# Info:
+#   info at EmbeddedProto dot com
+#
+# Postal address:
+#   Johan Huizingalaan 763a
+#   1066 VH, Amsterdam
+#   the Netherlands
+#
+
+from .Field import Field
+from .Oneof import Oneof
+import jinja2
+
+
+# This class deal with the scope in which definitions and field are located. It is used to keep track of template
+# parameters required for a given scope.
+class Scope:
+    def __init__(self, scope_name, parent):
+        # The name of this scope/namespace
+        self.name = scope_name
+
+        # A reference to the scope above this scope. If we are at the top level this will be None.
+        self.parent = parent
+
+        # Start of without any children.
+        self.child_scopes = []
+
+        # Register this object with it's parent.
+        if self.parent:
+            self.parent.child_scopes.append(self)
+
+        self.fields_with_templates = []
+
+    # This function is used
+    def get_list_of_scope_str(self):
+        if self.parent:
+            result = self.parent.get_list_of_scope_str()
+            result.append(self.name)
+        else:
+            result = [self.name]
+        return result
+
+    # When searching for the definition of a field this function returns a scope string equal to the type defined by
+    # protobuf.
+    def get_scope_str(self):
+        if self.parent:
+            scope_str = self.parent.get_scope_str() + "::" + self.name
+        else:
+            scope_str = self.name
+
+        return scope_str
+
+    def register_template_parameters(self, field):
+        self.fields_with_templates.append(field)
+
+    # Return the list of template parameters required for this scope alone.
+    def get_template_parameters(self):
+        result = []
+        for field in self.fields_with_templates:
+            result.extend(field.get_template_parameters())
+        return result
+
+    # Return a full list of the scope, parent scopes and their templates
+    def get(self):
+        result = []
+        if self.parent:
+            result.extend(self.parent.get())
+        result.extend([{"name": self.name, "templates": self.get_template_parameters()}])
+        return result
+
+# -----------------------------------------------------------------------------
+
+
+class TypeDefinition:
+    def __init__(self, proto_descriptor, parent_scope, template_filename):
+        self.descriptor = proto_descriptor
+        self.name = proto_descriptor.name
+        self.scope = Scope(self.name, parent_scope)
+        self.template_file = template_filename
+
+    def get_name(self):
+        return self.name
+
+    def render(self, jinja_environment):
+        template = jinja_environment.get_template(self.template_file)
+        render_result = template.render(typedef=self, environment=jinja_environment)
+        return render_result
+
+
+# -----------------------------------------------------------------------------
+
+class EnumDefinition(TypeDefinition):
+    def __init__(self, proto_descriptor, parent_scope):
+        super().__init__(proto_descriptor, parent_scope, "TypeDefEnum.h")
+
+    # Loop through the values defined in the enum.
+    def values(self):
+        for value in self.descriptor.value:
+            yield value
+
+
+# -----------------------------------------------------------------------------
+
+class MessageDefinition(TypeDefinition):
+    def __init__(self, proto_descriptor, parent_scope):
+        super().__init__(proto_descriptor, parent_scope, "TypeDefMsg.h")
+
+        self.nested_enum_definitions = [EnumDefinition(enum, self.scope) for enum in self.descriptor.enum_type]
+        self.nested_msg_definitions = [MessageDefinition(msg, self.scope) for msg in self.descriptor.nested_type]
+
+        # Store the id numbers of all the fields to create the ID enum.
+        self.field_ids = []
+
+        # Store all the variable fields in this message.
+        self.fields = []
+        for f in self.descriptor.field:
+            if not f.HasField('oneof_index'):
+                new_field = Field.factory(f, self)
+                self.fields.append(new_field)
+                self.field_ids.append((new_field.variable_id, new_field.variable_id_name))
+
+        # Store all the oneof definitions in this message.
+        self.oneofs = []
+        for index, oneof in enumerate(self.descriptor.oneof_decl):
+            new_oneof = Oneof(oneof, index, proto_descriptor, self)
+            self.oneofs.append(new_oneof)
+            for oneof_field in new_oneof.get_fields():
+                self.field_ids.append((oneof_field.variable_id, oneof_field.variable_id_name))
+
+        # Sort the field id's such they will appear in order in the id enum.
+        self.field_ids.sort()
+
+        # Not all template parameters for this message definition have been registered with the scope. This is
+        # most likely due to a message defined later in the proto file.
+        self.all_parameters_registered = False
+
+        # Does this message definition contains fields with template parameters.
+        self.contains_template_parameters = False
+
+    # Obtain a dictionary with references to all nested enums and messages
+    def get_all_nested_types(self):
+        nested_types = {"enums": [], "messages": []}
+        nested_types["enums"].extend(self.nested_enum_definitions)
+        for msg in self.nested_msg_definitions:
+            nt = msg.get_all_nested_types()
+            nested_types["enums"].extend(nt["enums"])
+            nested_types["messages"].extend(nt["messages"])
+            nested_types["messages"].append(msg)
+
+        return nested_types
+
+    def match_fields_with_definitions(self, all_types_definitions):
+        # Resolve the types of the nested messages.
+        for msg in self.nested_msg_definitions:
+            msg.match_fields_with_definitions(all_types_definitions)
+
+        # Resolve the types of the fields defined in this message.
+        for field in self.fields:
+            field.match_field_with_definitions(all_types_definitions)
+
+        for oneof in self.oneofs:
+            oneof.match_field_with_definitions(all_types_definitions)
+
+    # TODO This function will fail to return True if this definitions contains it self as a nested field.
+    def register_template_parameters(self):
+        self.all_parameters_registered = True
+        # First resolve the template parameters for all nested message definitions.
+        for nested_msg in self.nested_msg_definitions:
+            self.all_parameters_registered = nested_msg.register_template_parameters() \
+                                             and self.all_parameters_registered
+
+        # Next see if we our self have any fields that have template parameters.
+        for field in self.fields:
+            self.all_parameters_registered = field.register_template_parameters() and self.all_parameters_registered
+
+        for oneof in self.oneofs:
+            self.all_parameters_registered = oneof.register_template_parameters() and self.all_parameters_registered
+
+        return self.all_parameters_registered
+
+    def register_child_with_template(self, child):
+        self.scope.register_template_parameters(child)
+        self.contains_template_parameters = True
+
+    def get_templates(self):
+        return self.scope.get_template_parameters()
+
+    def get_type(self):
+        return self.scope.get_scope_str()

+ 0 - 0
generator/support/__init__.py


+ 50 - 0
generator/templates/FieldBasic_Deserialize.h

@@ -0,0 +1,50 @@
+{#
+Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+
+This file is part of Embedded Proto.
+
+Embedded Proto is open source software: you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published
+by the Free Software Foundation, version 3 of the license.
+
+Embedded Proto  is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+
+For commercial and closed source application please visit:
+<https://EmbeddedProto.com/license/>.
+
+Embedded AMS B.V.
+Info:
+  info at EmbeddedProto dot com
+
+Postal address:
+  Johan Huizingalaan 763a
+  1066 VH, Amsterdam
+  the Netherlands
+#}
+if(::EmbeddedProto::WireFormatter::WireType::{{field.get_wire_type_str()}} == wire_type)
+{
+  {% if field.oneof is not none %}
+  if(id::{{field.get_variable_id_name()}} != {{field.get_which_oneof()}})
+  {
+    init_{{field.get_oneof_name()}}(id::{{field.get_variable_id_name()}});
+  }
+  {% endif %}
+  return_value = {{field.get_variable_name()}}.deserialize(buffer);
+  {% if field.oneof is not none %}
+  if(::EmbeddedProto::Error::NO_ERRORS != return_value)
+  {
+    clear_{{field.get_name()}}();
+  }
+  {% endif %}
+}
+else
+{
+  // Wire type does not match field.
+  return_value = ::EmbeddedProto::Error::INVALID_WIRETYPE;
+}

+ 62 - 0
generator/templates/FieldBasic_GetSet.h

@@ -0,0 +1,62 @@
+{#
+Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+
+This file is part of Embedded Proto.
+
+Embedded Proto is open source software: you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published
+by the Free Software Foundation, version 3 of the license.
+
+Embedded Proto  is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+
+For commercial and closed source application please visit:
+<https://EmbeddedProto.com/license/>.
+
+Embedded AMS B.V.
+Info:
+  info at EmbeddedProto dot com
+
+Postal address:
+  Johan Huizingalaan 763a
+  1066 VH, Amsterdam
+  the Netherlands
+#}
+{% if field.oneof is not none %}
+inline void clear_{{field.get_name()}}()
+{
+  if(id::{{field.get_variable_id_name()}} == {{field.get_which_oneof()}})
+  {
+    {{field.get_which_oneof()}} = id::NOT_SET;
+    {{field.get_variable_name()}}.set({{field.get_default_value()}});
+  }
+}
+inline void set_{{field.get_name()}}(const {{field.get_type()}}::FIELD_TYPE& value)
+{
+  if(id::{{field.get_variable_id_name()}} != {{field.get_which_oneof()}})
+  {
+    init_{{field.get_oneof_name()}}(id::{{field.get_variable_id_name()}});
+  }
+  {{field.get_variable_name()}}.set(value);
+}
+inline void set_{{field.get_name()}}(const {{field.get_type()}}::FIELD_TYPE&& value)
+{
+  if(id::{{field.get_variable_id_name()}} != {{field.get_which_oneof()}})
+  {
+    init_{{field.get_oneof_name()}}(id::{{field.get_variable_id_name()}});
+  }
+  {{field.get_variable_name()}}.set(value);
+}
+{% else %}
+inline void clear_{{field.get_name()}}() { {{field.get_variable_name()}}.clear(); }
+inline void set_{{field.get_name()}}(const {{field.get_type()}}& value) { {{field.get_variable_name()}} = value; }
+inline void set_{{field.get_name()}}(const {{field.get_type()}}&& value) { {{field.get_variable_name()}} = value; }
+inline {{field.get_type()}}& mutable_{{field.get_name()}}() { return {{field.get_variable_name()}}; }
+{% endif %}
+inline const {{field.get_type()}}& get_{{field.get_name()}}() const { return {{field.get_variable_name()}}; }
+inline {{field.get_type()}}::FIELD_TYPE {{field.get_name()}}() const { return {{field.get_variable_name()}}.get(); }

+ 33 - 0
generator/templates/FieldBasic_Serialize.h

@@ -0,0 +1,33 @@
+{#
+Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+
+This file is part of Embedded Proto.
+
+Embedded Proto is open source software: you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published
+by the Free Software Foundation, version 3 of the license.
+
+Embedded Proto  is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+
+For commercial and closed source application please visit:
+<https://EmbeddedProto.com/license/>.
+
+Embedded AMS B.V.
+Info:
+  info at EmbeddedProto dot com
+
+Postal address:
+  Johan Huizingalaan 763a
+  1066 VH, Amsterdam
+  the Netherlands
+#}
+if(({{field.get_default_value()}} != {{field.get_variable_name()}}.get()) && (::EmbeddedProto::Error::NO_ERRORS == return_value))
+{
+  return_value = {{field.get_variable_name()}}.serialize_with_id(static_cast<uint32_t>(id::{{field.get_variable_id_name()}}), buffer);
+}

+ 52 - 0
generator/templates/FieldBytes_GetSet.h

@@ -0,0 +1,52 @@
+{#
+Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+
+This file is part of Embedded Proto.
+
+Embedded Proto is open source software: you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published
+by the Free Software Foundation, version 3 of the license.
+
+Embedded Proto  is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+
+For commercial and closed source application please visit:
+<https://EmbeddedProto.com/license/>.
+
+Embedded AMS B.V.
+Info:
+  info at EmbeddedProto dot com
+
+Postal address:
+  Johan Huizingalaan 763a
+  1066 VH, Amsterdam
+  the Netherlands
+#}
+{% if field.oneof is not none %}
+inline void clear_{{field.get_name()}}()
+{
+  if(id::{{field.get_variable_id_name()}} == {{field.get_which_oneof()}})
+  {
+    {{field.get_which_oneof()}} = id::NOT_SET;
+    {{field.get_variable_name()}}.~{{field.get_short_type()}}();
+  }
+}
+inline {{field.get_type()}}& mutable_{{field.get_name()}}()
+{
+  if(id::{{field.get_variable_id_name()}} != {{field.get_which_oneof()}})
+  {
+    init_{{field.get_oneof_name()}}(id::{{field.get_variable_id_name()}});
+  }
+  return {{field.get_variable_name()}};
+}
+{% else %}
+inline void clear_{{field.get_name()}}() { {{field.get_variable_name()}}.clear(); }
+inline {{field.get_type()}}& mutable_{{field.get_name()}}() { return {{field.get_variable_name()}}; }
+{% endif %}
+inline const {{field.get_type()}}& {{field.get_name()}}() const { return {{field.get_variable_name()}}; }
+inline const uint8_t* get_{{field.get_name()}}() const { return {{field.get_variable_name()}}.get_const(); }

+ 43 - 0
generator/templates/FieldEnum_Deserialize.h

@@ -0,0 +1,43 @@
+{#
+Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+
+This file is part of Embedded Proto.
+
+Embedded Proto is open source software: you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published
+by the Free Software Foundation, version 3 of the license.
+
+Embedded Proto  is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+
+For commercial and closed source application please visit:
+<https://EmbeddedProto.com/license/>.
+
+Embedded AMS B.V.
+Info:
+  info at EmbeddedProto dot com
+
+Postal address:
+  Johan Huizingalaan 763a
+  1066 VH, Amsterdam
+  the Netherlands
+#}
+if(::EmbeddedProto::WireFormatter::WireType::{{field.get_wire_type_str()}} == wire_type)
+{
+  uint32_t value;
+  return_value = ::EmbeddedProto::WireFormatter::DeserializeVarint(buffer, value);
+  if(::EmbeddedProto::Error::NO_ERRORS == return_value)
+  {
+    set_{{field.get_name()}}(static_cast<{{field.get_type()}}>(value));
+  }
+}
+else
+{
+  // Wire type does not match field.
+  return_value = ::EmbeddedProto::Error::INVALID_WIRETYPE;
+}

+ 61 - 0
generator/templates/FieldEnum_GetSet.h

@@ -0,0 +1,61 @@
+{#
+Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+
+This file is part of Embedded Proto.
+
+Embedded Proto is open source software: you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published
+by the Free Software Foundation, version 3 of the license.
+
+Embedded Proto  is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+
+For commercial and closed source application please visit:
+<https://EmbeddedProto.com/license/>.
+
+Embedded AMS B.V.
+Info:
+  info at EmbeddedProto dot com
+
+Postal address:
+  Johan Huizingalaan 763a
+  1066 VH, Amsterdam
+  the Netherlands
+#}
+{% if field.oneof is not none %}
+inline void clear_{{field.get_name()}}()
+{
+  if(id::{{field.get_variable_id_name()}} == {{field.get_which_oneof()}})
+  {
+    {{field.get_which_oneof()}} = id::NOT_SET;
+    {{field.get_variable_name()}} = static_cast<{{field.get_type()}}>({{field.get_default_value()}});
+  }
+}
+inline void set_{{field.get_name()}}(const {{field.get_type()}}& value)
+{
+  if(id::{{field.get_variable_id_name()}} != {{field.get_which_oneof()}})
+  {
+    init_{{field.get_oneof_name()}}(id::{{field.get_variable_id_name()}});
+  }
+  {{field.get_variable_name()}} = value;
+}
+inline void set_{{field.get_name()}}(const {{field.get_type()}}&& value)
+{
+  if(id::{{field.get_variable_id_name()}} != {{field.get_which_oneof()}})
+  {
+    init_{{field.get_oneof_name()}}(id::{{field.get_variable_id_name()}});
+  }
+  {{field.get_variable_name()}} = value;
+}
+{% else %}
+inline void clear_{{field.get_name()}}() { {{field.get_variable_name()}} = {{field.get_default_value()}}; }
+inline void set_{{field.get_name()}}(const {{field.get_type()}}& value) { {{field.get_variable_name()}} = value; }
+inline void set_{{field.get_name()}}(const {{field.get_type()}}&& value) { {{field.get_variable_name()}} = value; }
+{% endif %}
+inline const {{field.get_type()}}& get_{{field.get_name()}}() const { return {{field.get_variable_name()}}; }
+inline {{field.get_type()}} {{field.get_name()}}() const { return {{field.get_variable_name()}}; }

+ 35 - 0
generator/templates/FieldEnum_Serialize.h

@@ -0,0 +1,35 @@
+{#
+Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+
+This file is part of Embedded Proto.
+
+Embedded Proto is open source software: you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published
+by the Free Software Foundation, version 3 of the license.
+
+Embedded Proto  is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+
+For commercial and closed source application please visit:
+<https://EmbeddedProto.com/license/>.
+
+Embedded AMS B.V.
+Info:
+  info at EmbeddedProto dot com
+
+Postal address:
+  Johan Huizingalaan 763a
+  1066 VH, Amsterdam
+  the Netherlands
+#}
+if(({{field.get_default_value()}} != {{field.get_variable_name()}}) && (::EmbeddedProto::Error::NO_ERRORS == return_value))
+{
+  EmbeddedProto::uint32 value;
+  value.set(static_cast<uint32_t>({{field.get_variable_name()}}));
+  return_value = value.serialize_with_id(static_cast<uint32_t>(id::{{field.get_variable_id_name()}}), buffer);
+}

+ 50 - 0
generator/templates/FieldMsg_Deserialize.h

@@ -0,0 +1,50 @@
+{#
+Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+
+This file is part of Embedded Proto.
+
+Embedded Proto is open source software: you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published
+by the Free Software Foundation, version 3 of the license.
+
+Embedded Proto  is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+
+For commercial and closed source application please visit:
+<https://EmbeddedProto.com/license/>.
+
+Embedded AMS B.V.
+Info:
+  info at EmbeddedProto dot com
+
+Postal address:
+  Johan Huizingalaan 763a
+  1066 VH, Amsterdam
+  the Netherlands
+#}
+if(::EmbeddedProto::WireFormatter::WireType::{{field.get_wire_type_str()}} == wire_type)
+{
+  uint32_t size;
+  return_value = ::EmbeddedProto::WireFormatter::DeserializeVarint(buffer, size);
+  ::EmbeddedProto::ReadBufferSection bufferSection(buffer, size);
+  if(::EmbeddedProto::Error::NO_ERRORS == return_value)
+  {
+    return_value = mutable_{{field.get_name()}}().deserialize(bufferSection);
+  }
+  {% if field.oneof is not none %}
+  if(::EmbeddedProto::Error::NO_ERRORS != return_value)
+  {
+    clear_{{field.get_name()}}();
+  }
+  {% endif %}
+}
+else
+{
+  // Wire type does not match field.
+  return_value = ::EmbeddedProto::Error::INVALID_WIRETYPE;
+}

+ 70 - 0
generator/templates/FieldMsg_GetSet.h

@@ -0,0 +1,70 @@
+{#
+Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+
+This file is part of Embedded Proto.
+
+Embedded Proto is open source software: you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published
+by the Free Software Foundation, version 3 of the license.
+
+Embedded Proto  is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+
+For commercial and closed source application please visit:
+<https://EmbeddedProto.com/license/>.
+
+Embedded AMS B.V.
+Info:
+  info at EmbeddedProto dot com
+
+Postal address:
+  Johan Huizingalaan 763a
+  1066 VH, Amsterdam
+  the Netherlands
+#}
+{% if field.oneof is not none %}
+inline void clear_{{field.get_name()}}()
+{
+  if(id::{{field.get_variable_id_name()}} == {{field.get_which_oneof()}})
+  {
+    {{field.get_which_oneof()}} = id::NOT_SET;
+    {{field.get_variable_name()}}.~{{field.get_short_type()}}();
+  }
+}
+inline void set_{{field.get_name()}}(const {{field.get_type()}}& value)
+{
+  if(id::{{field.get_variable_id_name()}} != {{field.get_which_oneof()}})
+  {
+    init_{{field.get_oneof_name()}}(id::{{field.get_variable_id_name()}});
+  }
+  {{field.get_variable_name()}} = value;
+}
+inline void set_{{field.get_name()}}(const {{field.get_type()}}&& value)
+{
+  if(id::{{field.get_variable_id_name()}} != {{field.get_which_oneof()}})
+  {
+    init_{{field.get_oneof_name()}}(id::{{field.get_variable_id_name()}});
+  }
+  {{field.get_variable_name()}} = value;
+}
+inline {{field.get_type()}}& mutable_{{field.get_name()}}()
+{
+  if(id::{{field.get_variable_id_name()}} != {{field.get_which_oneof()}})
+  {
+    init_{{field.get_oneof_name()}}(id::{{field.get_variable_id_name()}});
+  }
+  return {{field.get_variable_name()}};
+}
+{% else %}
+inline void clear_{{field.get_name()}}() { {{field.get_variable_name()}}.clear(); }
+inline void set_{{field.get_name()}}(const {{field.get_type()}}& value) { {{field.get_variable_name()}} = value; }
+inline void set_{{field.get_name()}}(const {{field.get_type()}}&& value) { {{field.get_variable_name()}} = value; }
+inline {{field.get_type()}}& mutable_{{field.get_name()}}() { return {{field.get_variable_name()}}; }
+{% endif %}
+inline const {{field.get_type()}}& get_{{field.get_name()}}() const { return {{field.get_variable_name()}}; }
+inline const {{field.get_type()}}& {{field.get_name()}}() const { return {{field.get_variable_name()}}; }

+ 33 - 0
generator/templates/FieldMsg_Serialize.h

@@ -0,0 +1,33 @@
+{#
+Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+
+This file is part of Embedded Proto.
+
+Embedded Proto is open source software: you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published
+by the Free Software Foundation, version 3 of the license.
+
+Embedded Proto  is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+
+For commercial and closed source application please visit:
+<https://EmbeddedProto.com/license/>.
+
+Embedded AMS B.V.
+Info:
+  info at EmbeddedProto dot com
+
+Postal address:
+  Johan Huizingalaan 763a
+  1066 VH, Amsterdam
+  the Netherlands
+#}
+if(::EmbeddedProto::Error::NO_ERRORS == return_value)
+{
+  return_value = {{field.get_variable_name()}}.serialize_with_id(static_cast<uint32_t>(id::{{field.get_variable_id_name()}}), buffer);
+}

+ 90 - 0
generator/templates/FieldRepeated_GetSet.h

@@ -0,0 +1,90 @@
+{#
+Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+
+This file is part of Embedded Proto.
+
+Embedded Proto is open source software: you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published
+by the Free Software Foundation, version 3 of the license.
+
+Embedded Proto  is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+
+For commercial and closed source application please visit:
+<https://EmbeddedProto.com/license/>.
+
+Embedded AMS B.V.
+Info:
+  info at EmbeddedProto dot com
+
+Postal address:
+  Johan Huizingalaan 763a
+  1066 VH, Amsterdam
+  the Netherlands
+#}
+{% if field.oneof is not none %}
+inline void clear_{{field.get_name()}}()
+{
+  if(id::{{field.get_variable_id_name()}} == {{field.get_which_oneof()}})
+  {
+    {{field.get_which_oneof}} = id::NOT_SET;
+    {{field.get_variable_name()}}.~{{field.get_short_type()}}();
+  }
+}
+inline void set_{{field.get_name()}}(uint32_t index, const {{field.get_type()}}& value)
+{
+  if(id::{{field.get_variable_id_name()}} != {{field.get_which_oneof()}})
+  {
+    init_{{field.get_oneof_name()}}(id::{{field.get_variable_id_name()}});
+  }
+  {{field.get_variable_name()}}.set(index, value);
+}
+inline void set_{{field.get_name()}}(uint32_t index, const {{field.get_type()}}&& value)
+{
+  if(id::{{field.get_variable_id_name()}} != {{field.get_which_oneof()}})
+  {
+    init_{{field.get_oneof_name()}}(id::{{field.get_variable_id_name()}});
+  }
+  {{field.get_variable_name()}}.set(index, value);
+}
+inline void set_{{field.get_name()}}(const {{field.repeated_type}}& values)
+{
+  if(id::{{field.get_variable_id_name()}} != {{field.get_which_oneof()}})
+  {
+    init_{{field.get_oneof_name()}}(id::{{field.get_variable_id_name()}});
+  }
+  {{field.get_variable_name()}} = values;
+}
+inline void add_{{field.get_name()}}(const {{field.get_type()}}& value)
+{
+  if(id::{{field.get_variable_id_name()}} != {{field.get_which_oneof()}})
+  {
+    init_{{field.get_oneof_name()}}(id::{{field.get_variable_id_name()}});
+  }
+  {{field.get_variable_name()}}.add(value);
+}
+inline {{field.repeated_type}}& mutable_{{field.get_name()}}()
+{
+  if(id::{{field.get_variable_id_name()}} != {{field.get_which_oneof()}})
+  {
+    init_{{field.get_oneof_name()}}(id::{{field.get_variable_id_name()}});
+  }
+  return {{field.get_variable_name()}};
+}
+{% else %}
+inline const {{field.get_base_type()}}& {{field.get_name()}}(uint32_t index) const { return {{field.get_variable_name()}}[index]; }
+inline void clear_{{field.get_name()}}() { {{field.get_variable_name()}}.clear(); }
+inline void set_{{field.get_name()}}(uint32_t index, const {{field.get_base_type()}}& value) { {{field.get_variable_name()}}.set(index, value); }
+inline void set_{{field.get_name()}}(uint32_t index, const {{field.get_base_type()}}&& value) { {{field.get_variable_name()}}.set(index, value); }
+inline void set_{{field.get_name()}}(const {{field.get_type()}}& values) { {{field.get_variable_name()}} = values; }
+inline void add_{{field.get_name()}}(const {{field.get_base_type()}}& value) { {{field.get_variable_name()}}.add(value); }
+inline {{field.get_type()}}& mutable_{{field.get_name()}}() { return {{field.get_variable_name()}}; }
+inline {{field.get_base_type()}}& mutable_{{field.get_name()}}(uint32_t index) { return {{field.get_variable_name()}}[index]; }
+{% endif %}
+inline const {{field.get_type()}}& get_{{field.get_name()}}() const { return {{field.get_variable_name()}}; }
+inline const {{field.get_type()}}& {{field.get_name()}}() const { return {{field.get_variable_name()}}; }

+ 33 - 0
generator/templates/FieldRepeated_Serialize.h

@@ -0,0 +1,33 @@
+{#
+Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+
+This file is part of Embedded Proto.
+
+Embedded Proto is open source software: you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published
+by the Free Software Foundation, version 3 of the license.
+
+Embedded Proto  is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+
+For commercial and closed source application please visit:
+<https://EmbeddedProto.com/license/>.
+
+Embedded AMS B.V.
+Info:
+  info at EmbeddedProto dot com
+
+Postal address:
+  Johan Huizingalaan 763a
+  1066 VH, Amsterdam
+  the Netherlands
+#}
+if(::EmbeddedProto::Error::NO_ERRORS == return_value)
+{
+  return_value = {{field.get_variable_name()}}.serialize_with_id(static_cast<uint32_t>(id::{{field.get_variable_id_name()}}), buffer);
+}

+ 52 - 0
generator/templates/FieldString_GetSet.h

@@ -0,0 +1,52 @@
+{#
+Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+
+This file is part of Embedded Proto.
+
+Embedded Proto is open source software: you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published
+by the Free Software Foundation, version 3 of the license.
+
+Embedded Proto  is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+
+For commercial and closed source application please visit:
+<https://EmbeddedProto.com/license/>.
+
+Embedded AMS B.V.
+Info:
+  info at EmbeddedProto dot com
+
+Postal address:
+  Johan Huizingalaan 763a
+  1066 VH, Amsterdam
+  the Netherlands
+#}
+{% if field.oneof is not none %}
+inline void clear_{{field.get_name()}}()
+{
+  if(id::{{field.get_variable_id_name()}} == {{field.get_which_oneof()}})
+  {
+    {{field.get_which_oneof()}} = id::NOT_SET;
+    {{field.get_variable_name()}}.~{{field.get_short_type()}}();
+  }
+}
+inline {{field.get_type()}}& mutable_{{field.get_name()}}()
+{
+  if(id::{{field.get_variable_id_name()}} != {{field.get_which_oneof()}})
+  {
+    init_{{field.get_oneof_name()}}(id::{{field.get_variable_id_name()}});
+  }
+  return {{field.get_variable_name()}};
+}
+{% else %}
+inline void clear_{{field.get_name()}}() { {{field.get_variable_name()}}.clear(); }
+inline {{field.get_type()}}& mutable_{{field.get_name()}}() { return {{field.get_variable_name()}}; }
+{% endif %}
+inline const {{field.get_type()}}& {{field.get_name()}}() const { return {{field.get_variable_name()}}; }
+inline const char* get_{{field.get_name()}}() const { return {{field.get_variable_name()}}.get_const(); }

+ 69 - 0
generator/templates/Header.h

@@ -0,0 +1,69 @@
+/*
+ *  Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+ *
+ *  This file is part of Embedded Proto.
+ *
+ *  Embedded Proto is open source software: you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License as published
+ *  by the Free Software Foundation, version 3 of the license.
+ *
+ *  Embedded Proto  is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+ *
+ *  For commercial and closed source application please visit:
+ *  <https://EmbeddedProto.com/license/>.
+ *
+ *  Embedded AMS B.V.
+ *  Info:
+ *    info at EmbeddedProto dot com
+ *
+ *  Postal address:
+ *    Johan Huizingalaan 763a
+ *    1066 VH, Amsterdam
+ *    the Netherlands
+ */
+
+// This file is generated. Please do not edit!
+#ifndef _{{proto_file.get_header_guard()}}_H_
+#define _{{proto_file.get_header_guard()}}_H_
+
+#include <cstdint>
+{% if proto_file.msg_definitions %}
+#include <MessageInterface.h>
+#include <WireFormatter.h>
+#include <Fields.h>
+#include <MessageSizeCalculator.h>
+#include <ReadBufferSection.h>
+#include <RepeatedFieldFixedSize.h>
+#include <FieldStringBytes.h>
+#include <Errors.h>
+
+{% endif %}
+{% if proto_file.get_dependencies() is defined %}
+// Include external proto definitions
+{% for dependency in proto_file.get_dependencies() %}
+#include <{{dependency}}>
+{% endfor %}
+
+{% endif %}
+{% for namespace in proto_file.get_namespaces() %}
+namespace {{ namespace }} {
+{% endfor %}
+
+{% for enum in proto_file.enum_definitions %}
+{{ enum.render(environment) }}
+
+{% endfor %}
+{% for msg in proto_file.msg_definitions %}
+{{ msg.render(environment) }}
+
+{% endfor %}
+{% for namespace in proto_file.get_namespaces()|reverse %}
+} // End of namespace {{ namespace }}
+{% endfor %}
+#endif // _{{proto_file.get_header_guard()}}_H_

+ 35 - 0
generator/templates/TypeDefEnum.h

@@ -0,0 +1,35 @@
+{#
+Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+
+This file is part of Embedded Proto.
+
+Embedded Proto is open source software: you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published
+by the Free Software Foundation, version 3 of the license.
+
+Embedded Proto  is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+
+For commercial and closed source application please visit:
+<https://EmbeddedProto.com/license/>.
+
+Embedded AMS B.V.
+Info:
+  info at EmbeddedProto dot com
+
+Postal address:
+  Johan Huizingalaan 763a
+  1066 VH, Amsterdam
+  the Netherlands
+#}
+enum {{ typedef.name }}
+{
+  {% for value in typedef.values() %}
+  {{ value.name }} = {{ value.number }}{{ "," if not loop.last }}
+  {% endfor %}
+};

+ 200 - 0
generator/templates/TypeDefMsg.h

@@ -0,0 +1,200 @@
+{#
+Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+
+This file is part of Embedded Proto.
+
+Embedded Proto is open source software: you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published
+by the Free Software Foundation, version 3 of the license.
+
+Embedded Proto  is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+
+For commercial and closed source application please visit:
+<https://EmbeddedProto.com/license/>.
+
+Embedded AMS B.V.
+Info:
+  info at EmbeddedProto dot com
+
+Postal address:
+  Johan Huizingalaan 763a
+  1066 VH, Amsterdam
+  the Netherlands
+#}
+{% import 'TypeOneof.h' as TypeOneof %}
+{% for tmpl_param in typedef.get_templates() %}
+{{"template<" if loop.first}}{{tmpl_param['type']}} {{tmpl_param['name']}}{{", " if not loop.last}}{{">" if loop.last}}
+{% endfor %}
+class {{ typedef.get_name() }} final: public ::EmbeddedProto::MessageInterface
+{
+  public:
+    {{ typedef.get_name() }}(){% if (typedef.fields or typedef.oneofs) %} :
+    {% endif %}
+    {% for field in typedef.fields %}
+        {{field.get_variable_name()}}({{field.get_default_value()}}){{"," if not loop.last}}{{"," if loop.last and typedef.oneofs}}
+    {% endfor %}
+    {% for oneof in typedef.oneofs %}
+        {{oneof.get_which_oneof()}}(id::NOT_SET){{"," if not loop.last}}
+    {% endfor %}
+    {
+
+    };
+    ~{{ typedef.get_name() }}() override = default;
+
+    {% for enum in typedef.nested_enum_definitions %}
+    {{ enum.render(environment)|indent(4) }}
+
+    {% endfor %}
+    {% for msg in typedef.nested_msg_definitions %}
+    {{ msg.render(environment)|indent(4) }}
+
+    {% endfor %}
+    enum class id
+    {
+      NOT_SET = 0,
+      {% for id_set in typedef.field_ids %}
+      {{id_set[1]}} = {{id_set[0]}}{{ "," if not loop.last }}
+      {% endfor %}
+    };
+
+    {{ typedef.name }}& operator=(const {{ typedef.name }}& rhs)
+    {
+      {% for field in typedef.fields %}
+      set_{{ field.get_name() }}(rhs.get_{{ field.get_name() }}());
+      {% endfor %}
+      {% for oneof in typedef.oneofs %}
+      {{ TypeOneof.assign(oneof)|indent(6) }}
+      {% endfor %}
+      return *this;
+    }
+
+    {% for field in typedef.fields %}
+    {{ field.render_get_set(environment)|indent(4) }}
+
+    {% endfor %}
+    {% for oneof in typedef.oneofs %}
+    id get_which_{{oneof.get_name()}}() const { return {{oneof.get_which_oneof()}}; }
+
+    {% for field in oneof.fields %}
+    {{ field.render_get_set(environment)|indent(4) }}
+
+    {% endfor %}
+    {% endfor %}
+
+    ::EmbeddedProto::Error serialize(::EmbeddedProto::WriteBufferInterface& buffer) const final
+    {
+      ::EmbeddedProto::Error return_value = ::EmbeddedProto::Error::NO_ERRORS;
+
+      {% for field in typedef.fields %}
+      {{ field.render_serialize(environment)|indent(6) }}
+
+      {% endfor %}
+      {% for oneof in typedef.oneofs %}
+      switch({{oneof.get_which_oneof()}})
+      {
+        {% for field in oneof.get_fields() %}
+        case id::{{field.variable_id_name}}:
+          {{ field.render_serialize(environment)|indent(10) }}
+          break;
+
+        {% endfor %}
+        default:
+          break;
+      }
+
+      {% endfor %}
+      return return_value;
+    };
+
+    ::EmbeddedProto::Error deserialize(::EmbeddedProto::ReadBufferInterface& buffer) final
+    {
+      ::EmbeddedProto::Error return_value = ::EmbeddedProto::Error::NO_ERRORS;
+      ::EmbeddedProto::WireFormatter::WireType wire_type;
+      uint32_t id_number = 0;
+
+      ::EmbeddedProto::Error tag_value = ::EmbeddedProto::WireFormatter::DeserializeTag(buffer, wire_type, id_number);
+      while((::EmbeddedProto::Error::NO_ERRORS == return_value) && (::EmbeddedProto::Error::NO_ERRORS == tag_value))
+      {
+        switch(id_number)
+        {
+          {% for field in typedef.fields %}
+          case static_cast<uint32_t>(id::{{field.get_variable_id_name()}}):
+          {
+            {{ field.render_deserialize(environment)|indent(12) }}
+            break;
+          }
+
+          {% endfor %}
+          {% for oneof in typedef.oneofs %}
+          {% for field in oneof.get_fields() %}
+          case static_cast<uint32_t>(id::{{field.get_variable_id_name()}}):
+          {
+            {{ field.render_deserialize(environment)|indent(12) }}
+            break;
+          }
+
+          {% endfor %}
+          {% endfor %}
+          default:
+            break;
+        }
+
+        if(::EmbeddedProto::Error::NO_ERRORS == return_value)
+        {
+            // Read the next tag.
+            tag_value = ::EmbeddedProto::WireFormatter::DeserializeTag(buffer, wire_type, id_number);
+        }
+      }
+
+      // When an error was detect while reading the tag but no other errors where found, set it in the return value.
+      if((::EmbeddedProto::Error::NO_ERRORS == return_value)
+         && (::EmbeddedProto::Error::NO_ERRORS != tag_value)
+         && (::EmbeddedProto::Error::END_OF_BUFFER != tag_value)) // The end of the buffer is not an array in this case.
+      {
+        return_value = tag_value;
+      }
+
+      return return_value;
+    };
+
+    void clear() final
+    {
+      {% for field in typedef.fields %}
+      clear_{{field.get_name()}}();
+      {% endfor %}
+      {% for oneof in typedef.oneofs %}
+      clear_{{oneof.get_name()}}();
+      {% endfor %}
+
+    }
+
+    private:
+
+      {% for field in typedef.fields %}
+      {{field.get_type()}} {{field.get_variable_name()}};
+      {% endfor %}
+
+      {% for oneof in typedef.oneofs %}
+      id {{oneof.get_which_oneof()}};
+      union {{oneof.get_name()}}
+      {
+        {{oneof.get_name()}}() {}
+        ~{{oneof.get_name()}}() {}
+        {% for field in oneof.fields %}
+        {# Here we use the field name variable instead of the get_ function as the get function will add the oneof
+           name. This is the only place where this is required. #}
+        {{field.get_type()}} {{field.variable_name}};
+        {% endfor %}
+      };
+      {{oneof.get_name()}} {{oneof.get_variable_name()}};
+
+      {{ TypeOneof.init(oneof)|indent(6) }}
+      {{ TypeOneof.clear(oneof)|indent(6) }}
+      {% endfor %}
+};

+ 106 - 0
generator/templates/TypeOneof.h

@@ -0,0 +1,106 @@
+{#
+Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+
+This file is part of Embedded Proto.
+
+Embedded Proto is open source software: you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published
+by the Free Software Foundation, version 3 of the license.
+
+Embedded Proto  is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+
+For commercial and closed source application please visit:
+<https://EmbeddedProto.com/license/>.
+
+Embedded AMS B.V.
+Info:
+  info at EmbeddedProto dot com
+
+Postal address:
+  Johan Huizingalaan 763a
+  1066 VH, Amsterdam
+  the Netherlands
+#}
+{% macro assign(_oneof) %}
+if(rhs.get_which_{{_oneof.get_name()}}() != {{_oneof.get_which_oneof()}})
+{
+  // First delete the old object in the oneof.
+  clear_{{_oneof.get_name()}}();
+}
+
+switch(rhs.get_which_{{_oneof.get_name()}}())
+{
+  {% for field in _oneof.get_fields() %}
+  case id::{{field.get_variable_id_name()}}:
+    set_{{field.get_name()}}(rhs.get_{{field.name}}());
+    break;
+
+  {% endfor %}
+  default:
+    break;
+}
+{% endmacro %}
+{# #}
+{# ------------------------------------------------------------------------------------------------------------------ #}
+{# #}
+{% macro init(_oneof) %}
+void init_{{_oneof.get_name()}}(const id field_id)
+{
+  if(id::NOT_SET != {{_oneof.get_which_oneof()}})
+  {
+    // First delete the old object in the oneof.
+    clear_{{_oneof.get_name()}}();
+  }
+
+  {% if _oneof.oneof_allocation_required() %}
+  // C++11 unions only support nontrivial members when you explicitly call the placement new statement.
+  switch(field_id)
+  {
+    {% for field in _oneof.get_fields() %}
+    {% if field.oneof_allocation_required() %}
+    case id::{{field.get_variable_id_name()}}:
+      new(&{{field.get_variable_name()}}) {{field.get_type()}};
+      {{_oneof.get_which_oneof()}} = id::{{field.get_variable_id_name()}};
+      break;
+
+    {% endif %}
+    {% endfor %}
+    default:
+      break;
+   }
+
+   {% endif %}
+   {{_oneof.get_which_oneof()}} = field_id;
+}
+{% endmacro %}
+{# #}
+{# ------------------------------------------------------------------------------------------------------------------ #}
+{# #}
+{% macro clear(_oneof) %}
+void clear_{{_oneof.get_name()}}()
+{
+  switch({{_oneof.get_which_oneof()}})
+  {
+    {% for field in _oneof.get_fields() %}
+    case id::{{field.get_variable_id_name()}}:
+      {% if field.oneof_allocation_required() %}
+      {{field.get_variable_name()}}.~{{field.get_short_type()}}();
+	  {% elif field.of_type_enum %}
+	  {{field.get_variable_name()}} = {{field.get_default_value()}};
+      {% else %}
+      {{field.get_variable_name()}}.set(0);
+      {% endif %}
+      break;
+    {% endfor %}
+    default:
+      break;
+  }
+  {{_oneof.get_which_oneof()}} = id::NOT_SET;
+}
+{% endmacro %}

+ 12 - 9
src/FieldStringBytes.h

@@ -45,8 +45,10 @@ namespace EmbeddedProto
   namespace internal
   {
 
+    class BaseStringBytes : public Field {};
+
     template<uint32_t MAX_LENGTH, class DATA_TYPE>
-    class FieldStringBytes : public Field
+    class FieldStringBytes : public BaseStringBytes
     {
       static_assert(std::is_same<uint8_t, DATA_TYPE>::value || std::is_same<char, DATA_TYPE>::value, 
                     "This class only supports unit8_t or chars.");
@@ -151,6 +153,10 @@ namespace EmbeddedProto
                                                     WireFormatter::WireType::LENGTH_DELIMITED);
               return_value = WireFormatter::SerializeVarint(tag, buffer);
               if(Error::NO_ERRORS == return_value) 
+              {
+                return_value = WireFormatter::SerializeVarint(current_length_, buffer);
+              }
+              if(Error::NO_ERRORS == return_value) 
               {
                 return_value = serialize(buffer);
               }
@@ -166,15 +172,12 @@ namespace EmbeddedProto
 
         Error serialize(WriteBufferInterface& buffer) const override 
         { 
-          Error return_value = WireFormatter::SerializeVarint(current_length_, buffer);
-          if(Error::NO_ERRORS == return_value) 
+          Error return_value = Error::NO_ERRORS;
+          const void* void_pointer = static_cast<const void*>(&(data_[0]));
+          const uint8_t* byte_pointer = static_cast<const uint8_t*>(void_pointer);
+          if(!buffer.push(byte_pointer, current_length_))
           {
-            const void* void_pointer = static_cast<const void*>(&(data_[0]));
-            const uint8_t* byte_pointer = static_cast<const uint8_t*>(void_pointer);
-            if(!buffer.push(byte_pointer, current_length_))
-            {
-              return_value = Error::BUFFER_FULL;
-            }
+            return_value = Error::BUFFER_FULL;
           }
           return return_value;
         }

+ 1 - 1
src/MessageInterface.cpp

@@ -37,7 +37,7 @@ namespace EmbeddedProto
   Error MessageInterface::MessageInterface::serialize_with_id(uint32_t field_number, ::EmbeddedProto::WriteBufferInterface& buffer) const
   {
     const uint32_t size_x = this->serialized_size();
-    bool result = (size_x < buffer.get_available_size());
+    bool result = (size_x <= buffer.get_available_size());
     Error return_value = result ? Error::NO_ERRORS : Error::BUFFER_FULL;
     if(result && (0 < size_x))
     {

+ 77 - 38
src/RepeatedField.h

@@ -34,7 +34,8 @@
 #include "Fields.h"
 #include "MessageInterface.h"
 #include "MessageSizeCalculator.h"
-#include "ReadBufferSection.h" 
+#include "ReadBufferSection.h"
+#include "FieldStringBytes.h"
 #include "Errors.h"
 
 #include <cstdint>
@@ -51,7 +52,9 @@ namespace EmbeddedProto
     static_assert(std::is_base_of<::EmbeddedProto::Field, DATA_TYPE>::value, "A Field can only be used as template paramter.");
 
     //! Check how this field shoeld be serialized, packed or not.
-    static constexpr bool PACKED = !std::is_base_of<MessageInterface, DATA_TYPE>::value;
+    static constexpr bool REPEATED_FIELD_IS_PACKED = 
+          !(std::is_base_of<MessageInterface, DATA_TYPE>::value 
+            || std::is_base_of<internal::BaseStringBytes, DATA_TYPE>::value);
 
     public:
 
@@ -134,7 +137,7 @@ namespace EmbeddedProto
       {
         Error return_value = Error::NO_ERRORS;
 
-        if(PACKED)
+        if(REPEATED_FIELD_IS_PACKED)
         {
           const uint32_t size_x = this->serialized_size_packed(field_number);
 
@@ -164,8 +167,14 @@ namespace EmbeddedProto
         else 
         {
           const uint32_t size_x = this->serialized_size_unpacked(field_number);
-          return_value = (size_x <= buffer.get_available_size()) ? serialize_unpacked(field_number, buffer) 
-                                                                 : Error::BUFFER_FULL;
+          if(size_x <= buffer.get_available_size()) 
+          {
+            return_value = serialize_unpacked(field_number, buffer);
+          }
+          else 
+          {
+            return_value = Error::BUFFER_FULL;
+          }
         }
 
         return return_value;
@@ -180,43 +189,13 @@ namespace EmbeddedProto
       Error deserialize(::EmbeddedProto::ReadBufferInterface& buffer) final
       {
         Error return_value = Error::NO_ERRORS;
-        if(PACKED)
+        if(REPEATED_FIELD_IS_PACKED)
         {              
-          uint32_t size;
-          return_value = WireFormatter::DeserializeVarint(buffer, size);
-          ReadBufferSection bufferSection(buffer, size);
-          DATA_TYPE x;
-          
-          return_value = x.deserialize(bufferSection);
-          while(Error::NO_ERRORS == return_value)
-          {
-            return_value = this->add(x);
-            if(Error::NO_ERRORS == return_value)
-            {
-              return_value = x.deserialize(bufferSection);
-            }
-          }
-
-          // We expect the buffersection to be empty, in that case everything is fine..
-          if(Error::END_OF_BUFFER == return_value)
-          {
-            return_value = Error::NO_ERRORS;
-          }
+          return_value = deserialize_packed(buffer);
         }
         else 
         {
-          uint32_t size;
-          return_value = WireFormatter::DeserializeVarint(buffer, size);
-          if(Error::NO_ERRORS == return_value) 
-          {
-            ReadBufferSection bufferSection(buffer, size);
-            DATA_TYPE x;
-            return_value = x.deserialize(bufferSection);
-            if(Error::NO_ERRORS == return_value)
-            {
-              return_value = this->add(x);
-            }
-          }
+          return_value = deserialize_unpacked(buffer);
         }
         return return_value;
       }
@@ -277,6 +256,66 @@ namespace EmbeddedProto
         return return_value;
       }
 
+      Error deserialize_packed(ReadBufferInterface& buffer)
+      {
+        uint32_t size;
+        Error return_value = WireFormatter::DeserializeVarint(buffer, size);
+        ReadBufferSection bufferSection(buffer, size);
+        DATA_TYPE x;
+        
+        return_value = x.deserialize(bufferSection);
+        while(Error::NO_ERRORS == return_value)
+        {
+          return_value = this->add(x);
+          if(Error::NO_ERRORS == return_value)
+          {
+            return_value = x.deserialize(bufferSection);
+          }
+        }
+
+        // We expect the buffersection to be empty, in that case everything is fine..
+        if(Error::END_OF_BUFFER == return_value)
+        {
+          return_value = Error::NO_ERRORS;
+        }
+
+        return return_value;
+      }
+
+      Error deserialize_unpacked(ReadBufferInterface& buffer)
+      {
+        Error return_value = Error::NO_ERRORS;
+
+        // For repeated messages, strings or bytes
+        // First allocate an element in the array.
+        const uint32_t index = this->get_length();
+        if(this->get_max_length() > index)
+        {
+          // For messages read the size here, with strings and byte arrays this is include in 
+          // deserialize.
+          if(std::is_base_of<MessageInterface, DATA_TYPE>::value)
+          {
+            uint32_t size;
+            return_value = WireFormatter::DeserializeVarint(buffer, size);
+            if(Error::NO_ERRORS == return_value) 
+            {
+              ReadBufferSection bufferSection(buffer, size);
+              return_value = this->get(index).deserialize(bufferSection);
+            }
+          }
+          else 
+          {
+            return_value = this->get(index).deserialize(buffer);
+          }
+        }
+        else 
+        {
+          return_value = Error::ARRAY_FULL;
+        }
+
+        return return_value;
+      }
+
   };
 
 

+ 20 - 2
src/RepeatedFieldFixedSize.h

@@ -63,6 +63,19 @@ namespace EmbeddedProto
 
       ~RepeatedFieldFixedSize() override = default;
 
+      //! Assign one repieted field to the other, but only when the length and type matches.
+      RepeatedFieldFixedSize<DATA_TYPE, MAX_LENGTH>& operator=(const 
+                                                RepeatedFieldFixedSize<DATA_TYPE, MAX_LENGTH>& rhs)
+      {
+        for(uint32_t i = 0; i < rhs.get_length(); ++i) 
+        {
+          data_[i] = rhs.get_const(i);
+        }
+        current_length_ = rhs.get_length();
+        
+        return *this;
+      }
+
       //! Obtain the total number of DATA_TYPE items in the array.
       uint32_t get_length() const override { return current_length_; }
 
@@ -106,8 +119,13 @@ namespace EmbeddedProto
         Error return_value = Error::NO_ERRORS;
         if(MAX_LENGTH >= length) 
         {
-          current_length_ = length;
-          memcpy(data_, data, length * BYTES_PER_ELEMENT);
+          const DATA_TYPE* d = data;
+          for(uint32_t i = 0; i < length; ++i) 
+          {
+            data_[i] = *d;
+            ++d;
+          }
+          current_length_ = length;        
         }
         else 
         {

+ 123 - 107
src/WireFormatter.h

@@ -54,6 +54,20 @@ namespace EmbeddedProto
       //! Definition of a mask indicating the most significant bit used in varint encoding.
       static constexpr uint8_t VARINT_MSB_BYTE = 0x80;
 
+      //! Convert the floating point number to the next highes integer.
+      /*!
+        The ceil function in std is not a constexpr. Some compilers doe not accept this.
+
+        \param num The value you would like ot convert.
+        \return The resulting integer. 
+      */
+      static constexpr int32_t constexpr_ceil(float num)
+      {
+          return (static_cast<float>(static_cast<int32_t>(num)) == num)
+              ? static_cast<int32_t>(num)
+              : static_cast<int32_t>(num) + ((num > 0) ? 1 : 0);
+      }
+
     public:
       //! Definitions of the different encoding types used in protobuf.
       enum class WireType 
@@ -66,6 +80,114 @@ namespace EmbeddedProto
         FIXED32           = 5,  //!< fixed32, sfixed32, float
       };
 
+      //! Encode a signed integer using the zig zag method
+      /*!
+        As specified the right-shift must be arithmetic, hence the cast is after the shift. The 
+        left shift must be unsigned because of overflow.
+
+        This function is suitable for 32 and 64 bit.
+
+        \param[in] n The signed value to be encoded.
+        \return The zig zag transformed value ready for serialization into the array.
+      */
+      template<class INT_TYPE>
+      static constexpr auto ZigZagEncode(const INT_TYPE n) 
+      {
+        static_assert(std::is_same<INT_TYPE, int32_t>::value || 
+                      std::is_same<INT_TYPE, int64_t>::value, "Wrong type passed to ZigZagEncode.");
+
+        typedef typename std::make_unsigned<INT_TYPE>::type UINT_TYPE;
+        constexpr uint8_t N_BITS_TO_ZIGZAG = std::numeric_limits<UINT_TYPE>::digits - 1;
+
+        return (static_cast<UINT_TYPE>(n) << 1) ^ static_cast<UINT_TYPE>(n >> N_BITS_TO_ZIGZAG);
+      }
+
+      //! Decode a signed integer using the zig zag method
+      /*!
+          \param[in] n The value encoded in zig zag to be decoded.
+          \return The decoded signed value.
+
+          This function is suitable for 32 and 64 bit.
+      */
+      template<class UINT_TYPE>
+      static constexpr auto ZigZagDecode(const UINT_TYPE n) 
+      {
+        static_assert(std::is_same<UINT_TYPE, uint32_t>::value || 
+                      std::is_same<UINT_TYPE, uint64_t>::value, "Wrong type passed to ZigZagDecode.");
+
+        typedef typename std::make_signed<UINT_TYPE>::type INT_TYPE;
+
+        return static_cast<INT_TYPE>((n >> 1) ^ (~(n & 1) + 1));
+      }
+
+      //! Create the tag of a field. 
+      /*!
+        This is the combination of the field number and wire type of the field. The field number is 
+        shifted to the left by three bits. This creates space to or the wire type of the designated 
+        field.
+      */
+      static constexpr uint32_t MakeTag(const uint32_t field_number, const WireType type)
+      {
+        return ((field_number << 3) | static_cast<uint32_t>(type));
+      }
+
+      /**
+         @brief Serialize fields, without tags the given buffer.
+         @{
+      **/
+
+      //! Serialize an unsigned fixed length field without the tag.
+      template<class UINT_TYPE>
+      static Error SerialzieFixedNoTag(UINT_TYPE value, WriteBufferInterface& buffer) 
+      {
+        static_assert(std::is_same<UINT_TYPE, uint32_t>::value || 
+                      std::is_same<UINT_TYPE, uint64_t>::value, "Wrong type passed to SerialzieFixedNoTag.");
+
+        // Push the data little endian to the buffer.
+        // TODO Define a little endian flag to support memcpy the data to the buffer.
+
+        bool result = true;
+
+        // Loop over all bytes in the integer.
+        for(uint8_t i = 0; (i < std::numeric_limits<UINT_TYPE>::digits) && result; i += 8) {
+          // Shift the value using the current value of i.
+          result = buffer.push(static_cast<uint8_t>((value >> i) & 0x00FF));
+        }
+        return result ? Error::NO_ERRORS : Error::BUFFER_FULL;
+      }
+
+      //! Serialize a signed fixed length field without the tag.
+      template<class INT_TYPE>
+      static Error SerialzieSFixedNoTag(INT_TYPE value, WriteBufferInterface& buffer)
+      {
+        static_assert(std::is_same<INT_TYPE, int32_t>::value || 
+                      std::is_same<INT_TYPE, int64_t>::value, "Wrong type passed to SerialzieSFixedNoTag.");
+
+        typedef typename std::make_unsigned<INT_TYPE>::type UINT_TYPE;
+
+        return SerialzieFixedNoTag(static_cast<UINT_TYPE>(value), buffer);
+      }
+
+      //! Serialize a 32bit real value without tag.
+      static Error SerialzieFloatNoTag(float value, WriteBufferInterface& buffer)
+      {
+        // Cast the type to void and to a 32 fixed number
+        void* pVoid = static_cast<void*>(&value);
+        uint32_t* fixed = static_cast<uint32_t*>(pVoid);
+        return SerialzieFixedNoTag(*fixed, buffer);
+      }
+
+      //! Serialize a 64bit real value without tag.
+      static Error SerialzieDoubleNoTag(double value, WriteBufferInterface& buffer)
+      {
+        // Cast the type to void and to a 64 fixed number
+        void* pVoid = static_cast<void*>(&value);
+        uint64_t* fixed = static_cast<uint64_t*>(pVoid);
+        return SerialzieFixedNoTag(*fixed, buffer);
+      }
+      /** @} **/
+
+
       /**
          @brief Serialize fields, including tags to the given buffer.
          @{
@@ -413,7 +535,7 @@ namespace EmbeddedProto
         
         // Calculate how many bytes there are in a varint 128 base encoded number. This should 
         // yield 5 for a 32bit number and 10 for a 64bit number.
-        static constexpr uint8_t N_BYTES_IN_VARINT = static_cast<uint8_t>(std::ceil(
+        static constexpr uint8_t N_BYTES_IN_VARINT = static_cast<uint8_t>(constexpr_ceil(
                                                           std::numeric_limits<UINT_TYPE>::digits 
                                                         / static_cast<float>(VARINT_SHIFT_N_BITS)));
         
@@ -449,112 +571,6 @@ namespace EmbeddedProto
         return return_value;
       }
 
-      //! Encode a signed integer using the zig zag method
-      /*!
-        As specified the right-shift must be arithmetic, hence the cast is after the shift. The 
-        left shift must be unsigned because of overflow.
-
-        This function is suitable for 32 and 64 bit.
-
-        \param[in] n The signed value to be encoded.
-        \return The zig zag transformed value ready for serialization into the array.
-      */
-      template<class INT_TYPE>
-      static constexpr auto ZigZagEncode(const INT_TYPE n) 
-      {
-        static_assert(std::is_same<INT_TYPE, int32_t>::value || 
-                      std::is_same<INT_TYPE, int64_t>::value, "Wrong type passed to ZigZagEncode.");
-
-        typedef typename std::make_unsigned<INT_TYPE>::type UINT_TYPE;
-        constexpr uint8_t N_BITS_TO_ZIGZAG = std::numeric_limits<UINT_TYPE>::digits - 1;
-
-        return (static_cast<UINT_TYPE>(n) << 1) ^ static_cast<UINT_TYPE>(n >> N_BITS_TO_ZIGZAG);
-      }
-
-      //! Decode a signed integer using the zig zag method
-      /*!
-          \param[in] n The value encoded in zig zag to be decoded.
-          \return The decoded signed value.
-
-          This function is suitable for 32 and 64 bit.
-      */
-      template<class UINT_TYPE>
-      static constexpr auto ZigZagDecode(const UINT_TYPE n) 
-      {
-        static_assert(std::is_same<UINT_TYPE, uint32_t>::value || 
-                      std::is_same<UINT_TYPE, uint64_t>::value, "Wrong type passed to ZigZagDecode.");
-
-        typedef typename std::make_signed<UINT_TYPE>::type INT_TYPE;
-
-        return static_cast<INT_TYPE>((n >> 1) ^ (~(n & 1) + 1));
-      }
-
-      //! Create the tag of a field. 
-      /*!
-        This is the combination of the field number and wire type of the field. The field number is 
-        shifted to the left by three bits. This creates space to or the wire type of the designated 
-        field.
-      */
-      static constexpr uint32_t MakeTag(const uint32_t field_number, const WireType type)
-      {
-        return ((static_cast<uint32_t>(field_number) << 3) | static_cast<uint32_t>(type));
-      }
-
-      /**
-         @brief Serialize fields, without tags the given buffer.
-         @{
-      **/
-
-      //! Serialize an unsigned fixed length field without the tag.
-      template<class UINT_TYPE>
-      static Error SerialzieFixedNoTag(UINT_TYPE value, WriteBufferInterface& buffer) 
-      {
-        static_assert(std::is_same<UINT_TYPE, uint32_t>::value || 
-                      std::is_same<UINT_TYPE, uint64_t>::value, "Wrong type passed to SerialzieFixedNoTag.");
-
-        // Push the data little endian to the buffer.
-        // TODO Define a little endian flag to support memcpy the data to the buffer.
-
-        bool result = true;
-
-        // Loop over all bytes in the integer.
-        for(uint8_t i = 0; (i < std::numeric_limits<UINT_TYPE>::digits) && result; i += 8) {
-          // Shift the value using the current value of i.
-          result = buffer.push(static_cast<uint8_t>((value >> i) & 0x00FF));
-        }
-        return result ? Error::NO_ERRORS : Error::BUFFER_FULL;
-      }
-
-      //! Serialize a signed fixed length field without the tag.
-      template<class INT_TYPE>
-      static Error SerialzieSFixedNoTag(INT_TYPE value, WriteBufferInterface& buffer)
-      {
-        static_assert(std::is_same<INT_TYPE, int32_t>::value || 
-                      std::is_same<INT_TYPE, int64_t>::value, "Wrong type passed to SerialzieSFixedNoTag.");
-
-        typedef typename std::make_unsigned<INT_TYPE>::type UINT_TYPE;
-
-        return SerialzieFixedNoTag(static_cast<UINT_TYPE>(value), buffer);
-      }
-
-      //! Serialize a 32bit real value without tag.
-      static Error SerialzieFloatNoTag(float value, WriteBufferInterface& buffer)
-      {
-        // Cast the type to void and to a 32 fixed number
-        void* pVoid = static_cast<void*>(&value);
-        uint32_t* fixed = static_cast<uint32_t*>(pVoid);
-        return SerialzieFixedNoTag(*fixed, buffer);
-      }
-
-      //! Serialize a 64bit real value without tag.
-      static Error SerialzieDoubleNoTag(double value, WriteBufferInterface& buffer)
-      {
-        // Cast the type to void and to a 64 fixed number
-        void* pVoid = static_cast<void*>(&value);
-        uint64_t* fixed = static_cast<uint64_t*>(pVoid);
-        return SerialzieFixedNoTag(*fixed, buffer);
-      }
-      /** @} **/
 
   };
 

+ 37 - 0
test/proto/empty_message.proto

@@ -0,0 +1,37 @@
+/*
+ *  Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+ *
+ *  This file is part of Embedded Proto.
+ *
+ *  Embedded Proto is open source software: you can redistribute it and/or 
+ *  modify it under the terms of the GNU General Public License as published 
+ *  by the Free Software Foundation, version 3 of the license.
+ *
+ *  Embedded Proto  is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+ *
+ *  For commercial and closed source application please visit:
+ *  <https://EmbeddedProto.com/license/>.
+ *
+ *  Embedded AMS B.V.
+ *  Info:
+ *    info at EmbeddedProto dot com
+ *
+ *  Postal address:
+ *    Johan Huizingalaan 763a
+ *    1066 VH, Amsterdam
+ *    the Netherlands
+ */
+
+// This file is used to test defining empty messages. This should not cause build errors.
+
+syntax = "proto3";
+
+message empty_message {
+  
+}

+ 5 - 0
test/proto/include_other_files.proto

@@ -38,8 +38,13 @@ import "file_to_include.proto";
 // Import something with variable length
 import "repeated_fields.proto";
 
+// Import something from a subfolder.
+import "subfolder/file_to_include_from_subfolder.proto";
+
+
 message IncludedMessages {
   some.external.lib.CommonStates  state = 1;
   some.external.lib.CommonMessage msg   = 2;
   repeated_fields rf  = 3;
+  sub.package.other_folder_msg sub_msg = 4;
 }

+ 9 - 1
test/proto/nested_message.proto

@@ -32,9 +32,11 @@
 
 syntax = "proto3";
 
+package demo.space;
+
 message message_a 
 {
-  int32 x   = 1;
+  repeated int32 x   = 1;
   float y   = 2;
   sint64 z  = 3;
 }
@@ -48,5 +50,11 @@ message message_b
 
 message message_c 
 {
+  message message_d
+  {
+    repeated uint32 d = 1;
+  }
+
   message_b nested_b = 1;
+  message_d nested_d = 2;
 }

+ 12 - 0
test/proto/oneof_fields.proto

@@ -50,11 +50,19 @@ message message_oneof
 {
   int32 a = 1;
 
+  enum States {
+    Idle = 0;
+    Run = 1;
+    Done = 2;
+    Error = 3;
+  }
+
   oneof xyz 
   {
     int32 x = 5;
     int32 y = 6;
     int32 z = 7;
+    States state = 8;
   }
 
   int32 b = 10;
@@ -72,3 +80,7 @@ message message_oneof
     some_DEF msg_DEF = 21;
   }
 }
+
+message nested_oneof {
+  message_oneof msg_oneof = 1;
+}

+ 1 - 1
test/proto/repeated_fields.proto

@@ -54,5 +54,5 @@ message repeated_message
 
 message nested_repeated_message
 {
-    repeated_message rm = 1;
+    repeated_fields rf = 1;
 }

+ 7 - 1
test/proto/string_bytes.proto

@@ -49,4 +49,10 @@ message string_or_bytes
     string txt = 1;
     bytes b = 2;
   }
-}
+}
+
+message repeated_string_bytes
+{
+  repeated string array_of_txt = 1;
+  repeated bytes array_of_bytes = 2;
+}

+ 41 - 0
test/proto/subfolder/file_to_include_from_subfolder.proto

@@ -0,0 +1,41 @@
+/*
+ *  Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+ *
+ *  This file is part of Embedded Proto.
+ *
+ *  Embedded Proto is open source software: you can redistribute it and/or 
+ *  modify it under the terms of the GNU General Public License as published 
+ *  by the Free Software Foundation, version 3 of the license.
+ *
+ *  Embedded Proto  is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+ *
+ *  For commercial and closed source application please visit:
+ *  <https://EmbeddedProto.com/license/>.
+ *
+ *  Embedded AMS B.V.
+ *  Info:
+ *    info at EmbeddedProto dot com
+ *
+ *  Postal address:
+ *    Johan Huizingalaan 763a
+ *    1066 VH, Amsterdam
+ *    the Netherlands
+ */
+
+// This file is used to test including other proto files particular from a subfolder.
+
+syntax = "proto3";
+
+package sub.package;
+
+message other_folder_msg {
+  int32 val = 1;
+  repeated int32 array = 2;
+}
+

+ 4 - 3
test/test_IncludeOtherFiles.cpp

@@ -51,13 +51,14 @@ namespace test_EmbeddedAMS_IncludeOtherFiles
 {
 
 static constexpr uint32_t RF_SIZE = 3;
+static constexpr uint32_t ARRAY_SIZE = 2;
 
 TEST(IncludeOtherFiles, zero) 
 {
   InSequence s;
 
   // See if an empty message results in no data been pushed.
-  ::IncludedMessages<RF_SIZE> msg;
+  ::IncludedMessages<RF_SIZE, ARRAY_SIZE> msg;
   Mocks::WriteBufferMock buffer;
 
   EXPECT_CALL(buffer, push(_)).Times(0);
@@ -73,7 +74,7 @@ TEST(IncludeOtherFiles, set)
 {
   InSequence s;
 
-  ::IncludedMessages<RF_SIZE> msg;
+  ::IncludedMessages<RF_SIZE, ARRAY_SIZE> msg;
   Mocks::WriteBufferMock buffer;
 
   msg.set_state(some::external::lib::CommonStates::StateA);
@@ -116,7 +117,7 @@ TEST(IncludeOtherFiles, get)
 {
   InSequence s;
 
-  ::IncludedMessages<RF_SIZE> msg;
+  ::IncludedMessages<RF_SIZE, ARRAY_SIZE> msg;
   Mocks::ReadBufferMock buffer;
   ON_CALL(buffer, get_size()).WillByDefault(Return(22));
 

+ 59 - 32
test/test_NestedMessage.cpp

@@ -49,11 +49,14 @@ using ::testing::SetArgReferee;
 namespace test_EmbeddedAMS_NestedMessage
 {
 
+constexpr uint32_t SIZE_MSG_A = 3;
+constexpr uint32_t SIZE_MSG_D = 5;
+
 TEST(NestedMessage, serialize_zero) 
 {
   // Test if a unset message results in zero bytes in the buffer.
 
-  ::message_b msg;
+  ::demo::space::message_b<SIZE_MSG_A> msg;
   Mocks::WriteBufferMock buffer;
   EXPECT_CALL(buffer, push(_)).Times(0);
   EXPECT_CALL(buffer, push(_,_)).Times(0);
@@ -68,14 +71,14 @@ TEST(NestedMessage, serialize_one)
 {
   InSequence s;
 
-  ::message_b msg;
+  ::demo::space::message_b<SIZE_MSG_A> msg;
   Mocks::WriteBufferMock buffer;
-  ON_CALL(buffer, get_size()).WillByDefault(Return(9));
+  ON_CALL(buffer, get_size()).WillByDefault(Return(25));
 
 
   // Test if a nested message can be serialized with values set to one.
   msg.set_u(1.0F);
-  msg.mutable_nested_a().set_x(1);
+  msg.mutable_nested_a().add_x(1);
   msg.mutable_nested_a().set_y(1.0F);
   msg.mutable_nested_a().set_z(1);
   msg.set_v(1);
@@ -87,10 +90,16 @@ TEST(NestedMessage, serialize_one)
   }
 
   // When called the buffer will have enough space for the message
-  EXPECT_CALL(buffer, get_available_size()).Times(1).WillOnce(Return(10));
+  EXPECT_CALL(buffer, get_available_size()).Times(1).WillOnce(Return(11));
+
+  // tag and size of nested a
+  EXPECT_CALL(buffer, push(0x12)).Times(1).WillOnce(Return(true));
+  EXPECT_CALL(buffer, push(0x0A)).Times(1).WillOnce(Return(true));
+
+  // The next call is for the repeated field x.
+  EXPECT_CALL(buffer, get_available_size()).Times(1).WillOnce(Return(9));
 
-  uint8_t expected_a[] = {0x12, 0x09, // tag and size of nested a
-                          0x08, 0x01, // x
+  uint8_t expected_a[] = {0x0A, 0x01, 0x01, // x
                           0x15, 0x00, 0x00, 0x80, 0x3f, // y
                           0x18, 0x02, // z
                           0x18, 0x01};// And back to the parent message with field v.
@@ -102,34 +111,41 @@ TEST(NestedMessage, serialize_one)
 
   EXPECT_EQ(::EmbeddedProto::Error::NO_ERRORS, msg.serialize(buffer));
 
-  EXPECT_EQ(22, msg.serialized_size());
+  EXPECT_EQ(23, msg.serialized_size());
 }
 
 TEST(NestedMessage, serialize_max) 
 {
   InSequence s;
 
-  ::message_b msg;
+  ::demo::space::message_b<SIZE_MSG_A> msg;
   Mocks::WriteBufferMock buffer;
 
   // Test if a nested message can be serialized with values set to one.
   msg.set_u(std::numeric_limits<double>::max());
-  msg.mutable_nested_a().set_x(std::numeric_limits<int32_t>::max());
+  msg.mutable_nested_a().add_x(std::numeric_limits<int32_t>::max());
   msg.mutable_nested_a().set_y(std::numeric_limits<float>::max());
   msg.mutable_nested_a().set_z(std::numeric_limits<int64_t>::max());
   msg.set_v(std::numeric_limits<int32_t>::max());
 
   uint8_t expected_b[] = {0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x7F}; // u
 
+
   for(auto e : expected_b) {
     EXPECT_CALL(buffer, push(e)).Times(1).WillOnce(Return(true));
   }
 
   // When called the buffer will have enough space for the message
-  EXPECT_CALL(buffer, get_available_size()).Times(1).WillOnce(Return(23));
+  EXPECT_CALL(buffer, get_available_size()).Times(1).WillOnce(Return(31));
+
+  // tag and size of nested a
+  EXPECT_CALL(buffer, push(0x12)).Times(1).WillOnce(Return(true));
+  EXPECT_CALL(buffer, push(0x17)).Times(1).WillOnce(Return(true));
 
-  uint8_t expected_a[] = {0x12, 0x16, // tag and size of nested a
-                          0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, // x
+  // The next call is for the repeated field x.
+  EXPECT_CALL(buffer, get_available_size()).Times(1).WillOnce(Return(11));
+
+  uint8_t expected_a[] = {0x0A, 0x05, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, // x
                           0x15, 0xFF, 0xFF, 0x7F, 0x7F, // y
                           0x18, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, // z
                           // And back to the parent message with field v.
@@ -141,26 +157,26 @@ TEST(NestedMessage, serialize_max)
 
   EXPECT_EQ(::EmbeddedProto::Error::NO_ERRORS, msg.serialize(buffer));
 
-  EXPECT_EQ(39, msg.serialized_size());
+  EXPECT_EQ(40, msg.serialized_size());
 }
 
 TEST(NestedMessage, serialize_nested_in_nested_max) 
 {
   InSequence s;
 
-  ::message_c msg;
+  ::demo::space::message_c<SIZE_MSG_A, SIZE_MSG_D> msg;
   Mocks::WriteBufferMock buffer;
 
   // Test if a nested message in a nested message with some data works.
   msg.mutable_nested_b().set_u(std::numeric_limits<double>::max());
-  msg.mutable_nested_b().mutable_nested_a().set_x(std::numeric_limits<int32_t>::max());
+  msg.mutable_nested_b().mutable_nested_a().add_x(std::numeric_limits<int32_t>::max());
   msg.mutable_nested_b().mutable_nested_a().set_y(std::numeric_limits<float>::max());
   msg.mutable_nested_b().mutable_nested_a().set_z(std::numeric_limits<int64_t>::max());
   msg.mutable_nested_b().set_v(std::numeric_limits<int32_t>::max());
 
   EXPECT_CALL(buffer, get_available_size()).Times(1).WillOnce(Return(42));
 
-  uint8_t expected_b[] = {0x0A, 0x27, // tag and size of nested b
+  uint8_t expected_b[] = {0x0A, 0x28, // tag and size of nested b
                           0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x7F}; // u
 
   for(auto e : expected_b) {
@@ -168,10 +184,16 @@ TEST(NestedMessage, serialize_nested_in_nested_max)
   }
 
   // When called the buffer will have enough space for the message
-  EXPECT_CALL(buffer, get_available_size()).Times(1).WillOnce(Return(23));
+  EXPECT_CALL(buffer, get_available_size()).Times(1).WillOnce(Return(31));
+
+  // tag and size of nested a
+  EXPECT_CALL(buffer, push(0x12)).Times(1).WillOnce(Return(true));
+  EXPECT_CALL(buffer, push(0x17)).Times(1).WillOnce(Return(true));
 
-  uint8_t expected_a[] = {0x12, 0x16, // tag and size of nested a
-                          0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, // x
+  // The next call is for the repeated field x.
+  EXPECT_CALL(buffer, get_available_size()).Times(1).WillOnce(Return(11));
+
+  uint8_t expected_a[] = {0x0A, 0x05, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, // x
                           0x15, 0xFF, 0xFF, 0x7F, 0x7F, // y
                           0x18, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, // z
                           // And back to the parent message with field v.
@@ -181,6 +203,9 @@ TEST(NestedMessage, serialize_nested_in_nested_max)
     EXPECT_CALL(buffer, push(e)).Times(1).WillOnce(Return(true));
   }
 
+  // In serializing D, even if it is not set, we check the size of the buffer.
+  EXPECT_CALL(buffer, get_available_size()).Times(1).WillOnce(Return(0));
+
   EXPECT_EQ(::EmbeddedProto::Error::NO_ERRORS, msg.serialize(buffer));
 }
 
@@ -188,19 +213,19 @@ TEST(NestedMessage, deserialize_one)
 {
   InSequence s;
 
-  ::message_b msg;
+  ::demo::space::message_b<SIZE_MSG_A> msg;
   Mocks::ReadBufferMock buffer;
 
 
-  static constexpr uint32_t SIZE = 22;
+  static constexpr uint32_t SIZE = 23;
 
   ON_CALL(buffer, get_size()).WillByDefault(Return(SIZE));
 
   // Test if a nested message can be deserialized with values set to one.
 
   uint8_t referee[SIZE] = { 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, // u
-                            0x12, 0x09, // tag and size of nested a
-                            0x08, 0x01, // x
+                            0x12, 0x0A, // tag and size of nested a
+                            0x0A, 0x01, 0x01, // x
                             0x15, 0x00, 0x00, 0x80, 0x3F, // y
                             0x18, 0x02, // z
                             // And back to the parent message with field v.
@@ -214,9 +239,10 @@ TEST(NestedMessage, deserialize_one)
   EXPECT_EQ(::EmbeddedProto::Error::NO_ERRORS, msg.deserialize(buffer));
 
   EXPECT_EQ(1.0F, msg.get_u());
-  EXPECT_EQ(1, msg.get_nested_a().get_x());
+  EXPECT_EQ(1, msg.get_nested_a().get_x().get_length());
+  EXPECT_EQ(1, msg.get_nested_a().x(0));
   EXPECT_EQ(1.0F, msg.get_nested_a().get_y());
-  EXPECT_EQ(1, msg.get_nested_a().get_x());
+  EXPECT_EQ(1, msg.get_nested_a().get_z());
   EXPECT_EQ(1, msg.get_v());
 }
 
@@ -224,20 +250,20 @@ TEST(NestedMessage, deserialize_nested_in_nested_max)
 {
   InSequence s;
 
-  ::message_c msg;
+  ::demo::space::message_c<SIZE_MSG_A, SIZE_MSG_D> msg;
   Mocks::ReadBufferMock buffer;
 
 
-  static constexpr uint32_t SIZE = 41;
+  static constexpr uint32_t SIZE = 42;
 
   ON_CALL(buffer, get_size()).WillByDefault(Return(SIZE));
 
   // Test if a double nested message can be deserialized with values set to maximum.
 
-  uint8_t referee[SIZE] = { 0x0A, 0x27, // tag and size of nested b
+  uint8_t referee[SIZE] = { 0x0A, 0x28, // tag and size of nested b
                             0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x7F, // u
-                            0x12, 0x16, // tag and size of nested a
-                            0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, // x
+                            0x12, 0x17, // tag and size of nested a
+                            0x0A, 0x05, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, // x
                             0x15, 0xFF, 0xFF, 0x7F, 0x7F, // y
                             0x18, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, // z
                             // And back to the parent message with field v.
@@ -251,7 +277,8 @@ TEST(NestedMessage, deserialize_nested_in_nested_max)
   EXPECT_EQ(::EmbeddedProto::Error::NO_ERRORS, msg.deserialize(buffer));
 
   EXPECT_EQ(std::numeric_limits<double>::max(), msg.get_nested_b().get_u());
-  EXPECT_EQ(std::numeric_limits<int32_t>::max(), msg.get_nested_b().get_nested_a().get_x());
+  EXPECT_EQ(1, msg.get_nested_b().get_nested_a().get_x().get_length());
+  EXPECT_EQ(std::numeric_limits<int32_t>::max(), msg.get_nested_b().get_nested_a().x(0));
   EXPECT_EQ(std::numeric_limits<float>::max(), msg.get_nested_b().get_nested_a().get_y());
   EXPECT_EQ(std::numeric_limits<int64_t>::max(), msg.get_nested_b().get_nested_a().get_z());
   EXPECT_EQ(std::numeric_limits<int32_t>::max(), msg.get_nested_b().get_v());

+ 24 - 0
test/test_RepeatedFieldMessage.cpp

@@ -483,4 +483,28 @@ TEST(RepeatedFieldMessage, deserialize_max)
 
 }
 
+TEST(RepeatedFieldMessage, assign_a_nested_message) 
+{
+  // Assign a nested message which holds an repeated field.
+  nested_repeated_message<Y_SIZE>  top_level_msg;
+
+  // The nexted message
+  repeated_fields<Y_SIZE> nested_msg;
+
+  // Fill the array with some data.
+  nested_msg.add_y(1);
+  nested_msg.add_y(2);
+  nested_msg.add_y(3);
+
+
+  // And assign
+  top_level_msg.set_rf(nested_msg);
+  
+  EXPECT_EQ(3, top_level_msg.get_rf().get_y().get_length());
+  EXPECT_EQ(1, top_level_msg.get_rf().get_y()[0]);
+  EXPECT_EQ(2, top_level_msg.get_rf().get_y()[1]);
+  EXPECT_EQ(3, top_level_msg.get_rf().get_y()[2]);
+
+}
+
 } // End of namespace test_EmbeddedAMS_RepeatedFieldMessage

+ 45 - 0
test/test_empty_messages.cpp

@@ -0,0 +1,45 @@
+/*
+ *  Copyright (C) 2020 Embedded AMS B.V. - All Rights Reserved
+ *
+ *  This file is part of Embedded Proto.
+ *
+ *  Embedded Proto is open source software: you can redistribute it and/or 
+ *  modify it under the terms of the GNU General Public License as published 
+ *  by the Free Software Foundation, version 3 of the license.
+ *
+ *  Embedded Proto  is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Embedded Proto. If not, see <https://www.gnu.org/licenses/>.
+ *
+ *  For commercial and closed source application please visit:
+ *  <https://EmbeddedProto.com/license/>.
+ *
+ *  Embedded AMS B.V.
+ *  Info:
+ *    info at EmbeddedProto dot com
+ *
+ *  Postal address:
+ *    Johan Huizingalaan 763a
+ *    1066 VH, Amsterdam
+ *    the Netherlands
+ */
+
+#include "gtest/gtest.h"
+#include "gmock/gmock.h"
+
+#include "empty_message.h"
+
+namespace test_EmbeddedAMS_empty_messages
+{
+
+TEST(EmptyMessages, construction)
+{ 
+  // Test if using a message with no fields or enums cause build errors. 
+  empty_message empty;
+}
+
+} // End of namespace test_EmbeddedAMS_empty_messages

+ 28 - 0
test/test_oneof_fields.cpp

@@ -84,6 +84,12 @@ TEST(OneofField, set_get_clear)
   EXPECT_EQ(message_oneof::id::Z, msg.get_which_xyz());
   msg.clear_z();
 
+  EXPECT_EQ(message_oneof::id::NOT_SET, msg.get_which_xyz());
+  msg.set_state(message_oneof::States::Run);
+  EXPECT_EQ(message_oneof::States::Run, msg.get_state());
+  EXPECT_EQ(message_oneof::id::STATE, msg.get_which_xyz());
+  msg.clear_state();
+
   EXPECT_EQ(message_oneof::id::NOT_SET, msg.get_which_xyz());
 
   EXPECT_EQ(message_oneof::id::NOT_SET, msg.get_which_message());
@@ -317,3 +323,25 @@ TEST(OneofField, deserialize_oneof_msg)
   EXPECT_EQ(22, msg.get_msg_DEF().get_varE());
   EXPECT_EQ(333, msg.get_msg_DEF().get_varF());
 }
+
+TEST(OneofField, nested_assign)
+{
+  // This test will call the assignement operator and set the union data correctly in the message
+  // which holds a nested message with oneof's.
+
+  InSequence s;
+  nested_oneof top_level_msg;
+
+  message_oneof nested_msg;
+  nested_msg.mutable_msg_ABC().set_varA(1);
+  nested_msg.mutable_msg_ABC().set_varB(22);
+  nested_msg.mutable_msg_ABC().set_varC(333);
+
+  top_level_msg.set_msg_oneof(nested_msg);
+
+  // Check the result.
+  EXPECT_EQ(message_oneof::id::MSG_ABC, top_level_msg.get_msg_oneof().get_which_message());
+  EXPECT_EQ(1, top_level_msg.get_msg_oneof().msg_ABC().varA());
+  EXPECT_EQ(22, top_level_msg.get_msg_oneof().msg_ABC().varB());
+  EXPECT_EQ(333, top_level_msg.get_msg_oneof().msg_ABC().varC());
+}

+ 115 - 0
test/test_string_bytes.cpp

@@ -362,4 +362,119 @@ TEST(FieldBytes, oneof_deserialize)
   EXPECT_EQ(0, msg.b()[3]);
 }
 
+TEST(RepeatedStringBytes, empty) 
+{ 
+  repeated_string_bytes<3, 10, 3, 10> msg;
+  Mocks::WriteBufferMock buffer;
+  EXPECT_CALL(buffer, get_available_size()).Times(2).WillRepeatedly(Return(99));  
+  EXPECT_EQ(::EmbeddedProto::Error::NO_ERRORS, msg.serialize(buffer));
+}
+
+TEST(RepeatedStringBytes, get_set) 
+{ 
+  repeated_string_bytes<3, 15, 3, 15> msg;
+
+  ::EmbeddedProto::FieldString<15> str;
+  msg.add_array_of_txt(str);
+  msg.mutable_array_of_txt(0) = "Foo bar 1";
+  msg.add_array_of_txt(str);
+  msg.mutable_array_of_txt(1) = "Foo bar 2";
+
+  str = "Foo bar 3";
+  msg.add_array_of_txt(str);
+  
+  EXPECT_EQ(3, msg.array_of_txt().get_length());
+  EXPECT_EQ(0, msg.array_of_bytes().get_length());
+  EXPECT_STREQ(msg.array_of_txt(0).get_const(), "Foo bar 1");
+  EXPECT_STREQ(msg.array_of_txt(1).get_const(), "Foo bar 2");
+  EXPECT_STREQ(msg.array_of_txt(2).get_const(), "Foo bar 3");
+}
+
+
+TEST(RepeatedStringBytes, serialize) 
+{ 
+  InSequence s;
+
+  repeated_string_bytes<3, 15, 3, 15> msg;
+  Mocks::WriteBufferMock buffer;
+
+  ::EmbeddedProto::FieldString<15> str;
+  msg.add_array_of_txt(str);
+  msg.mutable_array_of_txt(0) = "Foo bar 1";
+  msg.add_array_of_txt(str);
+  msg.mutable_array_of_txt(1) = "";
+  msg.add_array_of_txt(str);
+  msg.mutable_array_of_txt(2) = "Foo bar 3";
+
+  // We need 24 bytes to serialze the strings above.
+  EXPECT_CALL(buffer, get_available_size()).Times(1).WillOnce(Return(24));
+
+  // The first string.
+  // Id and size of array of txt.
+  EXPECT_CALL(buffer, push(0x0a)).Times(1).WillOnce(Return(true));
+  EXPECT_CALL(buffer, push(0x09)).Times(1).WillOnce(Return(true));
+  // The string is pushed as an array, we do not know the pointer value so use _, but we do know 
+  // the size.
+  EXPECT_CALL(buffer, push(_, 9)).Times(1).WillOnce(Return(true));
+  
+
+  // The empty string
+  EXPECT_CALL(buffer, push(0x0a)).Times(1).WillOnce(Return(true));
+  EXPECT_CALL(buffer, push(0x00)).Times(1).WillOnce(Return(true));
+  
+  // The last string
+  EXPECT_CALL(buffer, push(0x0a)).Times(1).WillOnce(Return(true));
+  EXPECT_CALL(buffer, push(0x09)).Times(1).WillOnce(Return(true));
+  EXPECT_CALL(buffer, push(_, 9)).Times(1).WillOnce(Return(true));
+
+  EXPECT_CALL(buffer, get_available_size()).Times(1).WillOnce(Return(0));
+
+  EXPECT_EQ(::EmbeddedProto::Error::NO_ERRORS, msg.serialize(buffer));
+}
+
+TEST(RepeatedStringBytes, deserialize) 
+{ 
+  InSequence s;
+
+  repeated_string_bytes<3, 15, 3, 15> msg;
+  Mocks::ReadBufferMock buffer;
+
+  // Pop the tag and size of the first string
+  EXPECT_CALL(buffer, pop(_)).Times(1).WillOnce(DoAll(SetArgReferee<0>(0x0a), Return(true)));
+  EXPECT_CALL(buffer, pop(_)).Times(1).WillOnce(DoAll(SetArgReferee<0>(0x09), Return(true)));
+
+  uint8_t referee_str1[] = {0x46, 0x6f, 0x6f, 0x20, 0x62, 0x61, 0x72, 0x20, 0x31};
+
+  for(auto r: referee_str1) 
+  {
+    EXPECT_CALL(buffer, pop(_)).Times(1).WillOnce(DoAll(SetArgReferee<0>(r), Return(true)));
+  }
+
+  // Pop the tag and size of the second string
+  EXPECT_CALL(buffer, pop(_)).Times(1).WillOnce(DoAll(SetArgReferee<0>(0x0a), Return(true)));
+  EXPECT_CALL(buffer, pop(_)).Times(1).WillOnce(DoAll(SetArgReferee<0>(0x00), Return(true)));
+
+  // Pop the tag and size of the third string
+  EXPECT_CALL(buffer, pop(_)).Times(1).WillOnce(DoAll(SetArgReferee<0>(0x0a), Return(true)));
+  EXPECT_CALL(buffer, pop(_)).Times(1).WillOnce(DoAll(SetArgReferee<0>(0x09), Return(true)));
+
+  uint8_t referee_str3[] = {0x46, 0x6f, 0x6f, 0x20, 0x62, 0x61, 0x72, 0x20, 0x33};
+
+  for(auto r: referee_str3) 
+  {
+    EXPECT_CALL(buffer, pop(_)).Times(1).WillOnce(DoAll(SetArgReferee<0>(r), Return(true)));
+  }
+
+  EXPECT_CALL(buffer, pop(_)).Times(1).WillOnce(Return(false));
+
+  EXPECT_EQ(::EmbeddedProto::Error::NO_ERRORS, msg.deserialize(buffer));
+  EXPECT_EQ(3, msg.array_of_txt().get_length());
+  EXPECT_EQ(0, msg.array_of_bytes().get_length());
+  EXPECT_STREQ(msg.array_of_txt(0).get_const(), "Foo bar 1");
+  EXPECT_STREQ(msg.array_of_txt(1).get_const(), "");
+  EXPECT_STREQ(msg.array_of_txt(2).get_const(), "Foo bar 3"); 
+}
+
+
+
 } // End of namespace test_EmbeddedAMS_string_bytes

+ 34 - 14
test_data.py

@@ -36,7 +36,8 @@ import nested_message_pb2 as nm
 import repeated_fields_pb2 as rf
 import oneof_fields_pb2 as of
 import file_to_include_pb2 as fti
-import include_other_files_pb2 as iof
+#import include_other_files_pb2 as iof
+import string_bytes_pb2 as sb
 
 
 def test_simple_types():
@@ -99,17 +100,17 @@ def test_simple_types():
 def test_nested_message():
     msg = nm.message_b()
 
-    # msg.u = 1.0
-    # msg.v = 1.0
-    # msg.nested_a.x = 1
-    # msg.nested_a.y = 1.0
-    # msg.nested_a.z = 1
+    #msg.u = 1.0
+    #msg.v = 1
+    #msg.nested_a.x.append(1)
+    #msg.nested_a.y = 1.0
+    #msg.nested_a.z = 1
 
-    msg.u = 0 #pow(2, 1023)
-    msg.v = 0 #pow(2, 1023)
-    #msg.nested_a.x = 0#pow(2, 31) - 1
-    #msg.nested_a.y = 0 #1.0
-    #msg.nested_a.z = 0 #1
+    msg.u = 1.7976931348623157e+308         # Max double 1.7976931348623157e+308
+    msg.v = pow(2, 31) - 1                  # Max int32
+    msg.nested_a.x.append(pow(2, 31) - 1)   # Max int32
+    msg.nested_a.y = 3.40282347e+38         # Max float
+    msg.nested_a.z = 9223372036854775807    # Max sint64
 
     str = ""
     msg_str = msg.SerializeToString()
@@ -192,7 +193,7 @@ def test_repeated_message():
 
 
 def test_string():
-    msg = rf.text()
+    msg = sb.text()
 
     msg.txt = "Foo bar"
 
@@ -208,7 +209,7 @@ def test_string():
 
 
 def test_bytes():
-    msg = rf.raw_bytes()
+    msg = sb.raw_bytes()
 
     msg.b = b'\x01\x02\x03\x00'
 
@@ -223,6 +224,24 @@ def test_bytes():
     print()
 
 
+def test_repeated_string_bytes():
+    msg = sb.repeated_string_bytes()
+
+    msg.array_of_txt.append("Foo bar 1")
+    msg.array_of_txt.append("")
+    msg.array_of_txt.append("Foo bar 3")
+
+    str = ""
+    msg_str = msg.SerializeToString()
+    print(len(msg_str))
+    print(msg_str)
+    for x in msg_str:
+        str += "0x{:02x}, ".format(x)
+
+    print(str)
+    print()
+
+
 def test_oneof_fields():
     msg = of.message_oneof()
 
@@ -269,7 +288,8 @@ def test_included_proto():
 #test_repeated_fields()
 #test_repeated_message()
 #test_string()
-test_bytes()
+#test_bytes()
+test_repeated_string_bytes()
 #test_nested_message()
 #test_oneof_fields()
 #test_included_proto()