This is an automated email from the ASF dual-hosted git repository.

jfeinauer pushed a commit to branch feature/plc4rs
in repository https://gitbox.apache.org/repos/asf/plc4x.git


The following commit(s) were added to refs/heads/feature/plc4rs by this push:
     new b6a4d30a07 Step forward complex types
b6a4d30a07 is described below

commit b6a4d30a078860f0a477786fd332675168d1d4cc
Author: julian <[email protected]>
AuthorDate: Sat Jun 4 17:48:50 2022 +0200

    Step forward complex types
---
 .../language/rust/RustLanguageTemplateHelper.java  |  119 +-
 .../templates/rust/complex-type-template.rs.ftlh   | 1648 ++++++++++----------
 .../resources/templates/rust/enum-template.rs.ftlh |    2 +-
 3 files changed, 958 insertions(+), 811 deletions(-)

diff --git 
a/code-generation/language-rust/src/main/java/org/apache/plc4x/language/rust/RustLanguageTemplateHelper.java
 
b/code-generation/language-rust/src/main/java/org/apache/plc4x/language/rust/RustLanguageTemplateHelper.java
index a55a4f5666..a865744f8f 100644
--- 
a/code-generation/language-rust/src/main/java/org/apache/plc4x/language/rust/RustLanguageTemplateHelper.java
+++ 
b/code-generation/language-rust/src/main/java/org/apache/plc4x/language/rust/RustLanguageTemplateHelper.java
@@ -21,9 +21,14 @@ package org.apache.plc4x.language.rust;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.math.NumberUtils;
 import org.apache.commons.text.WordUtils;
+import 
org.apache.plc4x.plugins.codegenerator.language.mspec.model.definitions.DefaultComplexTypeDefinition;
 import 
org.apache.plc4x.plugins.codegenerator.language.mspec.model.definitions.DefaultEnumTypeDefinition;
+import 
org.apache.plc4x.plugins.codegenerator.language.mspec.model.fields.DefaultDiscriminatorField;
+import 
org.apache.plc4x.plugins.codegenerator.language.mspec.model.fields.DefaultSwitchField;
 import 
org.apache.plc4x.plugins.codegenerator.language.mspec.model.references.DefaultEnumTypeReference;
+import 
org.apache.plc4x.plugins.codegenerator.language.mspec.model.terms.DefaultBooleanLiteral;
 import 
org.apache.plc4x.plugins.codegenerator.language.mspec.model.terms.DefaultStringLiteral;
+import 
org.apache.plc4x.plugins.codegenerator.language.mspec.model.terms.DefaultVariableLiteral;
 import 
org.apache.plc4x.plugins.codegenerator.protocol.freemarker.BaseFreemarkerLanguageTemplateHelper;
 import 
org.apache.plc4x.plugins.codegenerator.protocol.freemarker.FreemarkerException;
 import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer;
@@ -40,6 +45,7 @@ import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.util.*;
 import java.util.function.Function;
+import java.util.stream.Collectors;
 
 @SuppressWarnings({"unused", "WeakerAccess"})
 public class RustLanguageTemplateHelper extends 
BaseFreemarkerLanguageTemplateHelper {
@@ -80,13 +86,94 @@ public class RustLanguageTemplateHelper extends 
BaseFreemarkerLanguageTemplateHe
         return getLanguageTypeNameForTypeReference(((TypedField) 
field).getType(), !field.isOptionalField());
     }
 
