Refactored binapi generator with message encoding
[govpp.git] / binapigen / types.go
1 //  Copyright (c) 2020 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 binapigen
16
17 import (
18         "strings"
19
20         "github.com/sirupsen/logrus"
21 )
22
23 // define api
24 const (
25         defineApiPrefix = "vl_api_"
26         defineApiSuffix = "_t"
27 )
28
29 // BaseType represents base types in VPP binary API.
30 type BaseType int
31
32 const (
33         U8 BaseType = iota + 1
34         I8
35         U16
36         I16
37         U32
38         I32
39         U64
40         I64
41         F64
42         BOOL
43         STRING
44 )
45
46 var (
47         BaseTypes = map[BaseType]string{
48                 U8:     "u8",
49                 I8:     "i8",
50                 U16:    "u16",
51                 I16:    "i16",
52                 U32:    "u32",
53                 I32:    "i32",
54                 U64:    "u64",
55                 I64:    "i64",
56                 F64:    "f64",
57                 BOOL:   "bool",
58                 STRING: "string",
59         }
60         BaseTypeNames = map[string]BaseType{
61                 "u8":     U8,
62                 "i8":     I8,
63                 "u16":    U16,
64                 "i16":    I16,
65                 "u32":    U32,
66                 "i32":    I32,
67                 "u64":    U64,
68                 "i64":    I64,
69                 "f64":    F64,
70                 "bool":   BOOL,
71                 "string": STRING,
72         }
73 )
74
75 var BaseTypeSizes = map[BaseType]int{
76         U8:     1,
77         I8:     1,
78         U16:    2,
79         I16:    2,
80         U32:    4,
81         I32:    4,
82         U64:    8,
83         I64:    8,
84         F64:    8,
85         BOOL:   1,
86         STRING: 1,
87 }
88
89 type Kind int
90
91 const (
92         _ = iota
93         Uint8Kind
94         Int8Kind
95         Uint16Kind
96         Int16Kind
97         Uint32Kind
98         Int32Kind
99         Uint64Kind
100         Int64Kind
101         Float64Kind
102         BoolKind
103         StringKind
104         EnumKind
105         AliasKind
106         StructKind
107         UnionKind
108         MessageKind
109 )
110
111 // toApiType returns name that is used as type reference in VPP binary API
112 func toApiType(name string) string {
113         return defineApiPrefix + name + defineApiSuffix
114 }
115
116 func fromApiType(typ string) string {
117         name := typ
118         name = strings.TrimPrefix(name, defineApiPrefix)
119         name = strings.TrimSuffix(name, defineApiSuffix)
120         return name
121 }
122
123 func getSizeOfType(module *File, typ *Struct) (size int) {
124         for _, field := range typ.Fields {
125                 enum := getEnumByRef(module, field.Type)
126                 if enum != nil {
127                         size += getSizeOfBinapiTypeLength(enum.Type, field.Length)
128                         continue
129                 }
130                 size += getSizeOfBinapiTypeLength(field.Type, field.Length)
131         }
132         return size
133 }
134
135 func getEnumByRef(file *File, ref string) *Enum {
136         for _, typ := range file.Enums {
137                 if ref == toApiType(typ.Name) {
138                         return typ
139                 }
140         }
141         return nil
142 }
143
144 func getTypeByRef(file *File, ref string) *Struct {
145         for _, typ := range file.Structs {
146                 if ref == toApiType(typ.Name) {
147                         return typ
148                 }
149         }
150         return nil
151 }
152
153 func getAliasByRef(file *File, ref string) *Alias {
154         for _, alias := range file.Aliases {
155                 if ref == toApiType(alias.Name) {
156                         return alias
157                 }
158         }
159         return nil
160 }
161
162 func getUnionByRef(file *File, ref string) *Union {
163         for _, union := range file.Unions {
164                 if ref == toApiType(union.Name) {
165                         return union
166                 }
167         }
168         return nil
169 }
170
171 func getBinapiTypeSize(binapiType string) (size int) {
172         typName := BaseTypeNames[binapiType]
173         return BaseTypeSizes[typName]
174 }
175
176 // binapiTypes is a set of types used VPP binary API for translation to Go types
177 var binapiTypes = map[string]string{
178         "u8":  "uint8",
179         "i8":  "int8",
180         "u16": "uint16",
181         "i16": "int16",
182         "u32": "uint32",
183         "i32": "int32",
184         "u64": "uint64",
185         "i64": "int64",
186         "f64": "float64",
187 }
188 var BaseTypesGo = map[BaseType]string{
189         U8:     "uint8",
190         I8:     "int8",
191         U16:    "uint16",
192         I16:    "int16",
193         U32:    "uint32",
194         I32:    "int32",
195         U64:    "uint64",
196         I64:    "int64",
197         F64:    "float64",
198         BOOL:   "bool",
199         STRING: "string",
200 }
201
202 func getActualType(file *File, typ string) (actual string) {
203         for _, enum := range file.Enums {
204                 if enum.GoName == typ {
205                         return enum.Type
206                 }
207         }
208         for _, alias := range file.Aliases {
209                 if alias.GoName == typ {
210                         return alias.Type
211                 }
212         }
213         return typ
214 }
215
216 // convertToGoType translates the VPP binary API type into Go type
217 func convertToGoType(file *File, binapiType string) (typ string) {
218         if t, ok := binapiTypes[binapiType]; ok {
219                 // basic types
220                 typ = t
221         } else if r, ok := file.refmap[binapiType]; ok {
222                 // specific types (enums/types/unions)
223                 typ = camelCaseName(r)
224         } else {
225                 switch binapiType {
226                 case "bool", "string":
227                         typ = binapiType
228                 default:
229                         // fallback type
230                         logrus.Warnf("found unknown VPP binary API type %q, using byte", binapiType)
231                         typ = "byte"
232                 }
233         }
234         return typ
235 }
236
237 func getSizeOfBinapiTypeLength(typ string, length int) (size int) {
238         if n := getBinapiTypeSize(typ); n > 0 {
239                 if length > 0 {
240                         return n * length
241                 } else {
242                         return n
243                 }
244         }
245
246         return
247 }
248
249 func getUnionSize(file *File, union *Union) (maxSize int) {
250         for _, field := range union.Fields {
251                 typ := getTypeByRef(file, field.Type)
252                 if typ != nil {
253                         if size := getSizeOfType(file, typ); size > maxSize {
254                                 maxSize = size
255                         }
256                         continue
257                 }
258                 alias := getAliasByRef(file, field.Type)
259                 if alias != nil {
260                         if size := getSizeOfBinapiTypeLength(alias.Type, alias.Length); size > maxSize {
261                                 maxSize = size
262                         }
263                         continue
264                 } else {
265                         logf("no type or alias found for union %s field type %q", union.Name, field.Type)
266                         continue
267                 }
268         }
269         logf("getUnionSize: %s %+v max=%v", union.Name, union.Fields, maxSize)
270         return
271 }