Fix union data size for types with enums
[govpp.git] / cmd / binapi-generator / types.go
1 // Copyright (c) 2019 Cisco and/or its affiliates.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at:
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package main
16
17 import (
18         "fmt"
19         "strconv"
20         "strings"
21 )
22
23 // toApiType returns name that is used as type reference in VPP binary API
24 func toApiType(name string) string {
25         return fmt.Sprintf("vl_api_%s_t", name)
26 }
27
28 // binapiTypes is a set of types used VPP binary API for translation to Go types
29 var binapiTypes = map[string]string{
30         "u8":  "uint8",
31         "i8":  "int8",
32         "u16": "uint16",
33         "i16": "int16",
34         "u32": "uint32",
35         "i32": "int32",
36         "u64": "uint64",
37         "i64": "int64",
38         "f64": "float64",
39 }
40
41 func getBinapiTypeSize(binapiType string) int {
42         if _, ok := binapiTypes[binapiType]; ok {
43                 b, err := strconv.Atoi(strings.TrimLeft(binapiType, "uif"))
44                 if err == nil {
45                         return b / 8
46                 }
47         }
48         return -1
49 }
50
51 // convertToGoType translates the VPP binary API type into Go type
52 func convertToGoType(ctx *context, binapiType string) (typ string) {
53         if t, ok := binapiTypes[binapiType]; ok {
54                 // basic types
55                 typ = t
56         } else if r, ok := ctx.packageData.RefMap[binapiType]; ok {
57                 // specific types (enums/types/unions)
58                 typ = camelCaseName(r)
59         } else {
60                 switch binapiType {
61                 case "bool", "string":
62                         typ = binapiType
63                 default:
64                         // fallback type
65                         log.Warnf("found unknown VPP binary API type %q, using byte", binapiType)
66                         typ = "byte"
67                 }
68         }
69         return typ
70 }
71
72 func getSizeOfType(ctx *context, typ *Type) (size int) {
73         for _, field := range typ.Fields {
74                 enum := getEnumByRef(ctx, field.Type)
75                 if enum != nil {
76                         size += getSizeOfBinapiTypeLength(enum.Type, field.Length)
77                         continue
78                 }
79                 size += getSizeOfBinapiTypeLength(field.Type, field.Length)
80         }
81         return size
82 }
83
84 func getSizeOfBinapiTypeLength(typ string, length int) (size int) {
85         if n := getBinapiTypeSize(typ); n > 0 {
86                 if length > 0 {
87                         return n * length
88                 } else {
89                         return n
90                 }
91         }
92
93         return
94 }
95
96 func getEnumByRef(ctx *context, ref string) *Enum {
97         for _, typ := range ctx.packageData.Enums {
98                 if ref == toApiType(typ.Name) {
99                         return &typ
100                 }
101         }
102         return nil
103 }
104
105 func getTypeByRef(ctx *context, ref string) *Type {
106         for _, typ := range ctx.packageData.Types {
107                 if ref == toApiType(typ.Name) {
108                         return &typ
109                 }
110         }
111         return nil
112 }
113
114 func getAliasByRef(ctx *context, ref string) *Alias {
115         for _, alias := range ctx.packageData.Aliases {
116                 if ref == toApiType(alias.Name) {
117                         return &alias
118                 }
119         }
120         return nil
121 }
122
123 func getUnionSize(ctx *context, union *Union) (maxSize int) {
124         for _, field := range union.Fields {
125                 typ := getTypeByRef(ctx, field.Type)
126                 if typ != nil {
127                         if size := getSizeOfType(ctx, typ); size > maxSize {
128                                 maxSize = size
129                         }
130                         continue
131                 }
132                 alias := getAliasByRef(ctx, field.Type)
133                 if alias != nil {
134                         if size := getSizeOfBinapiTypeLength(alias.Type, alias.Length); size > maxSize {
135                                 maxSize = size
136                         }
137                         continue
138                 } else {
139                         logf("no type or alias found for union %s field type %q", union.Name, field.Type)
140                         continue
141                 }
142         }
143         logf("getUnionSize: %s %+v max=%v", union.Name, union.Fields, maxSize)
144         return
145 }