90c890f027a69249a990afe2c780a4d265e39b19
[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         "github.com/sirupsen/logrus"
23 )
24
25 // toApiType returns name that is used as type reference in VPP binary API
26 func toApiType(name string) string {
27         return fmt.Sprintf("vl_api_%s_t", name)
28 }
29
30 // binapiTypes is a set of types used VPP binary API for translation to Go types
31 var binapiTypes = map[string]string{
32         "u8":  "uint8",
33         "i8":  "int8",
34         "u16": "uint16",
35         "i16": "int16",
36         "u32": "uint32",
37         "i32": "int32",
38         "u64": "uint64",
39         "i64": "int64",
40         "f64": "float64",
41 }
42
43 func getBinapiTypeSize(binapiType string) int {
44         if _, ok := binapiTypes[binapiType]; ok {
45                 b, err := strconv.Atoi(strings.TrimLeft(binapiType, "uif"))
46                 if err == nil {
47                         return b / 8
48                 }
49         }
50         return -1
51 }
52
53 // convertToGoType translates the VPP binary API type into Go type
54 func convertToGoType(ctx *context, binapiType string) (typ string) {
55         if t, ok := binapiTypes[binapiType]; ok {
56                 // basic types
57                 typ = t
58         } else if r, ok := ctx.packageData.RefMap[binapiType]; ok {
59                 // specific types (enums/types/unions)
60                 typ = camelCaseName(r)
61         } else {
62                 switch binapiType {
63                 case "bool", "string":
64                         typ = binapiType
65                 default:
66                         // fallback type
67                         logrus.Warnf("found unknown VPP binary API type %q, using byte", binapiType)
68                         typ = "byte"
69                 }
70         }
71         return typ
72 }
73
74 func getSizeOfType(ctx *context, typ *Type) (size int) {
75         for _, field := range typ.Fields {
76                 enum := getEnumByRef(ctx, field.Type)
77                 if enum != nil {
78                         size += getSizeOfBinapiTypeLength(enum.Type, field.Length)
79                         continue
80                 }
81                 size += getSizeOfBinapiTypeLength(field.Type, field.Length)
82         }
83         return size
84 }
85
86 func getSizeOfBinapiTypeLength(typ string, length int) (size int) {
87         if n := getBinapiTypeSize(typ); n > 0 {
88                 if length > 0 {
89                         return n * length
90                 } else {
91                         return n
92                 }
93         }
94
95         return
96 }
97
98 func getEnumByRef(ctx *context, ref string) *Enum {
99         for _, typ := range ctx.packageData.Enums {
100                 if ref == toApiType(typ.Name) {
101                         return &typ
102                 }
103         }
104         return nil
105 }
106
107 func getTypeByRef(ctx *context, ref string) *Type {
108         for _, typ := range ctx.packageData.Types {
109                 if ref == toApiType(typ.Name) {
110                         return &typ
111                 }
112         }
113         return nil
114 }
115
116 func getAliasByRef(ctx *context, ref string) *Alias {
117         for _, alias := range ctx.packageData.Aliases {
118                 if ref == toApiType(alias.Name) {
119                         return &alias
120                 }
121         }
122         return nil
123 }
124
125 func getUnionSize(ctx *context, union *Union) (maxSize int) {
126         for _, field := range union.Fields {
127                 typ := getTypeByRef(ctx, field.Type)
128                 if typ != nil {
129                         if size := getSizeOfType(ctx, typ); size > maxSize {
130                                 maxSize = size
131                         }
132                         continue
133                 }
134                 alias := getAliasByRef(ctx, field.Type)
135                 if alias != nil {
136                         if size := getSizeOfBinapiTypeLength(alias.Type, alias.Length); size > maxSize {
137                                 maxSize = size
138                         }
139                         continue
140                 } else {
141                         logf("no type or alias found for union %s field type %q", union.Name, field.Type)
142                         continue
143                 }
144         }
145         logf("getUnionSize: %s %+v max=%v", union.Name, union.Fields, maxSize)
146         return
147 }