From 43cd23926d5eec359d4b554a4330e1aa596c76de Mon Sep 17 00:00:00 2001 From: Vladimir Lavor Date: Wed, 16 Sep 2020 13:44:31 +0200 Subject: 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 --- binapigen/generator_test.go | 106 +++++++++++++++++++++++++++++++++++++++++++- binapigen/types.go | 64 +++++++++++++++----------- 2 files changed, 144 insertions(+), 26 deletions(-) (limited to 'binapigen') 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 } -- cgit 1.2.3-korg