Improve binapi generator
[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         "fmt"
19         "strings"
20
21         "github.com/sirupsen/logrus"
22 )
23
24 // define api
25 const (
26         defineApiPrefix = "vl_api_"
27         defineApiSuffix = "_t"
28 )
29
30 // toApiType returns name that is used as type reference in VPP binary API
31 func toApiType(name string) string {
32         return defineApiPrefix + name + defineApiSuffix
33 }
34
35 func fromApiType(typ string) string {
36         name := typ
37         name = strings.TrimPrefix(name, defineApiPrefix)
38         name = strings.TrimSuffix(name, defineApiSuffix)
39         return name
40 }
41
42 const (
43         U8     = "u8"
44         I8     = "i8"
45         U16    = "u16"
46         I16    = "i16"
47         U32    = "u32"
48         I32    = "i32"
49         U64    = "u64"
50         I64    = "i64"
51         F64    = "f64"
52         BOOL   = "bool"
53         STRING = "string"
54 )
55
56 var BaseTypeSizes = map[string]int{
57         U8:     1,
58         I8:     1,
59         U16:    2,
60         I16:    2,
61         U32:    4,
62         I32:    4,
63         U64:    8,
64         I64:    8,
65         F64:    8,
66         BOOL:   1,
67         STRING: 1,
68 }
69
70 var BaseTypesGo = map[string]string{
71         U8:     "uint8",
72         I8:     "int8",
73         U16:    "uint16",
74         I16:    "int16",
75         U32:    "uint32",
76         I32:    "int32",
77         U64:    "uint64",
78         I64:    "int64",
79         F64:    "float64",
80         BOOL:   "bool",
81         STRING: "string",
82 }
83
84 func fieldActualType(field *Field) (actual string) {
85         switch {
86         case field.TypeAlias != nil:
87                 actual = field.TypeAlias.Type
88         case field.TypeEnum != nil:
89                 actual = field.TypeEnum.Type
90         }
91         return field.Type
92 }
93
94 func fieldGoType(g *GenFile, field *Field) string {
95         switch {
96         case field.TypeAlias != nil:
97                 return g.GoIdent(field.TypeAlias.GoIdent)
98         case field.TypeEnum != nil:
99                 return g.GoIdent(field.TypeEnum.GoIdent)
100         case field.TypeStruct != nil:
101                 return g.GoIdent(field.TypeStruct.GoIdent)
102         case field.TypeUnion != nil:
103                 return g.GoIdent(field.TypeUnion.GoIdent)
104         }
105         t, ok := BaseTypesGo[field.Type]
106         if !ok {
107                 logrus.Panicf("type %s is not base type", field.Type)
108         }
109         return t
110 }
111
112 func getFieldType(g *GenFile, field *Field) string {
113         gotype := fieldGoType(g, field)
114         if field.Array {
115                 switch gotype {
116                 case "uint8":
117                         return "[]byte"
118                 case "string":
119                         return "string"
120                 }
121                 if _, ok := BaseTypesGo[field.Type]; !ok && field.Length > 0 {
122                         return fmt.Sprintf("[%d]%s", field.Length, gotype)
123                 }
124                 return "[]" + gotype
125         }
126         return gotype
127 }
128
129 func getSizeOfBinapiTypeLength(typ string, length int) (size int) {
130         if n := BaseTypeSizes[typ]; n > 0 {
131                 if length > 0 {
132                         return n * length
133                 } else {
134                         return n
135                 }
136         }
137         return
138 }
139
140 func getSizeOfType(typ *Struct) (size int) {
141         for _, field := range typ.Fields {
142                 if enum := field.TypeEnum; enum != nil {
143                         size += getSizeOfBinapiTypeLength(enum.Type, field.Length)
144                         continue
145                 }
146                 size += getSizeOfBinapiTypeLength(field.Type, field.Length)
147         }
148         return size
149 }
150
151 func getUnionSize(union *Union) (maxSize int) {
152         for _, field := range union.Fields {
153                 if typ := field.TypeStruct; typ != nil {
154                         if size := getSizeOfType(typ); size > maxSize {
155                                 maxSize = size
156                         }
157                         continue
158                 }
159                 if alias := field.TypeAlias; alias != nil {
160                         if size := getSizeOfBinapiTypeLength(alias.Type, alias.Length); size > maxSize {
161                                 maxSize = size
162                         }
163                         continue
164                 } else {
165                         logrus.Panicf("no type or alias found for union %s field type %q", union.Name, field.Type)
166                 }
167         }
168         //logf("getUnionSize: %s %+v max=%v", union.Name, union.Fields, maxSize)
169         return
170 }