-    public List<String> generateImports(EnumTypeDefinition typeDefinition) {
+    public List<TypeDefinition> getSubtypes(TypeDefinition typeDefinition) {
+        List<TypeDefinition> subtypes = new ArrayList<>();
+        if (typeDefinition instanceof DefaultComplexTypeDefinition) {
+            for (Field field : ((DefaultComplexTypeDefinition) 
typeDefinition).getAllFields()) {
+                if (field instanceof DefaultSwitchField) {
+                    subtypes.addAll(((DefaultSwitchField) field).getCases());
+                }
+            }
+        }
+        return subtypes;
+    }
+
+    public String generateFieldParseCode(Field field) {
+        if (field instanceof DefaultDiscriminatorField) {
+            // Get it from the parameter
+            String type = this.getLanguageTypeNameForField(field);
+            return "let " + ((DefaultDiscriminatorField) field).getName() + " 
= parser.parse_" + type + "()?;";
+        }
+        if (field instanceof DefaultSwitchField) {
+            String matchExpression = String.join(", ", ((DefaultSwitchField) 
field).getDiscriminatorExpressions().stream().map(literal -> 
literal.getName()).collect(Collectors.toList()));
+            StringBuilder sb = new StringBuilder();
+            sb.append(String.format("match (%s) {", matchExpression) + "\n");
+
+            int numberOfCases = ((DefaultSwitchField) 
field).getDiscriminatorExpressions().size();
+
+            for (DiscriminatedComplexTypeDefinition aCase : 
((DefaultSwitchField) field).getCases()) {
+                ArrayList<String> caseStatement = new ArrayList<>();
+                for (int i = 0; i < numberOfCases; i++) {
+                    if (aCase.getDiscriminatorValueTerms().size() > i) {
+                        Term discriminatorLiteral = 
aCase.getDiscriminatorValueTerms().get(i);
+                        String literal = 
discriminatorLiteral.stringRepresentation();
+                        if (discriminatorLiteral instanceof Literal) {
+                            if (discriminatorLiteral instanceof 
DefaultBooleanLiteral) {
+                                literal = 
Boolean.toString(((DefaultBooleanLiteral) discriminatorLiteral).getValue());
+                            }
+                            if (discriminatorLiteral instanceof 
DefaultVariableLiteral) {
+                                // Find out type of the Variable
+                                TypeReference typeReference = 
((DefaultSwitchField) 
field).getDiscriminatorExpressions().get(i).getTypeReference();
+                                if (!(typeReference instanceof 
DefaultEnumTypeReference)) {
+                                    throw new RuntimeException("...");
+                                }
+                                literal = ((DefaultEnumTypeReference) 
typeReference).getName() + "::" + ((DefaultVariableLiteral) 
discriminatorLiteral).getName();
+                            }
+                        }
+                        caseStatement.add(literal);
+                    } else {
+                        caseStatement.add("_");
+                    }
+                }
+
+                sb.append("(" + String.join(", ", caseStatement) + ") => {\n");
+
+
+                // TODO handle parser arguments if the type needs it
+                String options  = "None";
+
+                sb.append("Ok(" + aCase.getParentType().get().getName() + "::" 
+ aCase.getName() + "(" + aCase.getName() + "::parse::<T>(reader, " + options + 
")?))");
+
+                // TODO add the action here...
+                System.out.println("Hallo");
+
+                sb.append("}\n");
+            }
+
+            sb.append("}\n");
+            return sb.toString();
+        }
+        return "";
+    }
+
+    public List<String> generateImports(TypeDefinition typeDefinition) {
         // Iterate all Types to see what kind of other Enums / Objects are 
references
         List<String> imports = new ArrayList<>();
-        for (String constantName : typeDefinition.getConstantNames()) {
-            TypeReference constantType = 
typeDefinition.getConstantType(constantName);
-            if (constantType instanceof DefaultEnumTypeReference) {
-                imports.add(((DefaultEnumTypeReference) 
constantType).getName());
+        if (typeDefinition instanceof EnumTypeDefinition) {
+            for (String constantName : ((EnumTypeDefinition) 
typeDefinition).getConstantNames()) {
+                TypeReference constantType = ((EnumTypeDefinition) 
typeDefinition).getConstantType(constantName);
+                if (constantType instanceof DefaultEnumTypeReference) {
+                    imports.add(((DefaultEnumTypeReference) 
constantType).getName());
+                }
+            }
+        }
+        if (typeDefinition instanceof DefaultComplexTypeDefinition) {
+            for (Field field : ((DefaultComplexTypeDefinition) 
typeDefinition).getFields()) {
+                if (field instanceof DefaultSwitchField) {
+                    for (DiscriminatedComplexTypeDefinition subclass : 
((DefaultSwitchField) field).getCases()) {
+                        imports.add(subclass.getName());
+                    }
+                }
             }
         }
         return imports;
@@ -112,6 +199,28 @@ public class RustLanguageTemplateHelper extends 
BaseFreemarkerLanguageTemplateHe
         return false;
     }
 
+    public boolean needsParserArguments(TypeDefinition typeDefinition) {
+        if (typeDefinition.getParserArguments().isPresent()) {
+            return !typeDefinition.getParserArguments().get().isEmpty();
+        }
+        return false;
+    }
+
+    public boolean isSwitchField(Field field) {
+        return field instanceof DefaultSwitchField;
+    }
+
+    public boolean isAbstract(TypeDefinition typeDefinition) {
+        if (typeDefinition instanceof DefaultComplexTypeDefinition) {
+            return ((DefaultComplexTypeDefinition) 
typeDefinition).isAbstract();
+        }
+        return false;
+    }
+
+    public boolean isDiscriminated(TypeDefinition typeDefinition) {
+        return typeDefinition instanceof DiscriminatedComplexTypeDefinition;
+    }
+
     public String sink(Object definition) {
         return "";
     }
diff --git 
a/code-generation/language-rust/src/main/resources/templates/rust/complex-type-template.rs.ftlh
 
b/code-generation/language-rust/src/main/resources/templates/rust/complex-type-template.rs.ftlh
index f2b5a53216..10725b9e55 100644
--- 
a/code-generation/language-rust/src/main/resources/templates/rust/complex-type-template.rs.ftlh
+++ 
b/code-generation/language-rust/src/main/resources/templates/rust/complex-type-template.rs.ftlh
@@ -45,829 +45,867 @@ ${helper.packageName(protocolName, languageName, 
outputFlavor)?replace(".", "/")
  * specific language governing permissions and limitations
  * under the License.
  */
-package ${helper.packageName(protocolName, languageName, outputFlavor)};
-
-import static org.apache.plc4x.java.spi.generation.StaticHelper.*;
-import static org.apache.plc4x.java.spi.codegen.io.DataReaderFactory.*;
-import static org.apache.plc4x.java.spi.codegen.io.DataWriterFactory.*;
-import static org.apache.plc4x.java.spi.codegen.fields.FieldReaderFactory.*;
-import static org.apache.plc4x.java.spi.codegen.fields.FieldWriterFactory.*;
-
-import org.apache.plc4x.java.spi.codegen.*;
-import org.apache.plc4x.java.spi.codegen.io.*;
-import org.apache.plc4x.java.spi.codegen.fields.*;
-import org.apache.plc4x.java.api.exceptions.*;
-import org.apache.plc4x.java.spi.generation.*;
-import org.apache.plc4x.java.api.value.*;
-
-import java.time.*;
-import java.util.*;
-import java.math.BigInteger;
+// package ${helper.packageName(protocolName, languageName, outputFlavor)};
 
 // Code generated by code-generation. DO NOT EDIT.
-
-<#-- TODO: the code below implies that parserArguments will be null if not 
present... not pretty  -->
-<#if type.parserArguments.isPresent()><#assign 
parserArguments=type.allParserArguments.orElseThrow()></#if>
-public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class 
${type.name}<#if type.isDiscriminatedParentTypeDefinition()></#if><#if 
type.parentType.isPresent()> extends 
${type.parentType.orElseThrow().name}</#if> implements Message {
-
-<#--
-    If this is a discriminated child type, we need to generate methods for 
accessing it's discriminator
-    values, as if they were normal java properties.
--->
-<#if type.isDiscriminatedChildTypeDefinition()>
-    <#assign discriminatedChildType = 
type.asDiscriminatedComplexTypeDefinition().orElseThrow()>
-    // Accessors for discriminator values.
-    <#list discriminatedChildType.getDiscriminatorMap() as discriminatorName, 
discriminatorValue>
-        <#-- If the discriminator name matches that of another field, suppress 
the methods generation -->
-        <#if 
!discriminatedChildType.isNonDiscriminatorField(discriminatorName)><#--&& 
!discriminatedChildType.isParserArgument(discriminatorName)-->
-            <#assign discriminatorType = 
helper.getDiscriminatorTypes()[discriminatorName]>
-    public ${helper.getLanguageTypeNameForTypeReference(discriminatorType)} 
get${discriminatorName?cap_first}() {
-            <#if discriminatorValue?? && 
!helper.isWildcard(discriminatorValue)>
-                <#if discriminatorType.isEnumTypeReference()>
-        return 
${helper.getLanguageTypeNameForTypeReference(discriminatorType)}.${helper.toParseExpression(null,
 discriminatorType, discriminatorValue, parserArguments)};
-                <#else>
-        return 
(${helper.getLanguageTypeNameForTypeReference(discriminatorType, true)}) 
${helper.toParseExpression(null, discriminatorType, discriminatorValue, 
parserArguments)};
-                </#if>
-            <#else>
-        return ${helper.getNullValueForTypeReference(discriminatorType)};
-            </#if>
-    }
-        </#if>
-    </#list>
-</#if>
-<#--
-    If this is a discriminated parent type, we need to generate the abstract 
methods for accessing it's
-    discriminator values instead.
--->
-<#if type.isDiscriminatedParentTypeDefinition()>
-    <#assign discriminatedParentType = type>
-    <#-- @ftlvariable name="discriminatedParentType" 
type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition"
 -->
-    // Abstract accessors for discriminator values.
-    <#list helper.discriminatorTypes as discriminatorName, discriminatorType>
-        <#-- If the discriminator name matches that of another field, suppress 
the methods generation -->
-        <#if !type.isNonDiscriminatorField(discriminatorName)><#-- && 
!type.isParserArgument(discriminatorName)-->
-    public abstract 
${helper.getLanguageTypeNameForTypeReference(discriminatorType)} 
get${discriminatorName?cap_first}();
-        </#if>
-    </#list>
-</#if>
-<#-- If the current type contains "const" fields, generate some java constants 
for holing their values -->
-<#if type.constFields?has_content>
-
-    // Constant values.
-    <#list type.constFields as field>
-    public static final 
${helper.getLanguageTypeNameForTypeReference(field.type)} 
${field.name?upper_case} = ${helper.toParseExpression(field, field.type, 
field.referenceValue, parserArguments)};
-    </#list>
-</#if>
-<#-- Property fields are fields that require a property in the pojo -->
-<#if type.propertyFields?has_content>
-
-    // Properties.
-    <#list type.propertyFields as field>
-    protected final ${helper.getLanguageTypeNameForTypeReference(field.type, 
!field.isOptionalField())} ${field.name};
-    </#list>
-</#if>
-<#if parserArguments?has_content>
-  <#assign filteredParserArguments=parserArguments?filter(arg -> 
!type.isDiscriminatorField(arg.name) && 
!type.getPropertyFieldFromThisOrParentByName(arg.name).isPresent())>
+<#list helper.generateImports(type) as import>
+<#if type.name != import>
+<#--  File -> Struct  -->
+use crate::${import}::${import};
 </#if>
-<#if filteredParserArguments?has_content>
-
-    // Arguments.
-    <#list filteredParserArguments as parserArgument>
-    protected final 
${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} 
${parserArgument.name};
-    </#list>
-</#if>
-
-    <#-- getAllPropertyFields() returns not only the property fields of this 
type but also of it's parents -->
-    <@compress single_line=true>
-    public ${type.name}(
-        <#list type.getAllPropertyFields() as field>
-            ${helper.getLanguageTypeNameForField(field)} ${field.name}
-            <#sep>, </#sep>
-        </#list>
-        <#if filteredParserArguments?has_content>
-            <#if type.getAllPropertyFields()?has_content>, </#if>
-            <#list filteredParserArguments as parserArgument>
-                
${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} 
${parserArgument.name}
-                <#sep>, </#sep>
-            </#list>
-        </#if>
-        ) {
-    </@compress>
-
-    <@compress single_line=true>
-        super(
-        <#if type.parentPropertyFields?has_content>
-            <#list type.parentPropertyFields as field>
-                ${field.name}
-                <#sep>, </#sep>
-            </#list>
-        </#if>
-        <#if type.parentType.isPresent() && 
type.parentType.orElseThrow().allParserArguments.isPresent()>
-            <#assign filteredParentParserArguments = 
type.parentType.orElseThrow().allParserArguments.orElseThrow()?filter(arg -> 
!type.parentType.orElseThrow().asComplexTypeDefinition().orElseThrow().isDiscriminatorField(arg.name))>
-            <#if filteredParentParserArguments?has_content>
-                <#if type.parentPropertyFields?has_content>, </#if>
-                <#list filteredParentParserArguments as parserArgument>
-                    ${parserArgument.name}
-                    <#sep>, </#sep>
-                </#list>
-            </#if>
-        </#if>
-        );
-    </@compress>
-
-<#list type.propertyFields as field>
-        this.${field.name} = ${field.name};
 </#list>
-<#if filteredParserArguments?has_content>
-    <#list filteredParserArguments as parserArgument>
-        this.${parserArgument.name} = ${parserArgument.name};
-    </#list>
-</#if>
-    }
-
-<#list type.abstractFields as field>
-    public abstract ${helper.getLanguageTypeNameForField(field)} 
get${field.asNamedField().orElseThrow().name?cap_first}();
 
+<#if helper.needsParserArguments(type)>
+pub struct ${type.name}Options {
+<#list type.parserArguments.orElseThrow() as arg>
+    ${arg.name}: 
${helper.getLanguageTypeNameForTypeReference(arg.type)}<#sep>, </#sep>
 </#list>
-<#list type.propertyFields as field>
-    public ${helper.getLanguageTypeNameForField(field)} 
get${field.name?cap_first}() {
-        return ${field.name};
-    }
-
-</#list>
-<#list type.virtualFields as field>
-    public ${helper.getLanguageTypeNameForField(field)} 
get${field.name?cap_first}() {
-        <#if helper.getLanguageTypeNameForField(field) = 'String'>
-        return 
${helper.getLanguageTypeNameForField(field)}.valueOf(${helper.toSerializationExpression(field,
 field.type, field.valueExpression, parserArguments)});
-        <#--elseif helper.getLanguageTypeNameForField(field) = 'BigInteger' && 
!helper.isBigIntegerSource(field.valueExpression)-->
-        <#elseif helper.getLanguageTypeNameForField(field) = 'BigInteger'>
-        Object o = ${helper.toSerializationExpression(field, field.type, 
field.valueExpression, parserArguments)};
-        if (o instanceof BigInteger)
-            return (BigInteger) o;
-        return BigInteger.valueOf(((Number)o).longValue());
-        <#else>
-        return (${helper.getLanguageTypeNameForField(field)}) 
(${helper.toSerializationExpression(field, field.type, field.valueExpression, 
parserArguments)});
-        </#if>
-    }
-
-</#list>
-<#list type.constFields as field>
-    public ${helper.getLanguageTypeNameForField(field)} 
get${field.name?cap_first}() {
-        return ${field.name?upper_case};
-    }
-
+}
+</#if>
+<#if helper.isAbstract(type)>
+#[derive(PartialEq, Debug, Clone)]
+pub enum ${type.name} {
+<#list helper.getSubtypes(type) as subtype>
+    ${subtype.name}(${subtype.name}::${subtype.name})<#sep>,</#sep>
 </#list>
+}
 
-    <#if outputFlavor != "passive">
-<#if type.isDiscriminatedChildTypeDefinition()>
-    @Override
-    protected void 
serialize${type.parentType.orElseThrow().name}Child(WriteBuffer writeBuffer) 
throws SerializationException {
-<#else>
-    <#if type.isDiscriminatedParentTypeDefinition()>
-    abstract protected void serialize${type.name?cap_first}Child(WriteBuffer 
writeBuffer) throws SerializationException;
-
-    </#if>
-    public void serialize(WriteBuffer writeBuffer) throws 
SerializationException {
-</#if>
-        PositionAware positionAware = writeBuffer;
-        <#if helper.hasFieldOfType("unknown")>
-            throw new SerializationException("Unknown field not serializable");
-        <#else>
-            int startPos = positionAware.getPos();
-            writeBuffer.pushContext("${type.name}");
-            <#list type.fields as field>
-                <#switch field.typeName>
-                    <#case "array">
-                        <#assign arrayField = 
field.asArrayField().orElseThrow()>
-                        <#assign typedField = 
field.asTypedField().orElseThrow()>
-                        <#assign namedField = 
field.asNamedField().orElseThrow()>
-
-                        // Array Field (${arrayField.name})
-                        <#if 
arrayField.type.elementTypeReference.isByteBased()>
-                        writeByteArrayField("${namedField.name}", 
${namedField.name}, writeByteArray(writeBuffer, 8));
-                        <#elseif 
arrayField.type.elementTypeReference.isSimpleTypeReference()>
-                        writeSimpleTypeArrayField("${namedField.name}", 
${namedField.name}, 
${helper.getDataWriterCall(arrayField.type.elementTypeReference, 
namedField.name)});
-                        <#else>
-                        writeComplexTypeArrayField("${namedField.name}", 
${namedField.name}, writeBuffer);
-                        </#if>
-                        <#break>
-                    <#case "checksum">
-                        <#assign checksumField = 
field.asChecksumField().orElseThrow()>
-                        <#assign typedField = 
field.asTypedField().orElseThrow()>
-                        <#assign namedField = 
field.asNamedField().orElseThrow()>
-
-                        // Checksum Field (checksum) (Calculated)
-                        writeChecksumField("${namedField.name}", 
(${helper.getLanguageTypeNameForField(field)}) 
(${helper.toParseExpression(checksumField, checksumField.type, 
checksumField.checksumExpression, parserArguments)}), 
${helper.getDataWriterCall(typedField.type, namedField.name)});
-                        <#break>
-                    <#case "const">
-                        <#assign constField = 
field.asConstField().orElseThrow()>
-                        <#assign typedField = 
field.asTypedField().orElseThrow()>
-                        <#assign namedField = 
field.asNamedField().orElseThrow()>
-
-                        // Const Field (${constField.name})
-                        <#if 
typedField.type.isEnumTypeReference()>writeConstField("${constField.name}", 
${namedField.name?upper_case}.getValue(), 
${helper.getDataWriterCall(helper.getEnumBaseTypeReference(typedField.type), 
namedField.name)});<#else>writeConstField("${constField.name}", 
${namedField.name?upper_case}, ${helper.getDataWriterCall(typedField.type, 
namedField.name)});</#if>
-                        <#break>
-                    <#case "discriminator">
-                        <#assign discriminatorField = 
field.asDiscriminatorField().orElseThrow()>
-                        <#assign typedField = 
field.asTypedField().orElseThrow()>
-                        <#assign namedField = 
field.asNamedField().orElseThrow()>
-
-                        // Discriminator Field (${discriminatorField.name}) 
(Used as input to a switch field)
-                        <#if 
typedField.type.isEnumTypeReference()>writeDiscriminatorEnumField("${namedField.name}",
 "${helper.getLanguageTypeNameForField(field)}", 
get${discriminatorField.name?cap_first}(), 
${helper.getEnumDataWriterCall(typedField.type, namedField.name, 
"value")});<#else>writeDiscriminatorField("${namedField.name}", 
get${discriminatorField.name?cap_first}(), 
${helper.getDataWriterCall(typedField.type, namedField.name)});</#if>
-                        <#break>
-                    <#case "enum">
-                        <#assign enumField = field.asEnumField().orElseThrow()>
-                        <#assign typedField = 
field.asTypedField().orElseThrow()>
-                        <#assign namedField = 
field.asNamedField().orElseThrow()>
-
-                        // Enum field (${namedField.name})
-                        writeEnumField("${namedField.name}", 
"${helper.getLanguageTypeNameForField(field)}", ${namedField.name}, 
${helper.getEnumDataWriterCall(typedField.type, namedField.name, 
enumField.fieldName)});
-                        <#break>
-                    <#case "implicit">
-                        <#assign implicitField = 
field.asImplicitField().orElseThrow()>
-                        <#assign typedField = 
field.asTypedField().orElseThrow()>
-                        <#assign namedField = 
field.asNamedField().orElseThrow()>
-
-                        // Implicit Field (${implicitField.name}) (Used for 
parsing, but its value is not stored as it's implicitly given by the objects 
content)
-                        <#-- Implicit field values might be used in 
expressions, in order to avoid problems, we generate a temporary variable with 
the given name. -->
-                        ${helper.getLanguageTypeNameForField(field)} 
${implicitField.name} = (${helper.getLanguageTypeNameForField(field)}) 
(${helper.toSerializationExpression(implicitField, implicitField.type, 
implicitField.serializeExpression, parserArguments)});
-                        writeImplicitField("${namedField.name}", 
${implicitField.name}, ${helper.getDataWriterCall(typedField.type, 
namedField.name)});
-                        <#break>
-                    <#case "manualArray">
-                        <#assign manualArrayField = 
field.asManualArrayField().orElseThrow()>
-                        <#assign typedField = 
field.asTypedField().orElseThrow()>
-                        <#assign namedField = 
field.asNamedField().orElseThrow()>
-
-                        // Manual Array Field (${manualArrayField.name})
-                        writeManualArrayField("${namedField.name}", 
${namedField.name}, 
(${helper.getLanguageTypeNameForTypeReference(manualArrayField.type.elementTypeReference)}
 _value) -> ${helper.toParseExpression(manualArrayField, 
manualArrayField.type.elementTypeReference, 
manualArrayField.serializeExpression, parserArguments)}, writeBuffer);
-                        <#break>
-                    <#case "manual">
-                        <#assign manualField = 
field.asManualField().orElseThrow()>
-                        <#assign typedField = 
field.asTypedField().orElseThrow()>
-                        <#assign namedField = 
field.asNamedField().orElseThrow()>
-
-                        // Manual Field (${manualField.name})
-                        writeManualField("${namedField.name}", () -> 
${helper.toParseExpression(manualField, manualField.type, 
manualField.serializeExpression, parserArguments)}, writeBuffer);
-                        <#break>
-                    <#case "optional">
-                        <#assign optionalField = 
field.asOptionalField().orElseThrow()>
-                        <#assign typedField = 
field.asTypedField().orElseThrow()>
-                        <#assign namedField = 
field.asNamedField().orElseThrow()>
-
-                        // Optional Field (${optionalField.name}) (Can be 
skipped, if the value is null)
-                        <#if optionalField.type.isEnumTypeReference()>
-                            writeOptionalEnumField("${optionalField.name}", 
"${helper.getLanguageTypeNameForField(field)}", ${optionalField.name}, 
${helper.getEnumDataWriterCall(optionalField.type, optionalField.name, 
"value")}<#if optionalField.conditionExpression.present>, 
${helper.toSerializationExpression(optionalField, helper.boolTypeReference, 
optionalField.conditionExpression.get(), parserArguments)}</#if>);
-                        <#elseif optionalField.type.isDataIoTypeReference()>
-                            writeOptionalField("${optionalField.name}", 
${optionalField.name}, new DataWriterDataIoDefault(writeBuffer, (wb, val) -> 
${optionalField.type.asComplexTypeReference().orElseThrow().name}.staticSerialize(wb,
 val<#if 
optionalField.type.asComplexTypeReference().orElseThrow().params?has_content>, 
<#list 
optionalField.type.asComplexTypeReference().orElseThrow().params.orElseThrow() 
as param>${helper.toParseExpression(optionalField, helper.anyTypeReference, 
param, p [...]
-                        <#else>
-                            writeOptionalField("${optionalField.name}", 
${optionalField.name}, ${helper.getDataWriterCall(typedField.type, 
optionalField.name)}<#if optionalField.conditionExpression.present>, 
${helper.toSerializationExpression(optionalField, helper.boolTypeReference, 
optionalField.conditionExpression.get(), parserArguments)}</#if>);
-                        </#if>
-                        <#break>
-                    <#case "padding">
-                        <#assign paddingField = 
field.asPaddingField().orElseThrow()>
-                        <#assign typedField = 
field.asTypedField().orElseThrow()>
-
-                        // Padding Field (padding)
-                        writePaddingField("padding", (int) 
(${helper.toParseExpression(paddingField, helper.intTypeReference, 
paddingField.paddingCondition, parserArguments)}), 
(${helper.getLanguageTypeNameForField(field)}) 
${helper.toSerializationExpression(paddingField, paddingField.type, 
paddingField.paddingValue, parserArguments)}, 
${helper.getDataWriterCall(typedField.type, "padding")});
-                        <#break>
-                    <#case "reserved">
-                        <#assign reservedField = 
field.asReservedField().orElseThrow()>
-                        <#assign typedField = 
field.asTypedField().orElseThrow()>
-
-                        // Reserved Field (reserved)
-                        writeReservedField("reserved", 
${helper.getReservedValue(reservedField)}, 
${helper.getDataWriterCall(typedField.type, "reserved")});
-                        <#break>
-                    <#case "simple">
-                        <#assign simpleField = 
field.asSimpleField().orElseThrow()>
-                        <#assign typedField = 
field.asTypedField().orElseThrow()>
-                        <#assign namedField = 
field.asNamedField().orElseThrow()>
-
-                        // Simple Field (${namedField.name})
-                        <#if typedField.type.isEnumTypeReference()>
-                            writeSimpleEnumField("${simpleField.name}", 
"${helper.getLanguageTypeNameForField(field)}", ${simpleField.name}, 
${helper.getEnumDataWriterCall(simpleField.type, simpleField.name, "value")});
-                        <#elseif simpleField.type.isDataIoTypeReference()>
-                            writeSimpleField("${simpleField.name}", 
${simpleField.name}, new DataWriterDataIoDefault(writeBuffer, (wb, val) -> 
${simpleField.type.asComplexTypeReference().orElseThrow().name}.staticSerialize(wb,
 val<#if 
simpleField.type.asComplexTypeReference().orElseThrow().params?has_content>, 
<#list 
simpleField.type.asComplexTypeReference().orElseThrow().params.orElseThrow() as 
param>${helper.toParseExpression(simpleField, helper.anyTypeReference, param, 
parserArguments [...]
-                        <#else>
-                            writeSimpleField("${simpleField.name}", 
${simpleField.name}, ${helper.getDataWriterCall(typedField.type, 
simpleField.name)}${helper.getFieldOptions(typedField, parserArguments)});</#if>
-                        <#break>
-                    <#case "switch">
-                        <#assign switchField = 
field.asSwitchField().orElseThrow()>
-
-                        // Switch field (Serialize the sub-type)
-                        serialize${type.name?cap_first}Child(writeBuffer);
-                        <#break>
-                    <#case "virtual">
-                        <#assign virtualField = 
field.asVirtualField().orElseThrow()>
-                        <#assign typedField = 
field.asTypedField().orElseThrow()>
-                        <#assign namedField = 
field.asNamedField().orElseThrow()>
-
-                        // Virtual field (doesn't actually serialize anything, 
just makes the value available)
-                        ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = get${namedField.name?cap_first}();
-                        writeBuffer.writeVirtual("${namedField.name}", 
${namedField.name});
-                        <#break>
-                </#switch>
-            </#list>
-
-            writeBuffer.popContext("${type.name}");
-        </#if>
-        }
-    </#if>
+impl Message for ${type.name} {
+    type M = ${type.name};
+    type P = <#if 
helper.needsParserArguments(type)>${type.name}Options<#else>NoOption</#if>;
 
-    @Override
-    public int getLengthInBytes() {
-        return (int) Math.ceil((float) getLengthInBits() / 8.0);
+    fn get_length_in_bits(&self) -> u32 {
+        todo!()
     }
 
-    @Override
-    public int getLengthInBits() {
-        int lengthInBits = <#if 
type.parentType.isPresent()>super.getLengthInBits()<#else>0</#if>;
-        ${type.name} _value  = this;
-<#list type.fields as field>
-<#switch field.typeName>
-    <#case "array">
-        <#assign arrayField = field.asArrayField().orElseThrow()>
-        <#assign arrayElementTypeReference = 
arrayField.type.asArrayTypeReference().orElseThrow().getElementTypeReference()>
-
-        // Array field
-        if(${arrayField.name} != null) {
-        <#if arrayElementTypeReference.isSimpleTypeReference()>
-            <#assign simpleTypeReference = 
arrayElementTypeReference.asSimpleTypeReference().orElseThrow()>
-            lengthInBits += ${simpleTypeReference.sizeInBits} * 
${arrayField.name}.<#if 
arrayElementTypeReference.isByteBased()>length<#else>size()</#if>;
-        <#elseif arrayField.isCountArrayField()>
-            int i=0;
-            <#assign nonSimpleTypeReference = 
arrayElementTypeReference.asNonSimpleTypeReference().orElseThrow()>
-            for(${nonSimpleTypeReference.name} element : ${arrayField.name}) {
-                boolean last = ++i >= ${arrayField.name}.size();
-                lengthInBits += element.getLengthInBits();
+    fn serialize<T: Write>(&self, writer: &mut WriteBuffer<T>) -> 
Result<usize, Error> {
+        match self {
+        <#list helper.getSubtypes(type) as subtype>
+            ${type.name}::${subtype.name}(msg) => {
+                msg.serialize(writer)
             }
-        <#else>
-            for(Message element : ${arrayField.name}) {
-                lengthInBits += element.getLengthInBits();
-            }
-        </#if>
-        }
-        <#break>
-    <#case "checksum">
-        <#assign checksumField = field.asChecksumField().orElseThrow()>
-        <#assign typedField = field.asTypedField().orElseThrow()>
-        <#assign simpleTypeReference = 
typedField.type.asSimpleTypeReference().orElseThrow()>
-
-        // Checksum Field (checksum)
-        lengthInBits += ${simpleTypeReference.sizeInBits};
-        <#break>
-    <#case "const">
-        <#assign constField = field.asConstField().orElseThrow()>
-        <#assign typedField = field.asTypedField().orElseThrow()>
-
-        // Const Field (${constField.name})
-        <#if typedField.type.isSimpleTypeReference()>
-        <#assign simpleTypeReference = 
typedField.type.asSimpleTypeReference().orElseThrow()>
-        lengthInBits += ${simpleTypeReference.sizeInBits};
-        <#else>
-        lengthInBits += 
${helper.getEnumBaseTypeReference(typedField.type).sizeInBits};
-        </#if>
-        <#break>
-    <#case "discriminator">
-        <#assign discriminatorField = 
field.asDiscriminatorField().orElseThrow()>
-
-        // Discriminator Field (${discriminatorField.name})
-        <#if discriminatorField.type.isSimpleTypeReference()>
-            <#assign simpleTypeReference = 
discriminatorField.type.asSimpleTypeReference().orElseThrow()>
-            <#if simpleTypeReference.isVstringTypeReference()>
-                <#assign vstringTypeReference = 
simpleTypeReference.asVstringTypeReference().orElseThrow()>
-        lengthInBits += ${helper.toSerializationExpression(discriminatorField, 
helper.intTypeReference, vstringTypeReference.getLengthExpression(), 
parserArguments)};
-            <#else>
-        lengthInBits += ${simpleTypeReference.sizeInBits};
-            </#if>
-        <#elseif helper.isEnumField(field)>
-            lengthInBits += 
${helper.getEnumBaseTypeReference(discriminatorField.type).sizeInBits};
-        <#else>
-            lengthInBits += ${discriminatorField.name}.getLengthInBits();
-        </#if>
-        <#break>
-    <#case "enum">
-        <#assign enumField = field.asEnumField().orElseThrow()>
-
-        // Enum Field (${enumField.name})
-        lengthInBits += 
${helper.getEnumBaseTypeReference(enumField.type).sizeInBits};
-        <#break>
-    <#case "implicit">
-        <#assign implicitField = field.asImplicitField().orElseThrow()>
-        <#assign simpleTypeReference = 
implicitField.type.asSimpleTypeReference().orElseThrow()>
-
-        // Implicit Field (${implicitField.name})
-        lengthInBits += ${simpleTypeReference.sizeInBits};
-        <#break>
-    <#case "manualArray">
-        <#assign manualArrayField = field.asManualArrayField().orElseThrow()>
-        <#assign arrayElementTypeReference = 
manualArrayField.type.asArrayTypeReference().orElseThrow().getElementTypeReference()>
-
-        // Manual Array Field (${manualArrayField.name})
-        lengthInBits += ${helper.toParseExpression(manualArrayField, 
helper.intTypeReference, manualArrayField.lengthExpression, parserArguments)} * 
8;
-        <#break>
-    <#case "manual">
-        <#assign manualField = field.asManualField().orElseThrow()>
-
-        // Manual Field (${manualField.name})
-        lengthInBits += ${helper.toParseExpression(manualField, 
helper.intTypeReference, manualField.lengthExpression, parserArguments)};
-        <#break>
-    <#case "optional">
-        <#assign optionalField = field.asOptionalField().orElseThrow()>
-
-        // Optional Field (${optionalField.name})
-        if(${optionalField.name} != null) {
-        <#if optionalField.type.isSimpleTypeReference()>
-            <#assign simpleTypeReference = 
optionalField.type.asSimpleTypeReference().orElseThrow()>
-            <#if simpleTypeReference.isVstringTypeReference()>
-                <#assign vstringTypeReference = 
simpleTypeReference.asVstringTypeReference().orElseThrow()>
-            lengthInBits += ${helper.toSerializationExpression(optionalField, 
helper.intTypeReference, vstringTypeReference.getLengthExpression(), 
parserArguments)};
-            <#else>
-            lengthInBits += ${simpleTypeReference.sizeInBits};
-            </#if>
-        <#elseif helper.isEnumField(field)>
-            lengthInBits += 
${helper.getEnumBaseTypeReference(optionalField.type).sizeInBits};
-        <#elseif optionalField.type.isDataIoTypeReference()>
-            lengthInBits += 
${optionalField.type.asComplexTypeReference().orElseThrow().name}.getLengthInBits(${optionalField.name}<#if
 optionalField.type.asComplexTypeReference().orElseThrow().params?has_content>, 
<#list 
optionalField.type.asComplexTypeReference().orElseThrow().params.orElseThrow() 
as param>${helper.toParseExpression(optionalField, helper.anyTypeReference, 
param, parserArguments)}<#sep>, </#sep></#list></#if>);
-        <#else>
-            lengthInBits += ${optionalField.name}.getLengthInBits();
-        </#if>
-        }
-        <#break>
-    <#case "padding">
-        <#assign paddingField = field.asPaddingField().orElseThrow()>
-        <#assign simpleTypeReference = 
paddingField.type.asSimpleTypeReference().orElseThrow()>
-
-        // Padding Field (padding)
-        <#-- We're replacing the "lastItem" with 'false' here as the item 
itself can't know if it is the last -->
-        int _timesPadding = (int) (${helper.toParseExpression(paddingField, 
helper.intTypeReference, paddingField.paddingCondition, parserArguments)});
-        while (_timesPadding-- > 0) {
-            lengthInBits += ${simpleTypeReference.sizeInBits};
-        }
-        <#break>
-    <#case "reserved">
-        <#assign reservedField = field.asReservedField().orElseThrow()>
-        <#assign simpleTypeReference = 
reservedField.type.asSimpleTypeReference().orElseThrow()>
-
-        // Reserved Field (reserved)
-        lengthInBits += ${simpleTypeReference.sizeInBits};
-        <#break>
-    <#case "simple">
-        <#assign simpleField = field.asSimpleField().orElseThrow()>
-
-        // Simple field (${simpleField.name})
-        <#if simpleField.type.isSimpleTypeReference()>
-            <#assign simpleTypeReference = 
simpleField.type.asSimpleTypeReference().orElseThrow()>
-            <#if simpleTypeReference.isVstringTypeReference()>
-                <#assign vstringTypeReference = 
simpleTypeReference.asVstringTypeReference().orElseThrow()>
-        lengthInBits += ${helper.toSerializationExpression(simpleField, 
helper.intTypeReference, vstringTypeReference.getLengthExpression(), 
parserArguments)};
-            <#else>
-        lengthInBits += ${simpleTypeReference.sizeInBits};
-            </#if>
-        <#elseif helper.isEnumField(field)>
-        lengthInBits += 
${helper.getEnumBaseTypeReference(simpleField.type).sizeInBits};
-        <#elseif simpleField.type.isDataIoTypeReference()>
-        lengthInBits += 
${simpleField.type.asComplexTypeReference().orElseThrow().name}.getLengthInBits(${simpleField.name}<#if
 simpleField.type.asComplexTypeReference().orElseThrow().params?has_content>, 
<#list 
simpleField.type.asComplexTypeReference().orElseThrow().params.orElseThrow() as 
param>${helper.toParseExpression(simpleField, helper.anyTypeReference, param, 
parserArguments)}<#sep>, </#sep></#list></#if>);
-        <#else>
-        lengthInBits += ${simpleField.name}.getLengthInBits();
-        </#if>
-        <#break>
-    <#case "switch">
-        <#assign switchField = field.asSwitchField().orElseThrow()>
-
-        // Length of sub-type elements will be added by sub-type...
-        <#break>
-    <#case "unknown">
-        <#assign unknownField = field.asUnknownField().orElseThrow()>
-        <#assign simpleTypeReference = 
unknownField.type.asSimpleTypeReference().orElseThrow()>
-
-        // Unknown field
-        lengthInBits += ${simpleTypeReference.sizeInBits};
-        <#break>
-    <#case "virtual">
-        <#assign virtualField = field.asVirtualField().orElseThrow()>
-
-        // A virtual field doesn't have any in- or output.
-        <#break>
-</#switch>
-</#list>
-
-        return lengthInBits;
-    }
-
-<#-- The parse and serialize methods here are just proxies for forwardning the 
requests to static counterparts -->
-    <#if !type.isDiscriminatedChildTypeDefinition()>
-    public static ${type.name} staticParse(ReadBuffer readBuffer, Object... 
args) throws ParseException {
-        PositionAware positionAware = readBuffer;
-        <#if parserArguments?has_content>
-        if((args == null) || (args.length != ${parserArguments?size})) {
-            throw new PlcRuntimeException("Wrong number of arguments, expected 
${parserArguments?size}, but got " + args.length);
-        }
-            <#list parserArguments as parserArgument>
-                <#assign 
languageName=helper.getLanguageTypeNameForTypeReference(parserArgument.type, 
false)>
-        ${languageName} ${parserArgument.name};
-        if(args[${parserArgument?index}] instanceof ${languageName}) {
-            ${parserArgument.name} = (${languageName}) 
args[${parserArgument?index}];
-                <#if parserArgument.type.isSimpleTypeReference() || 
parserArgument.type.isEnumTypeReference()>
-        } else if (args[${parserArgument?index}] instanceof String) {
-            ${parserArgument.name} = ${languageName}.valueOf((String) 
args[${parserArgument?index}]);
-                </#if>
-        } else {
-            throw new PlcRuntimeException("Argument ${parserArgument?index} 
expected to be of type ${languageName} or a string which is parseable but was " 
+ args[${parserArgument?index}].getClass().getName());
+        </#list>
         }
-            </#list>
-        </#if>
-        return staticParse(readBuffer<#if parserArguments?has_content>, <#list 
parserArguments as parserArgument>${parserArgument.name}<#sep>, 
</#sep></#list></#if>);
     }
 
-    </#if>
-<#-- Here come the actual parse and serialize methods that actually do the 
parsing and serlaizing -->
-    <#assign hasParserArguments=parserArguments?has_content/>
-    <#assign parserArgumentList><#if hasParserArguments><#list parserArguments 
as 
parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type,
 false)} ${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
-    public static ${type.name}<#if 
type.isDiscriminatedChildTypeDefinition()>Builder staticParseBuilder<#else> 
staticParse</#if>(ReadBuffer readBuffer<#if hasParserArguments>, 
${parserArgumentList}</#if>) throws ParseException {
-        readBuffer.pullContext("${type.name}");
-        PositionAware positionAware = readBuffer;
-        int startPos = positionAware.getPos();
-        int curPos;
+    fn parse<T: Read>(reader: &mut ReadBuffer<T>, parameter: Option<Self::P>) 
-> Result<Self::M, Error> {
+    // (Re-)define the options
+    <#list type.parserArguments.orElseThrow() as arg>
+        let ${arg.name} = parameter.unwrap().${arg.name};
+    </#list>
     <#list type.fields as field>
-        <#switch field.typeName>
-            <#case "array">
-                <#assign arrayField = field.asArrayField().orElseThrow()>
-                <#assign typedField = field.asTypedField().orElseThrow()>
-                <#assign namedField = field.asNamedField().orElseThrow()>
-                <#assign arrayElementTypeReference = 
arrayField.type.asArrayTypeReference().orElseThrow().getElementTypeReference()>
-
-                <#if arrayElementTypeReference.isByteBased()>
-                    <#if !field.isCountArrayField() && 
!field.isLengthArrayField()>
-                        throw new ParseException("array fields of type byte 
only support 'count' and 'length' loop-types.");
-                    </#if>
-                    byte[] ${namedField.name} = 
readBuffer.readByteArray("${namedField.name}", 
Math.toIntExact(${helper.toParseExpression(arrayField, helper.intTypeReference, 
arrayField.loopExpression, 
parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});
-                <#else>
-                <#-- If this is a count array, we can directly initialize an 
array with the given size -->
-                    <#if field.isCountArrayField()>
-                        
${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)} 
${arrayField.name} = readCountArrayField("${arrayField.name}", 
${helper.getDataReaderCall(arrayField.type)}, 
${helper.toParseExpression(arrayField, helper.intTypeReference, 
arrayField.loopExpression, 
parserArguments)}${helper.getFieldOptions(typedField, parserArguments)});
-                    <#-- In all other cases do we have to work with a list, 
that is later converted to an array -->
-                    <#else>
-                    <#-- For a length array, we read data till the read 
position of the buffer reaches a given position -->
-                        <#if field.isLengthArrayField()>
-                            
${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)} 
${arrayField.name} = readLengthArrayField("${arrayField.name}", 
${helper.getDataReaderCall(arrayField.type)}, 
${helper.toParseExpression(arrayField, helper.intTypeReference, 
arrayField.loopExpression, 
parserArguments)}${helper.getFieldOptions(typedField, parserArguments)});
-                        <#-- A terminated array keeps on reading data as long 
as the termination expression evaluates to false -->
-                        <#elseif field.isTerminatedArrayField()>
-                            
${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)} 
${arrayField.name} = readTerminatedArrayField("${arrayField.name}", 
${helper.getDataReaderCall(arrayField.type)}, () -> ((boolean) 
(${helper.toParseExpression(arrayField, helper.intTypeReference, 
arrayField.loopExpression, 
parserArguments)}))${helper.getFieldOptions(typedField, parserArguments)});
-                        </#if>
-                    </#if>
-                </#if>
-                <#break>
-            <#case "assert">
-                <#assign assertField = field.asAssertField().orElseThrow()>
-                <#assign typedField = field.asTypedField().orElseThrow()>
-                <#assign namedField = field.asNamedField().orElseThrow()>
-
-                ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", 
${helper.getDataReaderCall(typedField.type)}, 
(${helper.getLanguageTypeNameForField(field)}) 
(${helper.toParseExpression(assertField, assertField.type, 
assertField.conditionExpression, 
parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});
-                <#break>
-            <#case "checksum">
-                <#assign checksumField = field.asChecksumField().orElseThrow()>
-                <#assign typedField = field.asTypedField().orElseThrow()>
-                <#assign namedField = field.asNamedField().orElseThrow()>
-
-                ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", 
${helper.getDataReaderCall(typedField.type)}, 
(${helper.getLanguageTypeNameForField(field)}) 
(${helper.toParseExpression(checksumField, checksumField.type, 
checksumField.checksumExpression, 
parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});
-                <#break>
-            <#case "const">
-                <#assign constField = field.asConstField().orElseThrow()>
-                <#assign typedField = field.asTypedField().orElseThrow()>
-                <#assign namedField = field.asNamedField().orElseThrow()>
-
-                ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", 
${helper.getDataReaderCall(typedField.type)}, 
${type.name}.${namedField.name?upper_case}${helper.getFieldOptions(typedField, 
parserArguments)});
-                <#break>
-            <#case "discriminator">
-                <#assign discriminatorField = 
field.asDiscriminatorField().orElseThrow()>
-                <#assign typedField = field.asTypedField().orElseThrow()>
-                <#assign namedField = field.asNamedField().orElseThrow()>
-
-                ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", 
${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField,
 parserArguments)});
-                <#break>
-            <#case "enum">
-                <#assign enumField = field.asEnumField().orElseThrow()>
-                <#assign typedField = field.asTypedField().orElseThrow()>
-                <#assign namedField = field.asNamedField().orElseThrow()>
-
-                ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", 
"${enumField.type.asNonSimpleTypeReference().orElseThrow().typeDefinition.name}",
 
readEnum(${enumField.type.asNonSimpleTypeReference().orElseThrow().typeDefinition.name}::firstEnumForField${enumField.fieldName?cap_first},
 ${helper.getDataReaderCall(helper.getEnumFieldTypeReference(enumField.type, 
enumField.fieldName))})${helper.getFieldOptions(typed [...]
-                <#break>
-            <#case "implicit">
-                <#assign implicitField = field.asImplicitField().orElseThrow()>
-                <#assign typedField = field.asTypedField().orElseThrow()>
-                <#assign namedField = field.asNamedField().orElseThrow()>
-
-                ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", 
${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField,
 parserArguments)});
-                <#break>
-            <#case "manualArray">
-                <#assign manualArrayField = 
field.asManualArrayField().orElseThrow()>
-                <#assign typedField = field.asTypedField().orElseThrow()>
-                <#assign namedField = field.asNamedField().orElseThrow()>
-                <#assign arrayElementTypeReference = 
manualArrayField.type.asArrayTypeReference().orElseThrow().getElementTypeReference()>
-
-                <#if arrayElementTypeReference.isByteBased()>
-                    byte[] ${namedField.name} = 
readManualByteArrayField("${namedField.name}", readBuffer, (byte[] _values) -> 
(boolean) (${helper.toParseExpression(manualArrayField, 
helper.boolTypeReference, manualArrayField.loopExpression, parserArguments)}), 
() -> (byte) (${helper.toParseExpression(manualArrayField, 
manualArrayField.type, manualArrayField.parseExpression, 
parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});
-                <#else>
-                    
${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)} 
${namedField.name} = readManualArrayField("${namedField.name}", readBuffer, 
(${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)} _values) 
-> (boolean) (${helper.toParseExpression(manualArrayField, 
helper.boolTypeReference, manualArrayField.loopExpression, parserArguments)}), 
() -> 
(${helper.getLanguageTypeNameForTypeReference(manualArrayField.type.elementTypeReference)})
 (${helper.toPa [...]
-                </#if>
-                <#break>
-            <#case "manual">
-                <#assign manualField = field.asManualField().orElseThrow()>
-                <#assign typedField = field.asTypedField().orElseThrow()>
-                <#assign namedField = field.asNamedField().orElseThrow()>
-
-                ${helper.getLanguageTypeNameForField(field)} 
${manualField.name} = readManualField("${namedField.name}", readBuffer, () -> 
(${helper.getLanguageTypeNameForField(manualField)}) 
(${helper.toParseExpression(manualField, manualField.type, 
manualField.parseExpression, 
parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});
-                <#break>
-            <#case "optional">
-                <#assign optionalField = field.asOptionalField().orElseThrow()>
-                <#assign typedField = field.asTypedField().orElseThrow()>
-                <#assign namedField = field.asNamedField().orElseThrow()>
-
-                ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", 
${helper.getDataReaderCall(typedField.type)}<#if 
optionalField.conditionExpression.present>, 
${helper.toParseExpression(optionalField, helper.boolTypeReference, 
optionalField.conditionExpression.get(), 
parserArguments)}</#if>${helper.getFieldOptions(typedField, parserArguments)});
-                <#break>
-            <#case "padding">
-                <#assign paddingField = field.asPaddingField().orElseThrow()>
-                <#assign typedField = field.asTypedField().orElseThrow()>
-                <#assign simpleTypeReference = 
paddingField.type.asSimpleTypeReference().orElseThrow()>
-
-                
read${field.typeName?cap_first}Field(${helper.getDataReaderCall(typedField.type)},
 (int) (${helper.toParseExpression(paddingField, paddingField.type, 
paddingField.paddingCondition, 
parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});
-                <#break>
-            <#case "reserved">
-                <#assign reservedField = field.asReservedField().orElseThrow()>
-                <#assign typedField = field.asTypedField().orElseThrow()>
-
-                read${field.typeName?cap_first}Field("reserved", 
${helper.getDataReaderCall(typedField.type)}, 
${helper.getReservedValue(reservedField)}${helper.getFieldOptions(typedField, 
parserArguments)});
-                <#break>
-            <#case "simple">
-                <#assign simpleField = field.asSimpleField().orElseThrow()>
-                <#assign typedField = field.asTypedField().orElseThrow()>
-                <#assign namedField = field.asNamedField().orElseThrow()>
-
-                ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = <#if 
typedField.type.isEnumTypeReference()>readEnumField("${namedField.name}", 
"${helper.getLanguageTypeNameForField(field)}", 
${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField,
 
parserArguments)});<#else>read${field.typeName?cap_first}Field("${namedField.name}",
 
${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField,
 parserArguments)});</#if>
-                <#break>
-            <#case "switch">
-                <#assign switchField = field.asSwitchField().orElseThrow()>
-
-                // Switch Field (Depending on the discriminator values, passes 
the instantiation to a sub-type)
-                ${type.name}Builder builder = null;
-                <#list switchField.cases as case>
-                    <@compress single_line=true>
-                        <#if case.discriminatorValueTerms?has_content>
-                            if(
-                            <#list case.discriminatorValueTerms as 
discriminatorValueTerm>
-                                <#if helper.isWildcard(discriminatorValueTerm)>
-                                    true
-                                <#else>
-                                    <#assign 
discriminatorExpression=switchField.discriminatorExpressions[discriminatorValueTerm?index].asLiteral().orElseThrow().asVariableLiteral().orElseThrow()>
-                                    <#assign 
discriminatorType=helper.getDiscriminatorTypes()[discriminatorExpression.discriminatorName]>
-                                    EvaluationHelper.equals(
-                                    ${helper.toParseExpression(switchField, 
discriminatorType, discriminatorExpression, parserArguments)},
-                                    <#if 
discriminatorType.isEnumTypeReference()>
-                                        
${helper.getLanguageTypeNameForTypeReference(discriminatorType)}.${helper.toParseExpression(switchField,
 discriminatorType, discriminatorValueTerm, parserArguments)}
-                                    <#else>
-                                        
(${helper.getLanguageTypeNameForTypeReference(discriminatorType, true)}) 
${helper.toParseExpression(switchField, discriminatorType, 
discriminatorValueTerm, parserArguments)}
-                                    </#if>
-                                    )
-                                </#if>
-                                <#sep> && </#sep>
-                            </#list>
-                            )
-                        </#if>{
-                    </@compress>
-                    <@compress single_line=true>
-                        <#assign 
hasCaseParseArguments=case.allParserArguments.isPresent() && 
case.allParserArguments.orElseThrow()?has_content>
-                        <#assign caseParseArguments><#if 
hasCaseParseArguments><#list case.allParserArguments.orElseThrow() as 
parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
-                        builder = 
${case.name}.staticParseBuilder(readBuffer<#if hasCaseParseArguments>, 
${tracer.dive("case parse arguments")} ${caseParseArguments}</#if>);
-                    </@compress>
-                    }<#sep> else </#sep>
-                </#list>
-                if (builder == null) {
-                    throw new ParseException("Unsupported case for 
discriminated type");
-                }
-                <#break>
-            <#case "unknown">
-                <#assign unknownField = field.asUnknownField().orElseThrow()>
-                <#assign typedField = field.asTypedField().orElseThrow()>
-
-                read${field.typeName?cap_first}Field("unknown", 
${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField,
 parserArguments)});
-                <#break>
-            <#case "virtual">
-                <#assign virtualField = field.asVirtualField().orElseThrow()>
-                <#assign typedField = field.asTypedField().orElseThrow()>
-                <#assign namedField = field.asNamedField().orElseThrow()>
-                ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", 
${helper.getLanguageTypeNameForField(field)}.class, 
${helper.toParseExpression(virtualField, virtualField.type, 
virtualField.valueExpression, 
parserArguments)}${helper.getFieldOptions(typedField, parserArguments)});
-                <#break>
-            <#case "validation">
-                <#assign validationField = 
field.asValidationField().orElseThrow()>
-                // Validation
-                if (!(${helper.toParseExpression(validationField, 
helper.boolTypeReference, validationField.getValidationExpression(), null)})) {
-                    <#assign errorType="ParseValidationException">
-                    <#if !validationField.shouldFail()><#assign 
errorType="ParseAssertException"></#if>
-                    throw new 
${errorType}(${validationField.getDescription().orElse("\"Validation 
failed\"")});
-                }
-                <#break>
-            <#case "peek">
-                <#assign peekField = field.asPeekField().orElseThrow()>
-                <#assign typedField = field.asTypedField().orElseThrow()>
-                <#assign namedField = field.asNamedField().orElseThrow()>
-
-                ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", 
${helper.getDataReaderCall(typedField.type)}<#if 
peekField.offsetExpression.present>, ${helper.toParseExpression(peekField, 
helper.boolTypeReference, peekField.offsetExpression.get(), 
parserArguments)}</#if>${helper.getFieldOptions(typedField, parserArguments)});
-                <#break>
-        </#switch>
+        ${helper.generateFieldParseCode(field)}
     </#list>
-
-    readBuffer.closeContext("${type.name}");
-    // Create the instance
-    <#if type.isDiscriminatedChildTypeDefinition()>
-        return new ${type.name}Builder(<#list type.propertyFields as 
field>${field.name}<#sep>, </#sep></#list><#if 
filteredParserArguments?has_content><#if type.propertyFields?has_content>, 
</#if><#list filteredParserArguments as arg>${arg.name}<#sep>, 
</#sep></#list></#if>);
-    <#elseif type.isDiscriminatedParentTypeDefinition()>
-        return builder.build(<#list type.propertyFields as 
field>${field.name}<#sep>, </#sep></#list><#if 
filteredParserArguments?has_content><#if type.propertyFields?has_content>, 
</#if><#list filteredParserArguments as arg>${arg.name}<#sep>, 
</#sep></#list></#if>);
-    <#else>
-        return new ${type.name}(<#list type.propertyFields as 
field>${field.name}<#sep>, </#sep></#list><#if 
filteredParserArguments?has_content><#if type.propertyFields?has_content>, 
</#if><#list filteredParserArguments as arg>${arg.name}<#sep>, 
</#sep></#list></#if>);
-    </#if>
-    }
-
-    <#if type.isDiscriminatedParentTypeDefinition()>
-        public static interface ${type.name}Builder {
-            ${type.name} build(<#list type.propertyFields as 
field>${helper.getLanguageTypeNameForField(field)} ${field.name}<#sep>, 
</#sep></#list><#if filteredParserArguments?has_content><#if 
type.propertyFields?has_content>, </#if><#list filteredParserArguments as 
arg>${helper.getLanguageTypeNameForTypeReference(arg.type)} ${arg.name}<#sep>, 
</#sep></#list></#if>);
-        }
-
-    </#if>
-    <#if type.isDiscriminatedChildTypeDefinition()>
-        public static class ${type.name}Builder implements 
${type.parentType.orElseThrow().name}.${type.parentType.orElseThrow().name}Builder
 {
-        <#if type.propertyFields?has_content>
-            <#list type.propertyFields as field>
-                private final ${helper.getLanguageTypeNameForField(field)} 
${field.name};
-            </#list>
-        </#if>
-        <#if filteredParserArguments?has_content>
-            <#list filteredParserArguments as arg>
-                private final 
${helper.getLanguageTypeNameForTypeReference(arg.type)} ${arg.name};
-            </#list>
-        </#if>
-
-        public ${type.name}Builder(<#list type.propertyFields as 
field>${helper.getLanguageTypeNameForField(field)} ${field.name}<#sep>, 
</#sep></#list><#if filteredParserArguments?has_content><#if 
type.propertyFields?has_content>, </#if><#list filteredParserArguments as 
arg>${helper.getLanguageTypeNameForTypeReference(arg.type)} ${arg.name}<#sep>, 
</#sep></#list></#if>) {
-        <#list type.propertyFields as field>
-            this.${field.name} = ${field.name};
-        </#list>
-        <#if filteredParserArguments?has_content>
-            <#list filteredParserArguments as arg>
-            this.${arg.name} = ${arg.name};
-            </#list>
-        </#if>
-        }
-
-        public ${type.name} build(<#list 
type.parentType.orElseThrow().asComplexTypeDefinition().orElseThrow().propertyFields
 as field>${helper.getLanguageTypeNameForField(field)} ${field.name}<#sep>, 
</#sep></#list><#if filteredParentParserArguments?has_content><#if 
type.parentType.orElseThrow().asComplexTypeDefinition().orElseThrow().propertyFields?has_content>,
 </#if><#list filteredParentParserArguments as 
arg>${helper.getLanguageTypeNameForTypeReference(arg.type)} ${arg.name}<#sep>,  
[...]
-            return new ${type.name}(<#list type.allPropertyFields as 
field>${field.name}<#sep>, </#sep></#list><#if 
filteredParserArguments?has_content><#if type.allPropertyFields?has_content>, 
</#if><#list filteredParserArguments as arg>${arg.name}<#sep>, 
</#sep></#list></#if>);
-        }
-    }
-
-    </#if>
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (!(o instanceof ${type.name})) {
-            return false;
-        }
-        ${type.name} that = (${type.name}) o;
-        return
-            <#if type.propertyFields?has_content>
-            <#list type.propertyFields as field>
-            (get${field.name?cap_first}() == 
that.get${field.name?cap_first}()) &&
-            </#list>
-            </#if>
-            <#if type.parentType.isPresent()>
-            super.equals(that) &&
-            </#if>
-            true;
     }
+}
+<#else>
+pub struct ${type.name} {
+}
+</#if>
 
-    @Override
-    public int hashCode() {
-        return Objects.hash(
-            <#if type.parentType.isPresent()>
-            super.hashCode()<#if type.propertyFields?has_content>,</#if>
-            </#if>
-            <#if type.propertyFields?has_content>
-            <#list type.propertyFields as field>
-            get${field.name?cap_first}()<#sep>,</#sep>
-            </#list>
-            </#if>
-        );
-    }
 
-    @Override
-    public String toString() {
-        WriteBufferBoxBased writeBufferBoxBased = new 
WriteBufferBoxBased(true, true);
-        try {
-            serialize(writeBufferBoxBased);
-        } catch (SerializationException e) {
-            throw new RuntimeException(e);
-        }
-        return "\n" + writeBufferBoxBased.getBox().toString()+ "\n";
-    }
-}
+<#--&lt;#&ndash; TODO: the code below implies that parserArguments will be 
null if not present... not pretty  &ndash;&gt;-->
+<#--<#if type.parserArguments.isPresent()><#assign 
parserArguments=type.allParserArguments.orElseThrow()></#if>-->
+<#--public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> 
class ${type.name}<#if type.isDiscriminatedParentTypeDefinition()></#if><#if 
type.parentType.isPresent()> extends 
${type.parentType.orElseThrow().name}</#if> implements Message {-->
+
+<#--&lt;#&ndash;-->
+<#--    If this is a discriminated child type, we need to generate methods for 
accessing it's discriminator-->
+<#--    values, as if they were normal java properties.-->
+<#--&ndash;&gt;-->
+<#--<#if type.isDiscriminatedChildTypeDefinition()>-->
+<#--    <#assign discriminatedChildType = 
type.asDiscriminatedComplexTypeDefinition().orElseThrow()>-->
+<#--    // Accessors for discriminator values.-->
+<#--    <#list discriminatedChildType.getDiscriminatorMap() as 
discriminatorName, discriminatorValue>-->
+<#--        &lt;#&ndash; If the discriminator name matches that of another 
field, suppress the methods generation &ndash;&gt;-->
+<#--        <#if 
!discriminatedChildType.isNonDiscriminatorField(discriminatorName)>&lt;#&ndash;&&
 !discriminatedChildType.isParserArgument(discriminatorName)&ndash;&gt;-->
+<#--            <#assign discriminatorType = 
helper.getDiscriminatorTypes()[discriminatorName]>-->
+<#--    public 
${helper.getLanguageTypeNameForTypeReference(discriminatorType)} 
get${discriminatorName?cap_first}() {-->
+<#--            <#if discriminatorValue?? && 
!helper.isWildcard(discriminatorValue)>-->
+<#--                <#if discriminatorType.isEnumTypeReference()>-->
+<#--        return 
${helper.getLanguageTypeNameForTypeReference(discriminatorType)}.${helper.toParseExpression(null,
 discriminatorType, discriminatorValue, parserArguments)};-->
+<#--                <#else>-->
+<#--        return 
(${helper.getLanguageTypeNameForTypeReference(discriminatorType, true)}) 
${helper.toParseExpression(null, discriminatorType, discriminatorValue, 
parserArguments)};-->
+<#--                </#if>-->
+<#--            <#else>-->
+<#--        return 
${helper.getNullValueForTypeReference(discriminatorType)};-->
+<#--            </#if>-->
+<#--    }-->
+<#--        </#if>-->
+<#--    </#list>-->
+<#--</#if>-->
+<#--&lt;#&ndash;-->
+<#--    If this is a discriminated parent type, we need to generate the 
abstract methods for accessing it's-->
+<#--    discriminator values instead.-->
+<#--&ndash;&gt;-->
+<#--<#if type.isDiscriminatedParentTypeDefinition()>-->
+<#--    <#assign discriminatedParentType = type>-->
+<#--    &lt;#&ndash; @ftlvariable name="discriminatedParentType" 
type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition"
 &ndash;&gt;-->
+<#--    // Abstract accessors for discriminator values.-->
+<#--    <#list helper.discriminatorTypes as discriminatorName, 
discriminatorType>-->
+<#--        &lt;#&ndash; If the discriminator name matches that of another 
field, suppress the methods generation &ndash;&gt;-->
+<#--        <#if !type.isNonDiscriminatorField(discriminatorName)>&lt;#&ndash; 
&& !type.isParserArgument(discriminatorName)&ndash;&gt;-->
+<#--    public abstract 
${helper.getLanguageTypeNameForTypeReference(discriminatorType)} 
get${discriminatorName?cap_first}();-->
+<#--        </#if>-->
+<#--    </#list>-->
+<#--</#if>-->
+<#--&lt;#&ndash; If the current type contains "const" fields, generate some 
java constants for holing their values &ndash;&gt;-->
+<#--<#if type.constFields?has_content>-->
+
+<#--    // Constant values.-->
+<#--    <#list type.constFields as field>-->
+<#--    public static final 
${helper.getLanguageTypeNameForTypeReference(field.type)} 
${field.name?upper_case} = ${helper.toParseExpression(field, field.type, 
field.referenceValue, parserArguments)};-->
+<#--    </#list>-->
+<#--</#if>-->
+<#--&lt;#&ndash; Property fields are fields that require a property in the 
pojo &ndash;&gt;-->
+<#--<#if type.propertyFields?has_content>-->
+
+<#--    // Properties.-->
+<#--    <#list type.propertyFields as field>-->
+<#--    protected final 
${helper.getLanguageTypeNameForTypeReference(field.type, 
!field.isOptionalField())} ${field.name};-->
+<#--    </#list>-->
+<#--</#if>-->
+<#--<#if parserArguments?has_content>-->
+<#--  <#assign filteredParserArguments=parserArguments?filter(arg -> 
!type.isDiscriminatorField(arg.name) && 
!type.getPropertyFieldFromThisOrParentByName(arg.name).isPresent())>-->
+<#--</#if>-->
+<#--<#if filteredParserArguments?has_content>-->
+
+<#--    // Arguments.-->
+<#--    <#list filteredParserArguments as parserArgument>-->
+<#--    protected final 
${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} 
${parserArgument.name};-->
+<#--    </#list>-->
+<#--</#if>-->
+
+<#--    &lt;#&ndash; getAllPropertyFields() returns not only the property 
fields of this type but also of it's parents &ndash;&gt;-->
+<#--    <@compress single_line=true>-->
+<#--    public ${type.name}(-->
+<#--        <#list type.getAllPropertyFields() as field>-->
+<#--            ${helper.getLanguageTypeNameForField(field)} ${field.name}-->
+<#--            <#sep>, </#sep>-->
+<#--        </#list>-->
+<#--        <#if filteredParserArguments?has_content>-->
+<#--            <#if type.getAllPropertyFields()?has_content>, </#if>-->
+<#--            <#list filteredParserArguments as parserArgument>-->
+<#--                
${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} 
${parserArgument.name}-->
+<#--                <#sep>, </#sep>-->
+<#--            </#list>-->
+<#--        </#if>-->
+<#--        ) {-->
+<#--    </@compress>-->
+
+<#--    <@compress single_line=true>-->
+<#--        super(-->
+<#--        <#if type.parentPropertyFields?has_content>-->
+<#--            <#list type.parentPropertyFields as field>-->
+<#--                ${field.name}-->
+<#--                <#sep>, </#sep>-->
+<#--            </#list>-->
+<#--        </#if>-->
+<#--        <#if type.parentType.isPresent() && 
type.parentType.orElseThrow().allParserArguments.isPresent()>-->
+<#--            <#assign filteredParentParserArguments = 
type.parentType.orElseThrow().allParserArguments.orElseThrow()?filter(arg -> 
!type.parentType.orElseThrow().asComplexTypeDefinition().orElseThrow().isDiscriminatorField(arg.name))>-->
+<#--            <#if filteredParentParserArguments?has_content>-->
+<#--                <#if type.parentPropertyFields?has_content>, </#if>-->
+<#--                <#list filteredParentParserArguments as parserArgument>-->
+<#--                    ${parserArgument.name}-->
+<#--                    <#sep>, </#sep>-->
+<#--                </#list>-->
+<#--            </#if>-->
+<#--        </#if>-->
+<#--        );-->
+<#--    </@compress>-->
+
+<#--<#list type.propertyFields as field>-->
+<#--        this.${field.name} = ${field.name};-->
+<#--</#list>-->
+<#--<#if filteredParserArguments?has_content>-->
+<#--    <#list filteredParserArguments as parserArgument>-->
+<#--        this.${parserArgument.name} = ${parserArgument.name};-->
+<#--    </#list>-->
+<#--</#if>-->
+<#--    }-->
+
+<#--<#list type.abstractFields as field>-->
+<#--    public abstract ${helper.getLanguageTypeNameForField(field)} 
get${field.asNamedField().orElseThrow().name?cap_first}();-->
+
+<#--</#list>-->
+<#--<#list type.propertyFields as field>-->
+<#--    public ${helper.getLanguageTypeNameForField(field)} 
get${field.name?cap_first}() {-->
+<#--        return ${field.name};-->
+<#--    }-->
+
+<#--</#list>-->
+<#--<#list type.virtualFields as field>-->
+<#--    public ${helper.getLanguageTypeNameForField(field)} 
get${field.name?cap_first}() {-->
+<#--        <#if helper.getLanguageTypeNameForField(field) = 'String'>-->
+<#--        return 
${helper.getLanguageTypeNameForField(field)}.valueOf(${helper.toSerializationExpression(field,
 field.type, field.valueExpression, parserArguments)});-->
+<#--        &lt;#&ndash;elseif helper.getLanguageTypeNameForField(field) = 
'BigInteger' && !helper.isBigIntegerSource(field.valueExpression)&ndash;&gt;-->
+<#--        <#elseif helper.getLanguageTypeNameForField(field) = 
'BigInteger'>-->
+<#--        Object o = ${helper.toSerializationExpression(field, field.type, 
field.valueExpression, parserArguments)};-->
+<#--        if (o instanceof BigInteger)-->
+<#--            return (BigInteger) o;-->
+<#--        return BigInteger.valueOf(((Number)o).longValue());-->
+<#--        <#else>-->
+<#--        return (${helper.getLanguageTypeNameForField(field)}) 
(${helper.toSerializationExpression(field, field.type, field.valueExpression, 
parserArguments)});-->
+<#--        </#if>-->
+<#--    }-->
+
+<#--</#list>-->
+<#--<#list type.constFields as field>-->
+<#--    public ${helper.getLanguageTypeNameForField(field)} 
get${field.name?cap_first}() {-->
+<#--        return ${field.name?upper_case};-->
+<#--    }-->
+
+<#--</#list>-->
+
+<#--    <#if outputFlavor != "passive">-->
+<#--<#if type.isDiscriminatedChildTypeDefinition()>-->
+<#--    @Override-->
+<#--    protected void 
serialize${type.parentType.orElseThrow().name}Child(WriteBuffer writeBuffer) 
throws SerializationException {-->
+<#--<#else>-->
+<#--    <#if type.isDiscriminatedParentTypeDefinition()>-->
+<#--    abstract protected void 
serialize${type.name?cap_first}Child(WriteBuffer writeBuffer) throws 
SerializationException;-->
+
+<#--    </#if>-->
+<#--    public void serialize(WriteBuffer writeBuffer) throws 
SerializationException {-->
+<#--</#if>-->
+<#--        PositionAware positionAware = writeBuffer;-->
+<#--        <#if helper.hasFieldOfType("unknown")>-->
+<#--            throw new SerializationException("Unknown field not 
serializable");-->
+<#--        <#else>-->
+<#--            int startPos = positionAware.getPos();-->
+<#--            writeBuffer.pushContext("${type.name}");-->
+<#--            <#list type.fields as field>-->
+<#--                <#switch field.typeName>-->
+<#--                    <#case "array">-->
+<#--                        <#assign arrayField = 
field.asArrayField().orElseThrow()>-->
+<#--                        <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                        <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+
+<#--                        // Array Field (${arrayField.name})-->
+<#--                        <#if 
arrayField.type.elementTypeReference.isByteBased()>-->
+<#--                        writeByteArrayField("${namedField.name}", 
${namedField.name}, writeByteArray(writeBuffer, 8));-->
+<#--                        <#elseif 
arrayField.type.elementTypeReference.isSimpleTypeReference()>-->
+<#--                        writeSimpleTypeArrayField("${namedField.name}", 
${namedField.name}, 
${helper.getDataWriterCall(arrayField.type.elementTypeReference, 
namedField.name)});-->
+<#--                        <#else>-->
+<#--                        writeComplexTypeArrayField("${namedField.name}", 
${namedField.name}, writeBuffer);-->
+<#--                        </#if>-->
+<#--                        <#break>-->
+<#--                    <#case "checksum">-->
+<#--                        <#assign checksumField = 
field.asChecksumField().orElseThrow()>-->
+<#--                        <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                        <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+
+<#--                        // Checksum Field (checksum) (Calculated)-->
+<#--                        writeChecksumField("${namedField.name}", 
(${helper.getLanguageTypeNameForField(field)}) 
(${helper.toParseExpression(checksumField, checksumField.type, 
checksumField.checksumExpression, parserArguments)}), 
${helper.getDataWriterCall(typedField.type, namedField.name)});-->
+<#--                        <#break>-->
+<#--                    <#case "const">-->
+<#--                        <#assign constField = 
field.asConstField().orElseThrow()>-->
+<#--                        <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                        <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+
+<#--                        // Const Field (${constField.name})-->
+<#--                        <#if 
typedField.type.isEnumTypeReference()>writeConstField("${constField.name}", 
${namedField.name?upper_case}.getValue(), 
${helper.getDataWriterCall(helper.getEnumBaseTypeReference(typedField.type), 
namedField.name)});<#else>writeConstField("${constField.name}", 
${namedField.name?upper_case}, ${helper.getDataWriterCall(typedField.type, 
namedField.name)});</#if>-->
+<#--                        <#break>-->
+<#--                    <#case "discriminator">-->
+<#--                        <#assign discriminatorField = 
field.asDiscriminatorField().orElseThrow()>-->
+<#--                        <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                        <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+
+<#--                        // Discriminator Field 
(${discriminatorField.name}) (Used as input to a switch field)-->
+<#--                        <#if 
typedField.type.isEnumTypeReference()>writeDiscriminatorEnumField("${namedField.name}",
 "${helper.getLanguageTypeNameForField(field)}", 
get${discriminatorField.name?cap_first}(), 
${helper.getEnumDataWriterCall(typedField.type, namedField.name, 
"value")});<#else>writeDiscriminatorField("${namedField.name}", 
get${discriminatorField.name?cap_first}(), 
${helper.getDataWriterCall(typedField.type, namedField.name)});</#if>-->
+<#--                        <#break>-->
+<#--                    <#case "enum">-->
+<#--                        <#assign enumField = 
field.asEnumField().orElseThrow()>-->
+<#--                        <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                        <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+
+<#--                        // Enum field (${namedField.name})-->
+<#--                        writeEnumField("${namedField.name}", 
"${helper.getLanguageTypeNameForField(field)}", ${namedField.name}, 
${helper.getEnumDataWriterCall(typedField.type, namedField.name, 
enumField.fieldName)});-->
+<#--                        <#break>-->
+<#--                    <#case "implicit">-->
+<#--                        <#assign implicitField = 
field.asImplicitField().orElseThrow()>-->
+<#--                        <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                        <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+
+<#--                        // Implicit Field (${implicitField.name}) (Used 
for parsing, but its value is not stored as it's implicitly given by the 
objects content)-->
+<#--                        &lt;#&ndash; Implicit field values might be used 
in expressions, in order to avoid problems, we generate a temporary variable 
with the given name. &ndash;&gt;-->
+<#--                        ${helper.getLanguageTypeNameForField(field)} 
${implicitField.name} = (${helper.getLanguageTypeNameForField(field)}) 
(${helper.toSerializationExpression(implicitField, implicitField.type, 
implicitField.serializeExpression, parserArguments)});-->
+<#--                        writeImplicitField("${namedField.name}", 
${implicitField.name}, ${helper.getDataWriterCall(typedField.type, 
namedField.name)});-->
+<#--                        <#break>-->
+<#--                    <#case "manualArray">-->
+<#--                        <#assign manualArrayField = 
field.asManualArrayField().orElseThrow()>-->
+<#--                        <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                        <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+
+<#--                        // Manual Array Field (${manualArrayField.name})-->
+<#--                        writeManualArrayField("${namedField.name}", 
${namedField.name}, 
(${helper.getLanguageTypeNameForTypeReference(manualArrayField.type.elementTypeReference)}
 _value) -> ${helper.toParseExpression(manualArrayField, 
manualArrayField.type.elementTypeReference, 
manualArrayField.serializeExpression, parserArguments)}, writeBuffer);-->
+<#--                        <#break>-->
+<#--                    <#case "manual">-->
+<#--                        <#assign manualField = 
field.asManualField().orElseThrow()>-->
+<#--                        <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                        <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+
+<#--                        // Manual Field (${manualField.name})-->
+<#--                        writeManualField("${namedField.name}", () -> 
${helper.toParseExpression(manualField, manualField.type, 
manualField.serializeExpression, parserArguments)}, writeBuffer);-->
+<#--                        <#break>-->
+<#--                    <#case "optional">-->
+<#--                        <#assign optionalField = 
field.asOptionalField().orElseThrow()>-->
+<#--                        <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                        <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+
+<#--                        // Optional Field (${optionalField.name}) (Can be 
skipped, if the value is null)-->
+<#--                        <#if optionalField.type.isEnumTypeReference()>-->
+<#--                            
writeOptionalEnumField("${optionalField.name}", 
"${helper.getLanguageTypeNameForField(field)}", ${optionalField.name}, 
${helper.getEnumDataWriterCall(optionalField.type, optionalField.name, 
"value")}<#if optionalField.conditionExpression.present>, 
${helper.toSerializationExpression(optionalField, helper.boolTypeReference, 
optionalField.conditionExpression.get(), parserArguments)}</#if>);-->
+<#--                        <#elseif 
optionalField.type.isDataIoTypeReference()>-->
+<#--                            writeOptionalField("${optionalField.name}", 
${optionalField.name}, new DataWriterDataIoDefault(writeBuffer, (wb, val) -> 
${optionalField.type.asComplexTypeReference().orElseThrow().name}.staticSerialize(wb,
 val<#if 
optionalField.type.asComplexTypeReference().orElseThrow().params?has_content>, 
<#list 
optionalField.type.asComplexTypeReference().orElseThrow().params.orElseThrow() 
as param>${helper.toParseExpression(optionalField, helper.anyTypeReference, 
para [...]
+<#--                        <#else>-->
+<#--                            writeOptionalField("${optionalField.name}", 
${optionalField.name}, ${helper.getDataWriterCall(typedField.type, 
optionalField.name)}<#if optionalField.conditionExpression.present>, 
${helper.toSerializationExpression(optionalField, helper.boolTypeReference, 
optionalField.conditionExpression.get(), parserArguments)}</#if>);-->
+<#--                        </#if>-->
+<#--                        <#break>-->
+<#--                    <#case "padding">-->
+<#--                        <#assign paddingField = 
field.asPaddingField().orElseThrow()>-->
+<#--                        <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+
+<#--                        // Padding Field (padding)-->
+<#--                        writePaddingField("padding", (int) 
(${helper.toParseExpression(paddingField, helper.intTypeReference, 
paddingField.paddingCondition, parserArguments)}), 
(${helper.getLanguageTypeNameForField(field)}) 
${helper.toSerializationExpression(paddingField, paddingField.type, 
paddingField.paddingValue, parserArguments)}, 
${helper.getDataWriterCall(typedField.type, "padding")});-->
+<#--                        <#break>-->
+<#--                    <#case "reserved">-->
+<#--                        <#assign reservedField = 
field.asReservedField().orElseThrow()>-->
+<#--                        <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+
+<#--                        // Reserved Field (reserved)-->
+<#--                        writeReservedField("reserved", 
${helper.getReservedValue(reservedField)}, 
${helper.getDataWriterCall(typedField.type, "reserved")});-->
+<#--                        <#break>-->
+<#--                    <#case "simple">-->
+<#--                        <#assign simpleField = 
field.asSimpleField().orElseThrow()>-->
+<#--                        <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                        <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+
+<#--                        // Simple Field (${namedField.name})-->
+<#--                        <#if typedField.type.isEnumTypeReference()>-->
+<#--                            writeSimpleEnumField("${simpleField.name}", 
"${helper.getLanguageTypeNameForField(field)}", ${simpleField.name}, 
${helper.getEnumDataWriterCall(simpleField.type, simpleField.name, 
"value")});-->
+<#--                        <#elseif 
simpleField.type.isDataIoTypeReference()>-->
+<#--                            writeSimpleField("${simpleField.name}", 
${simpleField.name}, new DataWriterDataIoDefault(writeBuffer, (wb, val) -> 
${simpleField.type.asComplexTypeReference().orElseThrow().name}.staticSerialize(wb,
 val<#if 
simpleField.type.asComplexTypeReference().orElseThrow().params?has_content>, 
<#list 
simpleField.type.asComplexTypeReference().orElseThrow().params.orElseThrow() as 
param>${helper.toParseExpression(simpleField, helper.anyTypeReference, param, 
parserArgum [...]
+<#--                        <#else>-->
+<#--                            writeSimpleField("${simpleField.name}", 
${simpleField.name}, ${helper.getDataWriterCall(typedField.type, 
simpleField.name)}${helper.getFieldOptions(typedField, 
parserArguments)});</#if>-->
+<#--                        <#break>-->
+<#--                    <#case "switch">-->
+<#--                        <#assign switchField = 
field.asSwitchField().orElseThrow()>-->
+
+<#--                        // Switch field (Serialize the sub-type)-->
+<#--                        
serialize${type.name?cap_first}Child(writeBuffer);-->
+<#--                        <#break>-->
+<#--                    <#case "virtual">-->
+<#--                        <#assign virtualField = 
field.asVirtualField().orElseThrow()>-->
+<#--                        <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                        <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+
+<#--                        // Virtual field (doesn't actually serialize 
anything, just makes the value available)-->
+<#--                        ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = get${namedField.name?cap_first}();-->
+<#--                        writeBuffer.writeVirtual("${namedField.name}", 
${namedField.name});-->
+<#--                        <#break>-->
+<#--                </#switch>-->
+<#--            </#list>-->
+
+<#--            writeBuffer.popContext("${type.name}");-->
+<#--        </#if>-->
+<#--        }-->
+<#--    </#if>-->
+
+<#--    @Override-->
+<#--    public int getLengthInBytes() {-->
+<#--        return (int) Math.ceil((float) getLengthInBits() / 8.0);-->
+<#--    }-->
+
+<#--    @Override-->
+<#--    public int getLengthInBits() {-->
+<#--        int lengthInBits = <#if 
type.parentType.isPresent()>super.getLengthInBits()<#else>0</#if>;-->
+<#--        ${type.name} _value  = this;-->
+<#--<#list type.fields as field>-->
+<#--<#switch field.typeName>-->
+<#--    <#case "array">-->
+<#--        <#assign arrayField = field.asArrayField().orElseThrow()>-->
+<#--        <#assign arrayElementTypeReference = 
arrayField.type.asArrayTypeReference().orElseThrow().getElementTypeReference()>-->
+
+<#--        // Array field-->
+<#--        if(${arrayField.name} != null) {-->
+<#--        <#if arrayElementTypeReference.isSimpleTypeReference()>-->
+<#--            <#assign simpleTypeReference = 
arrayElementTypeReference.asSimpleTypeReference().orElseThrow()>-->
+<#--            lengthInBits += ${simpleTypeReference.sizeInBits} * 
${arrayField.name}.<#if 
arrayElementTypeReference.isByteBased()>length<#else>size()</#if>;-->
+<#--        <#elseif arrayField.isCountArrayField()>-->
+<#--            int i=0;-->
+<#--            <#assign nonSimpleTypeReference = 
arrayElementTypeReference.asNonSimpleTypeReference().orElseThrow()>-->
+<#--            for(${nonSimpleTypeReference.name} element : 
${arrayField.name}) {-->
+<#--                boolean last = ++i >= ${arrayField.name}.size();-->
+<#--                lengthInBits += element.getLengthInBits();-->
+<#--            }-->
+<#--        <#else>-->
+<#--            for(Message element : ${arrayField.name}) {-->
+<#--                lengthInBits += element.getLengthInBits();-->
+<#--            }-->
+<#--        </#if>-->
+<#--        }-->
+<#--        <#break>-->
+<#--    <#case "checksum">-->
+<#--        <#assign checksumField = field.asChecksumField().orElseThrow()>-->
+<#--        <#assign typedField = field.asTypedField().orElseThrow()>-->
+<#--        <#assign simpleTypeReference = 
typedField.type.asSimpleTypeReference().orElseThrow()>-->
+
+<#--        // Checksum Field (checksum)-->
+<#--        lengthInBits += ${simpleTypeReference.sizeInBits};-->
+<#--        <#break>-->
+<#--    <#case "const">-->
+<#--        <#assign constField = field.asConstField().orElseThrow()>-->
+<#--        <#assign typedField = field.asTypedField().orElseThrow()>-->
+
+<#--        // Const Field (${constField.name})-->
+<#--        <#if typedField.type.isSimpleTypeReference()>-->
+<#--        <#assign simpleTypeReference = 
typedField.type.asSimpleTypeReference().orElseThrow()>-->
+<#--        lengthInBits += ${simpleTypeReference.sizeInBits};-->
+<#--        <#else>-->
+<#--        lengthInBits += 
${helper.getEnumBaseTypeReference(typedField.type).sizeInBits};-->
+<#--        </#if>-->
+<#--        <#break>-->
+<#--    <#case "discriminator">-->
+<#--        <#assign discriminatorField = 
field.asDiscriminatorField().orElseThrow()>-->
+
+<#--        // Discriminator Field (${discriminatorField.name})-->
+<#--        <#if discriminatorField.type.isSimpleTypeReference()>-->
+<#--            <#assign simpleTypeReference = 
discriminatorField.type.asSimpleTypeReference().orElseThrow()>-->
+<#--            <#if simpleTypeReference.isVstringTypeReference()>-->
+<#--                <#assign vstringTypeReference = 
simpleTypeReference.asVstringTypeReference().orElseThrow()>-->
+<#--        lengthInBits += 
${helper.toSerializationExpression(discriminatorField, helper.intTypeReference, 
vstringTypeReference.getLengthExpression(), parserArguments)};-->
+<#--            <#else>-->
+<#--        lengthInBits += ${simpleTypeReference.sizeInBits};-->
+<#--            </#if>-->
+<#--        <#elseif helper.isEnumField(field)>-->
+<#--            lengthInBits += 
${helper.getEnumBaseTypeReference(discriminatorField.type).sizeInBits};-->
+<#--        <#else>-->
+<#--            lengthInBits += 
${discriminatorField.name}.getLengthInBits();-->
+<#--        </#if>-->
+<#--        <#break>-->
+<#--    <#case "enum">-->
+<#--        <#assign enumField = field.asEnumField().orElseThrow()>-->
+
+<#--        // Enum Field (${enumField.name})-->
+<#--        lengthInBits += 
${helper.getEnumBaseTypeReference(enumField.type).sizeInBits};-->
+<#--        <#break>-->
+<#--    <#case "implicit">-->
+<#--        <#assign implicitField = field.asImplicitField().orElseThrow()>-->
+<#--        <#assign simpleTypeReference = 
implicitField.type.asSimpleTypeReference().orElseThrow()>-->
+
+<#--        // Implicit Field (${implicitField.name})-->
+<#--        lengthInBits += ${simpleTypeReference.sizeInBits};-->
+<#--        <#break>-->
+<#--    <#case "manualArray">-->
+<#--        <#assign manualArrayField = 
field.asManualArrayField().orElseThrow()>-->
+<#--        <#assign arrayElementTypeReference = 
manualArrayField.type.asArrayTypeReference().orElseThrow().getElementTypeReference()>-->
+
+<#--        // Manual Array Field (${manualArrayField.name})-->
+<#--        lengthInBits += ${helper.toParseExpression(manualArrayField, 
helper.intTypeReference, manualArrayField.lengthExpression, parserArguments)} * 
8;-->
+<#--        <#break>-->
+<#--    <#case "manual">-->
+<#--        <#assign manualField = field.asManualField().orElseThrow()>-->
+
+<#--        // Manual Field (${manualField.name})-->
+<#--        lengthInBits += ${helper.toParseExpression(manualField, 
helper.intTypeReference, manualField.lengthExpression, parserArguments)};-->
+<#--        <#break>-->
+<#--    <#case "optional">-->
+<#--        <#assign optionalField = field.asOptionalField().orElseThrow()>-->
+
+<#--        // Optional Field (${optionalField.name})-->
+<#--        if(${optionalField.name} != null) {-->
+<#--        <#if optionalField.type.isSimpleTypeReference()>-->
+<#--            <#assign simpleTypeReference = 
optionalField.type.asSimpleTypeReference().orElseThrow()>-->
+<#--            <#if simpleTypeReference.isVstringTypeReference()>-->
+<#--                <#assign vstringTypeReference = 
simpleTypeReference.asVstringTypeReference().orElseThrow()>-->
+<#--            lengthInBits += 
${helper.toSerializationExpression(optionalField, helper.intTypeReference, 
vstringTypeReference.getLengthExpression(), parserArguments)};-->
+<#--            <#else>-->
+<#--            lengthInBits += ${simpleTypeReference.sizeInBits};-->
+<#--            </#if>-->
+<#--        <#elseif helper.isEnumField(field)>-->
+<#--            lengthInBits += 
${helper.getEnumBaseTypeReference(optionalField.type).sizeInBits};-->
+<#--        <#elseif optionalField.type.isDataIoTypeReference()>-->
+<#--            lengthInBits += 
${optionalField.type.asComplexTypeReference().orElseThrow().name}.getLengthInBits(${optionalField.name}<#if
 optionalField.type.asComplexTypeReference().orElseThrow().params?has_content>, 
<#list 
optionalField.type.asComplexTypeReference().orElseThrow().params.orElseThrow() 
as param>${helper.toParseExpression(optionalField, helper.anyTypeReference, 
param, parserArguments)}<#sep>, </#sep></#list></#if>);-->
+<#--        <#else>-->
+<#--            lengthInBits += ${optionalField.name}.getLengthInBits();-->
+<#--        </#if>-->
+<#--        }-->
+<#--        <#break>-->
+<#--    <#case "padding">-->
+<#--        <#assign paddingField = field.asPaddingField().orElseThrow()>-->
+<#--        <#assign simpleTypeReference = 
paddingField.type.asSimpleTypeReference().orElseThrow()>-->
+
+<#--        // Padding Field (padding)-->
+<#--        &lt;#&ndash; We're replacing the "lastItem" with 'false' here as 
the item itself can't know if it is the last &ndash;&gt;-->
+<#--        int _timesPadding = (int) 
(${helper.toParseExpression(paddingField, helper.intTypeReference, 
paddingField.paddingCondition, parserArguments)});-->
+<#--        while (_timesPadding-- > 0) {-->
+<#--            lengthInBits += ${simpleTypeReference.sizeInBits};-->
+<#--        }-->
+<#--        <#break>-->
+<#--    <#case "reserved">-->
+<#--        <#assign reservedField = field.asReservedField().orElseThrow()>-->
+<#--        <#assign simpleTypeReference = 
reservedField.type.asSimpleTypeReference().orElseThrow()>-->
+
+<#--        // Reserved Field (reserved)-->
+<#--        lengthInBits += ${simpleTypeReference.sizeInBits};-->
+<#--        <#break>-->
+<#--    <#case "simple">-->
+<#--        <#assign simpleField = field.asSimpleField().orElseThrow()>-->
+
+<#--        // Simple field (${simpleField.name})-->
+<#--        <#if simpleField.type.isSimpleTypeReference()>-->
+<#--            <#assign simpleTypeReference = 
simpleField.type.asSimpleTypeReference().orElseThrow()>-->
+<#--            <#if simpleTypeReference.isVstringTypeReference()>-->
+<#--                <#assign vstringTypeReference = 
simpleTypeReference.asVstringTypeReference().orElseThrow()>-->
+<#--        lengthInBits += ${helper.toSerializationExpression(simpleField, 
helper.intTypeReference, vstringTypeReference.getLengthExpression(), 
parserArguments)};-->
+<#--            <#else>-->
+<#--        lengthInBits += ${simpleTypeReference.sizeInBits};-->
+<#--            </#if>-->
+<#--        <#elseif helper.isEnumField(field)>-->
+<#--        lengthInBits += 
${helper.getEnumBaseTypeReference(simpleField.type).sizeInBits};-->
+<#--        <#elseif simpleField.type.isDataIoTypeReference()>-->
+<#--        lengthInBits += 
${simpleField.type.asComplexTypeReference().orElseThrow().name}.getLengthInBits(${simpleField.name}<#if
 simpleField.type.asComplexTypeReference().orElseThrow().params?has_content>, 
<#list 
simpleField.type.asComplexTypeReference().orElseThrow().params.orElseThrow() as 
param>${helper.toParseExpression(simpleField, helper.anyTypeReference, param, 
parserArguments)}<#sep>, </#sep></#list></#if>);-->
+<#--        <#else>-->
+<#--        lengthInBits += ${simpleField.name}.getLengthInBits();-->
+<#--        </#if>-->
+<#--        <#break>-->
+<#--    <#case "switch">-->
+<#--        <#assign switchField = field.asSwitchField().orElseThrow()>-->
+
+<#--        // Length of sub-type elements will be added by sub-type...-->
+<#--        <#break>-->
+<#--    <#case "unknown">-->
+<#--        <#assign unknownField = field.asUnknownField().orElseThrow()>-->
+<#--        <#assign simpleTypeReference = 
unknownField.type.asSimpleTypeReference().orElseThrow()>-->
+
+<#--        // Unknown field-->
+<#--        lengthInBits += ${simpleTypeReference.sizeInBits};-->
+<#--        <#break>-->
+<#--    <#case "virtual">-->
+<#--        <#assign virtualField = field.asVirtualField().orElseThrow()>-->
+
+<#--        // A virtual field doesn't have any in- or output.-->
+<#--        <#break>-->
+<#--</#switch>-->
+<#--</#list>-->
+
+<#--        return lengthInBits;-->
+<#--    }-->
+
+<#--&lt;#&ndash; The parse and serialize methods here are just proxies for 
forwardning the requests to static counterparts &ndash;&gt;-->
+<#--    <#if !type.isDiscriminatedChildTypeDefinition()>-->
+<#--    public static ${type.name} staticParse(ReadBuffer readBuffer, 
Object... args) throws ParseException {-->
+<#--        PositionAware positionAware = readBuffer;-->
+<#--        <#if parserArguments?has_content>-->
+<#--        if((args == null) || (args.length != ${parserArguments?size})) {-->
+<#--            throw new PlcRuntimeException("Wrong number of arguments, 
expected ${parserArguments?size}, but got " + args.length);-->
+<#--        }-->
+<#--            <#list parserArguments as parserArgument>-->
+<#--                <#assign 
languageName=helper.getLanguageTypeNameForTypeReference(parserArgument.type, 
false)>-->
+<#--        ${languageName} ${parserArgument.name};-->
+<#--        if(args[${parserArgument?index}] instanceof ${languageName}) {-->
+<#--            ${parserArgument.name} = (${languageName}) 
args[${parserArgument?index}];-->
+<#--                <#if parserArgument.type.isSimpleTypeReference() || 
parserArgument.type.isEnumTypeReference()>-->
+<#--        } else if (args[${parserArgument?index}] instanceof String) {-->
+<#--            ${parserArgument.name} = ${languageName}.valueOf((String) 
args[${parserArgument?index}]);-->
+<#--                </#if>-->
+<#--        } else {-->
+<#--            throw new PlcRuntimeException("Argument 
${parserArgument?index} expected to be of type ${languageName} or a string 
which is parseable but was " + 
args[${parserArgument?index}].getClass().getName());-->
+<#--        }-->
+<#--            </#list>-->
+<#--        </#if>-->
+<#--        return staticParse(readBuffer<#if parserArguments?has_content>, 
<#list parserArguments as parserArgument>${parserArgument.name}<#sep>, 
</#sep></#list></#if>);-->
+<#--    }-->
+
+<#--    </#if>-->
+<#--&lt;#&ndash; Here come the actual parse and serialize methods that 
actually do the parsing and serlaizing &ndash;&gt;-->
+<#--    <#assign hasParserArguments=parserArguments?has_content/>-->
+<#--    <#assign parserArgumentList><#if hasParserArguments><#list 
parserArguments as 
parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type,
 false)} ${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>-->
+<#--    public static ${type.name}<#if 
type.isDiscriminatedChildTypeDefinition()>Builder staticParseBuilder<#else> 
staticParse</#if>(ReadBuffer readBuffer<#if hasParserArguments>, 
${parserArgumentList}</#if>) throws ParseException {-->
+<#--        readBuffer.pullContext("${type.name}");-->
+<#--        PositionAware positionAware = readBuffer;-->
+<#--        int startPos = positionAware.getPos();-->
+<#--        int curPos;-->
+<#--    <#list type.fields as field>-->
+<#--        <#switch field.typeName>-->
+<#--            <#case "array">-->
+<#--                <#assign arrayField = 
field.asArrayField().orElseThrow()>-->
+<#--                <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+<#--                <#assign arrayElementTypeReference = 
arrayField.type.asArrayTypeReference().orElseThrow().getElementTypeReference()>-->
+
+<#--                <#if arrayElementTypeReference.isByteBased()>-->
+<#--                    <#if !field.isCountArrayField() && 
!field.isLengthArrayField()>-->
+<#--                        throw new ParseException("array fields of type 
byte only support 'count' and 'length' loop-types.");-->
+<#--                    </#if>-->
+<#--                    byte[] ${namedField.name} = 
readBuffer.readByteArray("${namedField.name}", 
Math.toIntExact(${helper.toParseExpression(arrayField, helper.intTypeReference, 
arrayField.loopExpression, 
parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});-->
+<#--                <#else>-->
+<#--                &lt;#&ndash; If this is a count array, we can directly 
initialize an array with the given size &ndash;&gt;-->
+<#--                    <#if field.isCountArrayField()>-->
+<#--                        
${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)} 
${arrayField.name} = readCountArrayField("${arrayField.name}", 
${helper.getDataReaderCall(arrayField.type)}, 
${helper.toParseExpression(arrayField, helper.intTypeReference, 
arrayField.loopExpression, 
parserArguments)}${helper.getFieldOptions(typedField, parserArguments)});-->
+<#--                    &lt;#&ndash; In all other cases do we have to work 
with a list, that is later converted to an array &ndash;&gt;-->
+<#--                    <#else>-->
+<#--                    &lt;#&ndash; For a length array, we read data till the 
read position of the buffer reaches a given position &ndash;&gt;-->
+<#--                        <#if field.isLengthArrayField()>-->
+<#--                            
${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)} 
${arrayField.name} = readLengthArrayField("${arrayField.name}", 
${helper.getDataReaderCall(arrayField.type)}, 
${helper.toParseExpression(arrayField, helper.intTypeReference, 
arrayField.loopExpression, 
parserArguments)}${helper.getFieldOptions(typedField, parserArguments)});-->
+<#--                        &lt;#&ndash; A terminated array keeps on reading 
data as long as the termination expression evaluates to false &ndash;&gt;-->
+<#--                        <#elseif field.isTerminatedArrayField()>-->
+<#--                            
${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)} 
${arrayField.name} = readTerminatedArrayField("${arrayField.name}", 
${helper.getDataReaderCall(arrayField.type)}, () -> ((boolean) 
(${helper.toParseExpression(arrayField, helper.intTypeReference, 
arrayField.loopExpression, 
parserArguments)}))${helper.getFieldOptions(typedField, parserArguments)});-->
+<#--                        </#if>-->
+<#--                    </#if>-->
+<#--                </#if>-->
+<#--                <#break>-->
+<#--            <#case "assert">-->
+<#--                <#assign assertField = 
field.asAssertField().orElseThrow()>-->
+<#--                <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+
+<#--                ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", 
${helper.getDataReaderCall(typedField.type)}, 
(${helper.getLanguageTypeNameForField(field)}) 
(${helper.toParseExpression(assertField, assertField.type, 
assertField.conditionExpression, 
parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});-->
+<#--                <#break>-->
+<#--            <#case "checksum">-->
+<#--                <#assign checksumField = 
field.asChecksumField().orElseThrow()>-->
+<#--                <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+
+<#--                ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", 
${helper.getDataReaderCall(typedField.type)}, 
(${helper.getLanguageTypeNameForField(field)}) 
(${helper.toParseExpression(checksumField, checksumField.type, 
checksumField.checksumExpression, 
parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});-->
+<#--                <#break>-->
+<#--            <#case "const">-->
+<#--                <#assign constField = 
field.asConstField().orElseThrow()>-->
+<#--                <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+
+<#--                ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", 
${helper.getDataReaderCall(typedField.type)}, 
${type.name}.${namedField.name?upper_case}${helper.getFieldOptions(typedField, 
parserArguments)});-->
+<#--                <#break>-->
+<#--            <#case "discriminator">-->
+<#--                <#assign discriminatorField = 
field.asDiscriminatorField().orElseThrow()>-->
+<#--                <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+
+<#--                ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", 
${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField,
 parserArguments)});-->
+<#--                <#break>-->
+<#--            <#case "enum">-->
+<#--                <#assign enumField = field.asEnumField().orElseThrow()>-->
+<#--                <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+
+<#--                ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", 
"${enumField.type.asNonSimpleTypeReference().orElseThrow().typeDefinition.name}",
 
readEnum(${enumField.type.asNonSimpleTypeReference().orElseThrow().typeDefinition.name}::firstEnumForField${enumField.fieldName?cap_first},
 ${helper.getDataReaderCall(helper.getEnumFieldTypeReference(enumField.type, 
enumField.fieldName))})${helper.getFieldOptions(t [...]
+<#--                <#break>-->
+<#--            <#case "implicit">-->
+<#--                <#assign implicitField = 
field.asImplicitField().orElseThrow()>-->
+<#--                <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+
+<#--                ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", 
${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField,
 parserArguments)});-->
+<#--                <#break>-->
+<#--            <#case "manualArray">-->
+<#--                <#assign manualArrayField = 
field.asManualArrayField().orElseThrow()>-->
+<#--                <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+<#--                <#assign arrayElementTypeReference = 
manualArrayField.type.asArrayTypeReference().orElseThrow().getElementTypeReference()>-->
+
+<#--                <#if arrayElementTypeReference.isByteBased()>-->
+<#--                    byte[] ${namedField.name} = 
readManualByteArrayField("${namedField.name}", readBuffer, (byte[] _values) -> 
(boolean) (${helper.toParseExpression(manualArrayField, 
helper.boolTypeReference, manualArrayField.loopExpression, parserArguments)}), 
() -> (byte) (${helper.toParseExpression(manualArrayField, 
manualArrayField.type, manualArrayField.parseExpression, 
parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});-->
+<#--                <#else>-->
+<#--                    
${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)} 
${namedField.name} = readManualArrayField("${namedField.name}", readBuffer, 
(${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)} _values) 
-> (boolean) (${helper.toParseExpression(manualArrayField, 
helper.boolTypeReference, manualArrayField.loopExpression, parserArguments)}), 
() -> 
(${helper.getLanguageTypeNameForTypeReference(manualArrayField.type.elementTypeReference)})
 (${helper. [...]
+<#--                </#if>-->
+<#--                <#break>-->
+<#--            <#case "manual">-->
+<#--                <#assign manualField = 
field.asManualField().orElseThrow()>-->
+<#--                <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+
+<#--                ${helper.getLanguageTypeNameForField(field)} 
${manualField.name} = readManualField("${namedField.name}", readBuffer, () -> 
(${helper.getLanguageTypeNameForField(manualField)}) 
(${helper.toParseExpression(manualField, manualField.type, 
manualField.parseExpression, 
parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});-->
+<#--                <#break>-->
+<#--            <#case "optional">-->
+<#--                <#assign optionalField = 
field.asOptionalField().orElseThrow()>-->
+<#--                <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+
+<#--                ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", 
${helper.getDataReaderCall(typedField.type)}<#if 
optionalField.conditionExpression.present>, 
${helper.toParseExpression(optionalField, helper.boolTypeReference, 
optionalField.conditionExpression.get(), 
parserArguments)}</#if>${helper.getFieldOptions(typedField, 
parserArguments)});-->
+<#--                <#break>-->
+<#--            <#case "padding">-->
+<#--                <#assign paddingField = 
field.asPaddingField().orElseThrow()>-->
+<#--                <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                <#assign simpleTypeReference = 
paddingField.type.asSimpleTypeReference().orElseThrow()>-->
+
+<#--                
read${field.typeName?cap_first}Field(${helper.getDataReaderCall(typedField.type)},
 (int) (${helper.toParseExpression(paddingField, paddingField.type, 
paddingField.paddingCondition, 
parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});-->
+<#--                <#break>-->
+<#--            <#case "reserved">-->
+<#--                <#assign reservedField = 
field.asReservedField().orElseThrow()>-->
+<#--                <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+
+<#--                read${field.typeName?cap_first}Field("reserved", 
${helper.getDataReaderCall(typedField.type)}, 
${helper.getReservedValue(reservedField)}${helper.getFieldOptions(typedField, 
parserArguments)});-->
+<#--                <#break>-->
+<#--            <#case "simple">-->
+<#--                <#assign simpleField = 
field.asSimpleField().orElseThrow()>-->
+<#--                <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+
+<#--                ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = <#if 
typedField.type.isEnumTypeReference()>readEnumField("${namedField.name}", 
"${helper.getLanguageTypeNameForField(field)}", 
${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField,
 
parserArguments)});<#else>read${field.typeName?cap_first}Field("${namedField.name}",
 
${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField,
 parserArguments)});</#if>-->
+<#--                <#break>-->
+<#--            <#case "switch">-->
+<#--                <#assign switchField = 
field.asSwitchField().orElseThrow()>-->
+
+<#--                // Switch Field (Depending on the discriminator values, 
passes the instantiation to a sub-type)-->
+<#--                ${type.name}Builder builder = null;-->
+<#--                <#list switchField.cases as case>-->
+<#--                    <@compress single_line=true>-->
+<#--                        <#if case.discriminatorValueTerms?has_content>-->
+<#--                            if(-->
+<#--                            <#list case.discriminatorValueTerms as 
discriminatorValueTerm>-->
+<#--                                <#if 
helper.isWildcard(discriminatorValueTerm)>-->
+<#--                                    true-->
+<#--                                <#else>-->
+<#--                                    <#assign 
discriminatorExpression=switchField.discriminatorExpressions[discriminatorValueTerm?index].asLiteral().orElseThrow().asVariableLiteral().orElseThrow()>-->
+<#--                                    <#assign 
discriminatorType=helper.getDiscriminatorTypes()[discriminatorExpression.discriminatorName]>-->
+<#--                                    EvaluationHelper.equals(-->
+<#--                                    
${helper.toParseExpression(switchField, discriminatorType, 
discriminatorExpression, parserArguments)},-->
+<#--                                    <#if 
discriminatorType.isEnumTypeReference()>-->
+<#--                                        
${helper.getLanguageTypeNameForTypeReference(discriminatorType)}.${helper.toParseExpression(switchField,
 discriminatorType, discriminatorValueTerm, parserArguments)}-->
+<#--                                    <#else>-->
+<#--                                        
(${helper.getLanguageTypeNameForTypeReference(discriminatorType, true)}) 
${helper.toParseExpression(switchField, discriminatorType, 
discriminatorValueTerm, parserArguments)}-->
+<#--                                    </#if>-->
+<#--                                    )-->
+<#--                                </#if>-->
+<#--                                <#sep> && </#sep>-->
+<#--                            </#list>-->
+<#--                            )-->
+<#--                        </#if>{-->
+<#--                    </@compress>-->
+<#--                    <@compress single_line=true>-->
+<#--                        <#assign 
hasCaseParseArguments=case.allParserArguments.isPresent() && 
case.allParserArguments.orElseThrow()?has_content>-->
+<#--                        <#assign caseParseArguments><#if 
hasCaseParseArguments><#list case.allParserArguments.orElseThrow() as 
parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>-->
+<#--                        builder = 
${case.name}.staticParseBuilder(readBuffer<#if hasCaseParseArguments>, 
${tracer.dive("case parse arguments")} ${caseParseArguments}</#if>);-->
+<#--                    </@compress>-->
+<#--                    }<#sep> else </#sep>-->
+<#--                </#list>-->
+<#--                if (builder == null) {-->
+<#--                    throw new ParseException("Unsupported case for 
discriminated type");-->
+<#--                }-->
+<#--                <#break>-->
+<#--            <#case "unknown">-->
+<#--                <#assign unknownField = 
field.asUnknownField().orElseThrow()>-->
+<#--                <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+
+<#--                read${field.typeName?cap_first}Field("unknown", 
${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField,
 parserArguments)});-->
+<#--                <#break>-->
+<#--            <#case "virtual">-->
+<#--                <#assign virtualField = 
field.asVirtualField().orElseThrow()>-->
+<#--                <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+<#--                ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", 
${helper.getLanguageTypeNameForField(field)}.class, 
${helper.toParseExpression(virtualField, virtualField.type, 
virtualField.valueExpression, 
parserArguments)}${helper.getFieldOptions(typedField, parserArguments)});-->
+<#--                <#break>-->
+<#--            <#case "validation">-->
+<#--                <#assign validationField = 
field.asValidationField().orElseThrow()>-->
+<#--                // Validation-->
+<#--                if (!(${helper.toParseExpression(validationField, 
helper.boolTypeReference, validationField.getValidationExpression(), null)})) 
{-->
+<#--                    <#assign errorType="ParseValidationException">-->
+<#--                    <#if !validationField.shouldFail()><#assign 
errorType="ParseAssertException"></#if>-->
+<#--                    throw new 
${errorType}(${validationField.getDescription().orElse("\"Validation 
failed\"")});-->
+<#--                }-->
+<#--                <#break>-->
+<#--            <#case "peek">-->
+<#--                <#assign peekField = field.asPeekField().orElseThrow()>-->
+<#--                <#assign typedField = 
field.asTypedField().orElseThrow()>-->
+<#--                <#assign namedField = 
field.asNamedField().orElseThrow()>-->
+
+<#--                ${helper.getLanguageTypeNameForField(field)} 
${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", 
${helper.getDataReaderCall(typedField.type)}<#if 
peekField.offsetExpression.present>, ${helper.toParseExpression(peekField, 
helper.boolTypeReference, peekField.offsetExpression.get(), 
parserArguments)}</#if>${helper.getFieldOptions(typedField, 
parserArguments)});-->
+<#--                <#break>-->
+<#--        </#switch>-->
+<#--    </#list>-->
+
+<#--    readBuffer.closeContext("${type.name}");-->
+<#--    // Create the instance-->
+<#--    <#if type.isDiscriminatedChildTypeDefinition()>-->
+<#--        return new ${type.name}Builder(<#list type.propertyFields as 
field>${field.name}<#sep>, </#sep></#list><#if 
filteredParserArguments?has_content><#if type.propertyFields?has_content>, 
</#if><#list filteredParserArguments as arg>${arg.name}<#sep>, 
</#sep></#list></#if>);-->
+<#--    <#elseif type.isDiscriminatedParentTypeDefinition()>-->
+<#--        return builder.build(<#list type.propertyFields as 
field>${field.name}<#sep>, </#sep></#list><#if 
filteredParserArguments?has_content><#if type.propertyFields?has_content>, 
</#if><#list filteredParserArguments as arg>${arg.name}<#sep>, 
</#sep></#list></#if>);-->
+<#--    <#else>-->
+<#--        return new ${type.name}(<#list type.propertyFields as 
field>${field.name}<#sep>, </#sep></#list><#if 
filteredParserArguments?has_content><#if type.propertyFields?has_content>, 
</#if><#list filteredParserArguments as arg>${arg.name}<#sep>, 
</#sep></#list></#if>);-->
+<#--    </#if>-->
+<#--    }-->
+
+<#--    <#if type.isDiscriminatedParentTypeDefinition()>-->
+<#--        public static interface ${type.name}Builder {-->
+<#--            ${type.name} build(<#list type.propertyFields as 
field>${helper.getLanguageTypeNameForField(field)} ${field.name}<#sep>, 
</#sep></#list><#if filteredParserArguments?has_content><#if 
type.propertyFields?has_content>, </#if><#list filteredParserArguments as 
arg>${helper.getLanguageTypeNameForTypeReference(arg.type)} ${arg.name}<#sep>, 
</#sep></#list></#if>);-->
+<#--        }-->
+
+<#--    </#if>-->
+<#--    <#if type.isDiscriminatedChildTypeDefinition()>-->
+<#--        public static class ${type.name}Builder implements 
${type.parentType.orElseThrow().name}.${type.parentType.orElseThrow().name}Builder
 {-->
+<#--        <#if type.propertyFields?has_content>-->
+<#--            <#list type.propertyFields as field>-->
+<#--                private final ${helper.getLanguageTypeNameForField(field)} 
${field.name};-->
+<#--            </#list>-->
+<#--        </#if>-->
+<#--        <#if filteredParserArguments?has_content>-->
+<#--            <#list filteredParserArguments as arg>-->
+<#--                private final 
${helper.getLanguageTypeNameForTypeReference(arg.type)} ${arg.name};-->
+<#--            </#list>-->
+<#--        </#if>-->
+
+<#--        public ${type.name}Builder(<#list type.propertyFields as 
field>${helper.getLanguageTypeNameForField(field)} ${field.name}<#sep>, 
</#sep></#list><#if filteredParserArguments?has_content><#if 
type.propertyFields?has_content>, </#if><#list filteredParserArguments as 
arg>${helper.getLanguageTypeNameForTypeReference(arg.type)} ${arg.name}<#sep>, 
</#sep></#list></#if>) {-->
+<#--        <#list type.propertyFields as field>-->
+<#--            this.${field.name} = ${field.name};-->
+<#--        </#list>-->
+<#--        <#if filteredParserArguments?has_content>-->
+<#--            <#list filteredParserArguments as arg>-->
+<#--            this.${arg.name} = ${arg.name};-->
+<#--            </#list>-->
+<#--        </#if>-->
+<#--        }-->
+
+<#--        public ${type.name} build(<#list 
type.parentType.orElseThrow().asComplexTypeDefinition().orElseThrow().propertyFields
 as field>${helper.getLanguageTypeNameForField(field)} ${field.name}<#sep>, 
</#sep></#list><#if filteredParentParserArguments?has_content><#if 
type.parentType.orElseThrow().asComplexTypeDefinition().orElseThrow().propertyFields?has_content>,
 </#if><#list filteredParentParserArguments as 
arg>${helper.getLanguageTypeNameForTypeReference(arg.type)} ${arg.name}<#se 
[...]
+<#--            return new ${type.name}(<#list type.allPropertyFields as 
field>${field.name}<#sep>, </#sep></#list><#if 
filteredParserArguments?has_content><#if type.allPropertyFields?has_content>, 
</#if><#list filteredParserArguments as arg>${arg.name}<#sep>, 
</#sep></#list></#if>);-->
+<#--        }-->
+<#--    }-->
+
+<#--    </#if>-->
+
+<#--    @Override-->
+<#--    public boolean equals(Object o) {-->
+<#--        if (this == o) {-->
+<#--            return true;-->
+<#--        }-->
+<#--        if (!(o instanceof ${type.name})) {-->
+<#--            return false;-->
+<#--        }-->
+<#--        ${type.name} that = (${type.name}) o;-->
+<#--        return-->
+<#--            <#if type.propertyFields?has_content>-->
+<#--            <#list type.propertyFields as field>-->
+<#--            (get${field.name?cap_first}() == 
that.get${field.name?cap_first}()) &&-->
+<#--            </#list>-->
+<#--            </#if>-->
+<#--            <#if type.parentType.isPresent()>-->
+<#--            super.equals(that) &&-->
+<#--            </#if>-->
+<#--            true;-->
+<#--    }-->
+
+<#--    @Override-->
+<#--    public int hashCode() {-->
+<#--        return Objects.hash(-->
+<#--            <#if type.parentType.isPresent()>-->
+<#--            super.hashCode()<#if type.propertyFields?has_content>,</#if>-->
+<#--            </#if>-->
+<#--            <#if type.propertyFields?has_content>-->
+<#--            <#list type.propertyFields as field>-->
+<#--            get${field.name?cap_first}()<#sep>,</#sep>-->
+<#--            </#list>-->
+<#--            </#if>-->
+<#--        );-->
+<#--    }-->
+
+<#--    @Override-->
+<#--    public String toString() {-->
+<#--        WriteBufferBoxBased writeBufferBoxBased = new 
WriteBufferBoxBased(true, true);-->
+<#--        try {-->
+<#--            serialize(writeBufferBoxBased);-->
+<#--        } catch (SerializationException e) {-->
+<#--            throw new RuntimeException(e);-->
+<#--        }-->
+<#--        return "\n" + writeBufferBoxBased.getBox().toString()+ "\n";-->
+<#--    }-->
+<#--}-->
 </#outputformat>
\ No newline at end of file
diff --git 
a/code-generation/language-rust/src/main/resources/templates/rust/enum-template.rs.ftlh
 
b/code-generation/language-rust/src/main/resources/templates/rust/enum-template.rs.ftlh
index 6a478a7ae4..2f58c5914c 100644
--- 
a/code-generation/language-rust/src/main/resources/templates/rust/enum-template.rs.ftlh
+++ 
b/code-generation/language-rust/src/main/resources/templates/rust/enum-template.rs.ftlh
@@ -126,7 +126,7 @@ impl Message for ${type.name} {
 <#if !type.parserArguments.isEmpty()>
 pub struct ${type.name}Arguments {
 <#list type.parserArguments.orElseThrow() as arg>
-    ${helper.sink(arg)}${arg.name}: 
${helper.getNullsafeLanguageTypeNameForTypeReference(arg, 
type.enumValues)}<#sep>, </#sep>
+    ${arg.name}: ${helper.getNullsafeLanguageTypeNameForTypeReference(arg, 
type.enumValues)}<#sep>, </#sep>
 </#list>
 }
 

Reply via email to