Skip to content

Commit

Permalink
feat(plc4go): provide finer interfaces
Browse files Browse the repository at this point in the history
+ A *Contract interface for parents declaring methods which are implemented by that parent
+ A *Requirements interface for parents which defines which methods the parent needs to properly function.
+ A interface which combines the two above to give a full picture
+ A type assertion to ensure the struct implements the right interface
  • Loading branch information
sruehl committed Sep 1, 2024
1 parent 620e0a4 commit f8cdada
Show file tree
Hide file tree
Showing 2,484 changed files with 6,425 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,37 +84,71 @@ const ${type.name}_${field.name?upper_case} ${helper.getLanguageTypeNameForField

// ${type.name} is the corresponding interface of ${type.name?cap_first}
type ${type.name} interface {
<#if type.isDiscriminatedParentTypeDefinition()>
${type.name}Contract
${type.name}Requirements
fmt.Stringer<@emitImport import="fmt" />
utils.LengthAware
utils.Serializable
<#if type.isDiscriminatedChildTypeDefinition()>
${type.parentType.orElseThrow().name?cap_first}
<#else>
fmt.Stringer<@emitImport import="fmt" />
utils.LengthAware
utils.Serializable
<#if type.isDiscriminatedChildTypeDefinition()>
${type.parentType.orElseThrow().name?cap_first}
</#if>
<#list type.propertyFields as field>
<#assign typeRef=field.asTypedField().orElseThrow().type>
// Get${field.name?cap_first} returns ${field.name?cap_first} (property field)
Get${field.name?cap_first}() <#if helper.needsPointerAccess(field)>*</#if>${helper.getLanguageTypeNameForTypeReference(typeRef)}
</#list>
<#list type.virtualFields as field>
<#assign typeRef=field.asTypedField().orElseThrow().type>
// Get${field.name?cap_first} returns ${field.name?cap_first} (virtual field)
Get${field.name?cap_first}() <#if helper.needsPointerAccess(field)>*</#if>${helper.getLanguageTypeNameForTypeReference(typeRef)}
</#list>
<#list type.abstractFields as field>
<#assign namedField=field.asNamedField().orElseThrow()>
// Get${namedField.name?cap_first} returns ${namedField.name?cap_first} (abstract field)
Get${namedField.name?cap_first}() ${helper.getLanguageTypeNameForField(field)}
</#list>
</#if>
}

<#if type.isDiscriminatedParentTypeDefinition()>
// ${type.name}Contract provides a set of functions which can be overwritten by a sub struct
type ${type.name}Contract interface {
<#if type.isDiscriminatedChildTypeDefinition()>
${type.parentType.orElseThrow().name?cap_first}
</#if>
<#list type.propertyFields as field>
<#assign typeRef=field.asTypedField().orElseThrow().type>
// Get${field.name?cap_first} returns ${field.name?cap_first} (property field)
Get${field.name?cap_first}() <#if helper.needsPointerAccess(field)>*</#if>${helper.getLanguageTypeNameForTypeReference(typeRef)}
</#list>
<#list type.virtualFields as field>
<#assign typeRef=field.asTypedField().orElseThrow().type>
// Get${field.name?cap_first} returns ${field.name?cap_first} (virtual field)
Get${field.name?cap_first}() <#if helper.needsPointerAccess(field)>*</#if>${helper.getLanguageTypeNameForTypeReference(typeRef)}
</#list>
<#list type.abstractFields as field>
<#assign namedField=field.asNamedField().orElseThrow()>
// Get${namedField.name?cap_first} returns ${namedField.name?cap_first} (abstract field)
Get${namedField.name?cap_first}() ${helper.getLanguageTypeNameForField(field)}
</#list>
}

// ${type.name}Requirements provides a set of functions which need to be implemented by a sub struct
type ${type.name}Requirements interface {
<#list helper.getDiscriminatorTypes() as discriminatorName, discriminatorType>
<#-- If the discriminator name matches that of another field, suppress the methods generation -->
<#if !type.isNonDiscriminatorField(discriminatorName)>
// Get${discriminatorName?cap_first} returns ${discriminatorName?cap_first} (discriminator field)
Get${discriminatorName?cap_first}() ${helper.getLanguageTypeNameForTypeReference(discriminatorType)}
</#if>
</#list>
</#if>
<#list type.propertyFields as field>
<#assign typeRef=field.asTypedField().orElseThrow().type>
// Get${field.name?cap_first} returns ${field.name?cap_first} (property field)
Get${field.name?cap_first}() <#if helper.needsPointerAccess(field)>*</#if>${helper.getLanguageTypeNameForTypeReference(typeRef)}
</#list>
<#list type.virtualFields as field>
<#assign typeRef=field.asTypedField().orElseThrow().type>
// Get${field.name?cap_first} returns ${field.name?cap_first} (virtual field)
Get${field.name?cap_first}() <#if helper.needsPointerAccess(field)>*</#if>${helper.getLanguageTypeNameForTypeReference(typeRef)}
</#list>
<#list type.abstractFields as field>
<#assign namedField=field.asNamedField().orElseThrow()>
// Get${namedField.name?cap_first} returns ${namedField.name?cap_first} (abstract field)
Get${namedField.name?cap_first}() ${helper.getLanguageTypeNameForField(field)}
</#list>
}
</#if>

// ${type.name}Exactly can be used when we want exactly this type and not a type which fulfills ${type.name}.
// This is useful for switch cases.
Expand Down Expand Up @@ -157,6 +191,12 @@ type _${type.name} struct {
</#if>
}

<#if type.isDiscriminatedParentTypeDefinition()>
var _ ${type.name}Contract = (*_${type.name})(nil)
<#else>
var _ ${type.name} = (*_${type.name})(nil)
</#if>

<#if type.isDiscriminatedParentTypeDefinition()>
type _${type.name}ChildRequirements interface {
utils.Serializable
Expand Down Expand Up @@ -847,7 +887,7 @@ func ${type.name}ParseWithBuffer(ctx context.Context, readBuffer utils.ReadBuffe
<#assign typedField = field.asTypedField().orElseThrow()>
<#assign namedField = field.asNamedField().orElseThrow()>

${namedField.name} := Read${field.typeName?cap_first}Field[${helper.getLanguageTypeNameForField(field)}](ctx, "${namedField.name}", ${helper.getDataReaderCall(typedField.type)}, ${helper.toParseExpression(assertField, assertField.type, assertField.conditionExpression, parserArguments)}${helper.getFieldOptions(typedField, parserArguments)})
${namedField.name},err := Read${field.typeName?cap_first}Field[${helper.getLanguageTypeNameForField(field)}](ctx, "${namedField.name}", ${helper.getDataReaderCall(typedField.type)}, ${helper.toParseExpression(assertField, assertField.type, assertField.conditionExpression, parserArguments)}${helper.getFieldOptions(typedField, parserArguments)})
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("Error parsing '${namedField.name}' field"))<@emitImport import="github.com/pkg/errors" />
}
Expand Down Expand Up @@ -1066,7 +1106,7 @@ func ${type.name}ParseWithBuffer(ctx context.Context, readBuffer utils.ReadBuffe
<#assign typedField = field.asTypedField().orElseThrow()>

if _, err := Read${field.typeName?cap_first}Field(ctx, "unknown", ${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField, parserArguments)}); err!=nil{
return nil, errors.Wrap(_UnknownErr, "Error parsing unknown field of ${type.name}")<@emitImport import="github.com/pkg/errors" />
return nil, errors.Wrap(err, "Error parsing unknown field of ${type.name}")<@emitImport import="github.com/pkg/errors" />
}
<#break>
<#case "virtual">${helper.emitRequiredImportRaw(". \"github.com/apache/plc4x/plc4go/spi/codegen/fields\"")}
Expand Down
16 changes: 9 additions & 7 deletions code-generation/language-go/src/test/resources/plc4go/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
//
module github.com/apache/plc4x/plc4go

go 1.16
go 1.23

require (
github.com/ajankovic/xdiff v0.0.1
github.com/icza/bitio v1.0.0
github.com/pkg/errors v0.9.1
github.com/rs/zerolog v1.20.0
github.com/subchen/go-xmldom v1.1.2
github.com/tebeka/go2xunit v1.4.10 // indirect
github.com/ajankovic/xdiff v0.0.1
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e // indirect
github.com/icza/bitio v1.1.0
github.com/pkg/errors v0.9.1
github.com/rs/zerolog v1.33.0
github.com/subchen/go-xmldom v1.1.2
github.com/tebeka/go2xunit v1.4.10 // indirect
golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74 // indirect
)
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@

package model

import "github.com/apache/plc4x/plc4go/spi/utils"
import (
"context"
"github.com/apache/plc4x/plc4go/spi/utils"
)

func ParseBit(io utils.ReadBuffer) int8 {
return 0
Expand Down Expand Up @@ -77,14 +80,19 @@ func Parse(io utils.ReadBuffer) int8 {
func Serialize(io utils.WriteBuffer, data byte) {
}

func ReadManualField(io utils.ReadBuffer, simpleField uint8) (any, error) {
func ReadAManualField(ctx context.Context, io utils.ReadBuffer, simpleField uint8) (any, error) {
return uint8(0), nil
}

func CrcInt8(num int) (int8, error) {
return int8(num), nil

func CrcInt8(num int) func() (int8, error) {
return func() (int8, error) {
return int8(num), nil
}
}

func CrcUint8(num int) (uint8, error) {
return uint8(num), nil
func CrcUint8(num int) func() (uint8, error) {
return func() (uint8, error) {
return uint8(num), nil
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
//[manualArray uint 8 manualArrayField count '1' ] // TODO: Implement ...
//[manualArray uint 8 manualArrayField length '1' ] // TODO: Implement ...
//[manualArray uint 8 manualArrayField terminated '1' ] // TODO: Implement ...
[manual uint 8 manualField 'STATIC_CALL("readManualField", readBuffer, simpleField)'
'STATIC_CALL("writeManualField", writeBuffer, simpleField)'
[manual uint 8 manualField 'STATIC_CALL("readAManualField", readBuffer, simpleField)'
'STATIC_CALL("writeAManualField", writeBuffer, simpleField)'
'simpleField*8' ]
[optional uint 8 optionalField 'simpleField == 5' ]
[padding uint 8 paddingField '0x00' 'simpleField']
Expand Down Expand Up @@ -476,6 +476,28 @@
////////////////////////////////////////////////////////////////
/* Needs to be ported to C and GO
[discriminatedType TTGranddad
[discriminator uint 8 dadNumber]
[simple uint 8 warStories]
[typeSwitch dadNumber
['0x00' TTDad
[discriminator uint 8 sonNumber]
[simple uint 8 beerBottles]
[typeSwitch sonNumber
['0x01' TTSon
[simple uint 8 gameConsoles]
[discriminator uint 8 babyNumber]
[typeSwitch babyNumber
['0x02' TTBaby
[simple uint 8 lalalala]
]
]
]
]
]
]
]

[discriminatedType TypeSwitchInTypeSwitchParentType
[discriminator uint 8 typeNumber]
[simple uint 8 parentFieldHurz]
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 14 additions & 2 deletions plc4go/protocols/abeth/readwrite/model/CIPEncapsulationPacket.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions plc4go/protocols/abeth/readwrite/model/DF1RequestCommand.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 14 additions & 2 deletions plc4go/protocols/abeth/readwrite/model/DF1RequestMessage.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit f8cdada

Please sign in to comment.