aboutsummaryrefslogtreecommitdiffstats
path: root/binapigen
diff options
context:
space:
mode:
authorVladimir Lavor <vlavor@cisco.com>2020-09-16 13:44:31 +0200
committerVladimir Lavor <vlavor@cisco.com>2020-09-18 10:41:12 +0200
commit43cd23926d5eec359d4b554a4330e1aa596c76de (patch)
tree344b7d9a19e2ec84b6f7aaa7c7667a8b94d06ab4 /binapigen
parente517439567ad843033257664fdfe90a9173b0aa6 (diff)
binapigen: fix union size
This change fixes calculated byte size of the union composed from another union(s). Change-Id: I596a3c2a585cc42570b1d00dab3a5ad4993dabfa Signed-off-by: Vladimir Lavor <vlavor@cisco.com>
Diffstat (limited to 'binapigen')
-rw-r--r--binapigen/generator_test.go106
-rw-r--r--binapigen/types.go64
2 files changed, 144 insertions, 26 deletions
diff --git a/binapigen/generator_test.go b/binapigen/generator_test.go
index 1dfaca4..7f334a9 100644
--- a/binapigen/generator_test.go
+++ b/binapigen/generator_test.go
@@ -15,6 +15,9 @@
package binapigen
import (
+ "fmt"
+ "git.fd.io/govpp.git/binapigen/vppapi"
+ . "github.com/onsi/gomega"
"testing"
)
@@ -45,10 +48,111 @@ func TestBinapiTypeSizes(t *testing.T) {
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
- size := getSizeOfBinapiTypeLength(test.input, 1)
+ size := getSizeOfBinapiBaseType(test.input, 1)
if size != test.expsize {
t.Errorf("expected %d, got %d", test.expsize, size)
}
})
}
}
+
+func TestBinapiUnionSizes(t *testing.T) {
+ RegisterTestingT(t)
+ tests := []struct {
+ testName string
+ input *Union
+ expsize int
+ }{
+ {testName: "union_alias", input: typeTestData{
+ typ: "union", fields: []*typeTestData{{typ: "alias", value: U16},
+ }}.getUnion("union1"), expsize: 2},
+ {testName: "union_enum", input: typeTestData{
+ typ: "union", fields: []*typeTestData{{typ: "enum", value: U32},
+ }}.getUnion("union2"), expsize: 4},
+ {testName: "union_struct", input: typeTestData{
+ typ: "union", fields: []*typeTestData{
+ {typ: "struct", fields: []*typeTestData{{value: U8}, {value: U16}, {value: U32}}},
+ }}.getUnion("union3"), expsize: 7},
+ {testName: "union_structs", input: typeTestData{
+ typ: "union", fields: []*typeTestData{
+ {typ: "struct", fields: []*typeTestData{{value: U8}, {value: BOOL}}},
+ {typ: "struct", fields: []*typeTestData{{value: U16}, {value: U32}}},
+ {typ: "struct", fields: []*typeTestData{{value: U32}, {value: U64}}},
+ }}.getUnion("union4"), expsize: 12},
+ {testName: "union_unions", input: typeTestData{
+ typ: "union", fields: []*typeTestData{
+ {typ: "union", fields: []*typeTestData{
+ {typ: "struct", fields: []*typeTestData{{value: STRING}}},
+ }},
+ {typ: "union", fields: []*typeTestData{
+ {typ: "struct", fields: []*typeTestData{{value: U32}}},
+ }},
+ {typ: "union", fields: []*typeTestData{
+ {typ: "struct", fields: []*typeTestData{{value: U64}}},
+ }},
+ }}.getUnion("union5"), expsize: 8},
+ {testName: "union_combined", input: typeTestData{
+ typ: "union", fields: []*typeTestData{
+ {typ: "alias", value: U8},
+ {typ: "enum", value: U16},
+ {typ: "struct", fields: []*typeTestData{{value: U8}, {value: U16}, {value: U32}}}, // <-
+ {typ: "union", fields: []*typeTestData{
+ {typ: "alias", value: U16},
+ {typ: "enum", value: U16},
+ {typ: "struct", fields: []*typeTestData{{value: U32}}},
+ }},
+ }}.getUnion("union6"), expsize: 7},
+ }
+ for _, test := range tests {
+ t.Run(test.testName, func(t *testing.T) {
+ size := getUnionSize(test.input)
+ Expect(size).To(Equal(test.expsize))
+ })
+ }
+}
+
+// Typed data used for union size evaluation testing.
+type typeTestData struct {
+ typ string
+ value string
+ fields []*typeTestData
+}
+
+func (t typeTestData) getUnion(name string) *Union {
+ return &Union{
+ UnionType: vppapi.UnionType{Name: name},
+ Fields: t.getUnionFields(name),
+ }
+}
+
+func (t typeTestData) getUnionFields(parentName string) (fields []*Field) {
+ for i, field := range t.fields {
+ var (
+ dataType string
+ aliasType *Alias
+ enumType *Enum
+ structType *Struct
+ unionType *Union
+ )
+ switch field.typ {
+ case "alias":
+ aliasType = &Alias{AliasType: vppapi.AliasType{Name: fmt.Sprintf("%s_alias_%d", parentName, i), Type: field.value}}
+ case "enum":
+ enumType = &Enum{EnumType: vppapi.EnumType{Name: fmt.Sprintf("%s_enum_%d", parentName, i), Type: field.value}}
+ case "struct":
+ structType = &Struct{Fields: field.getUnionFields(fmt.Sprintf("%s_struct_%d", parentName, i))}
+ case "union":
+ unionType = field.getUnion(parentName)
+ default:
+ dataType = field.value
+ }
+ fields = append(fields, &Field{
+ Field: vppapi.Field{Name: fmt.Sprintf("%s_field_%d", parentName, i), Type: dataType},
+ TypeAlias: aliasType,
+ TypeEnum: enumType,
+ TypeStruct: structType,
+ TypeUnion: unionType,
+ })
+ }
+ return fields
+}
diff --git a/binapigen/types.go b/binapigen/types.go
index 1d0dae5..addb122 100644
--- a/binapigen/types.go
+++ b/binapigen/types.go
@@ -128,45 +128,59 @@ func getFieldType(g *GenFile, field *Field) string {
return gotype
}
-func getSizeOfBinapiTypeLength(typ string, length int) (size int) {
- if n := BaseTypeSizes[typ]; n > 0 {
- if length > 0 {
- return n * length
- } else {
- return n
+func getUnionSize(union *Union) (maxSize int) {
+ for _, field := range union.Fields {
+ if size, isBaseType := getSizeOfField(field); isBaseType {
+ logrus.Panicf("union %s field %s has unexpected type %q", union.Name, field.Name, field.Type)
+ } else if size > maxSize {
+ maxSize = size
}
}
+ //logf("getUnionSize: %s %+v max=%v", union.Name, union.Fields, maxSize)
return
}
-func getSizeOfType(typ *Struct) (size int) {
+func getSizeOfField(field *Field) (size int, isBaseType bool) {
+ if alias := field.TypeAlias; alias != nil {
+ size = getSizeOfBinapiBaseType(alias.Type, alias.Length)
+ return
+ }
+ if enum := field.TypeEnum; enum != nil {
+ size = getSizeOfBinapiBaseType(enum.Type, field.Length)
+ return
+ }
+ if structType := field.TypeStruct; structType != nil {
+ size = getSizeOfStruct(structType)
+ return
+ }
+ if union := field.TypeUnion; union != nil {
+ size = getUnionSize(union)
+ return
+ }
+ return size, true
+}
+
+func getSizeOfStruct(typ *Struct) (size int) {
for _, field := range typ.Fields {
- if enum := field.TypeEnum; enum != nil {
- size += getSizeOfBinapiTypeLength(enum.Type, field.Length)
+ fieldSize, isBaseType := getSizeOfField(field)
+ if isBaseType {
+ size += getSizeOfBinapiBaseType(field.Type, field.Length)
continue
}
- size += getSizeOfBinapiTypeLength(field.Type, field.Length)
+ size += fieldSize
}
return size
}
-func getUnionSize(union *Union) (maxSize int) {
- for _, field := range union.Fields {
- if typ := field.TypeStruct; typ != nil {
- if size := getSizeOfType(typ); size > maxSize {
- maxSize = size
- }
- continue
- }
- if alias := field.TypeAlias; alias != nil {
- if size := getSizeOfBinapiTypeLength(alias.Type, alias.Length); size > maxSize {
- maxSize = size
- }
- continue
+// Returns size of base type multiplied by length. Length equal to zero
+// returns base type size.
+func getSizeOfBinapiBaseType(typ string, length int) (size int) {
+ if n := BaseTypeSizes[typ]; n > 0 {
+ if length > 1 {
+ return n * length
} else {
- logrus.Panicf("no type or alias found for union %s field type %q", union.Name, field.Type)
+ return n
}
}
- //logf("getUnionSize: %s %+v max=%v", union.Name, union.Fields, maxSize)
return
}